很久之前写过两篇博客:
spring3.0使用annotation完全代替XML
spring3.0使用annotation完全代替XML(续)
用java config来代替XML,当时还遗留下一些问题:
- <tx:annotation-driven />声明性事务等配置无法用简单代码来实现
- web.xml无法去掉
随着servlet 3.0规范以及spring3.1.M2的发布,现在以上的问题也解决了。
先来说说web.xml,有两种方法来替代
(一)annotation
@WebServlet(urlPatterns="/hello")
public class HelloServlet extends HttpServlet {}
servlet3.0增加了@WebServlet, @WebFilter, @WebListener等注解,servlet容器会在classpath扫描并注册所有的标注好的servlet, filter和listener。这种方法只针对你能访问源代码的情况,对于像spring_mvc用到的DispatcherServlet,无法在源码上加annotation,可以用第二种方法来实现bootstrap
(二)ServletContainerInitializer
这是servlet3的一个接口,我们来看看spring-web提供的实现
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
public void onStartup(Set<Class<?>> webAppInitializerClasses,
ServletContext servletContext) throws ServletException {
//implemention omitted
}
}
@HandlesTypes也是servlet3中的注解,这里它处理的是WebApplicationInitializer,也就是说servlet容器会扫描classpath,将所有实现了WebApplicationInitializer接口的类传给onStartup方法中的webAppInitializerClasses,并调用onStartup方法来注册servlet。具体的注册代码可以这样写:
public class WebInit implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext sc) throws ServletException {
sc.addFilter("hibernateFilter", OpenSessionInViewFilter.class).addMappingForUrlPatterns(null, false, "/*");
// Create the 'root' Spring application context
AnnotationConfigWebApplicationContext root = new AnnotationConfigWebApplicationContext();
root.scan("septem.config.app");
// Manages the lifecycle of the root application context
sc.addListener(new ContextLoaderListener(root));
AnnotationConfigWebApplicationContext webContext = new AnnotationConfigWebApplicationContext();
webContext.setConfigLocation("septem.config.web");
ServletRegistration.Dynamic appServlet = sc.addServlet("appServlet", new DispatcherServlet(webContext));
appServlet.setLoadOnStartup(1);
appServlet.addMapping("/");
}
}
以上的代码分别调用了sc.addFilter, sc.addListener, sc.addServlet来注册filter, listener和servlet.
用以上的方法就能将WEB-INF/web.xml删除了.spring3.1.M2开始增加了一系列annotation来实现声明性事务及简化spring_mvc配置。WebInit中注册的DispatcherServlet所对应的配置在septem.config.web包里面:
@Configuration
@ComponentScan(basePackages="septem.controller")
@EnableWebMvc
public class WebConfig {
}
一行@EnableWebMvc就导入了spring_mvc需要的诸多bean,再配合@ComponentScan扫描septem.controller包里面所有的@Controller,基本的mvc配置就完成了。
声明性事务也是类似,通过spring root application context扫描包septem.config.app:
@Configuration
@EnableTransactionManagement
public class DataConfig {
@Bean public AnnotationSessionFactoryBean sessionFactory() {
AnnotationSessionFactoryBean sessionFactoryBean = new AnnotationSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource());
sessionFactoryBean.setNamingStrategy(new ImprovedNamingStrategy());
sessionFactoryBean.setPackagesToScan("septem.model");
sessionFactoryBean.setHibernateProperties(hProps());
return sessionFactoryBean;
}
private DataSource dataSource() {
BasicDataSource source = new BasicDataSource();
source.setDriverClassName("org.hsqldb.jdbcDriver");
source.setUrl("jdbc:hsqldb:mem:s3demo_db");
source.setUsername("sa");
source.setPassword("");
return source;
}
@Bean public HibernateTransactionManager transactionManager() {
HibernateTransactionManager hibernateTransactionManager = new HibernateTransactionManager();
hibernateTransactionManager.setSessionFactory(sessionFactory().getObject());
return hibernateTransactionManager;
}
private Properties hProps() {
Properties p = new Properties();
p.put("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
p.put("hibernate.cache.use_second_level_cache", "true");
p.put("hibernate.cache.use_query_cache", "true");
p.put("hibernate.cache.provider_class",
"org.hibernate.cache.EhCacheProvider");
p.put("hibernate.cache.provider_configuration_file_resource_path",
"ehcache.xml");
p.put("hibernate.show_sql", "true");
p.put("hibernate.hbm2ddl.auto", "update");
p.put("hibernate.generate_statistics", "true");
p.put("hibernate.cache.use_structured_entries", "true");
return p;
}
}
DataConfig定义了所有与数据库和hibernate相关的bean,通过@EnableTransactionManagement实现声明性事务。
service是如何注册的呢?
@Configuration
@ComponentScan(basePackages="septem.service")
public class AppConfig {
}
通过@ComponentScan扫描包septem.service里定义的所有service,一个简单service实现如下:
@Service @Transactional
public class GreetingService {
@Autowired
private SessionFactory sessionFactory;
@Transactional(readOnly=true)
public String greeting() {
return "spring without xml works!";
}
@Transactional(readOnly=true)
public Book getBook(Long id) {
return (Book) getSession().get(Book.class, id);
}
@Transactional(readOnly=true)
public Author getAuthor(Long id){
return (Author) getSession().get(Author.class, id);
}
public Book newBook() {
Book book = new Book();
book.setTitle("java");
getSession().save(book);
return book;
}
public Author newAuthor() {
Book book = newBook();
Author author = new Author();
author.setName("septem");
author.addBook(book);
getSession().save(author);
return author;
}
private Session getSession() {
return sessionFactory.getCurrentSession();
}
}
这样整个项目中就没有XML文件了。在写这些代码的过程中也碰到不少问题,纪录如下:
(一)项目没有web.xml,maven的war插件要加上failOnMissingWebXml=false
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.1.1</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
(二) tomcat-embeded7.0.16还有点小BUG,不能把DispatcherServlet映射为"/",所以代码里把它映射为"/s3/"
appServlet.addMapping("/s3/");
(三) 如果要使用spring提供的OpenSessionInViewFilter,在定义Hibernate SessionFactory的时候,不能直接new SessionFactory出来,即以下代码是不能实现声明性事务的:
@Bean public SessionFactory sessionFactory() {
org.hibernate.cfg.Configuration config = new org.hibernate.cfg.Configuration();
config.setProperties(hProps());
config.addAnnotatedClass(Book.class);
return config.buildSessionFactory();
}
必须使用spring提供的FactoryBean:
@Bean public AnnotationSessionFactoryBean sessionFactory() {
AnnotationSessionFactoryBean sessionFactoryBean = new AnnotationSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource());
sessionFactoryBean.setNamingStrategy(new ImprovedNamingStrategy());
sessionFactoryBean.setPackagesToScan("septem.model");
sessionFactoryBean.setHibernateProperties(hProps());
return sessionFactoryBean;
}
后记:在spring3.1以servlet3中annotation已经是一等公民了,可以实现任何原先只能在xml文件中配置的功能,并具有简洁,静态检查及重构友好等优点。总体上来讲spring提供的“魔法”还是太多了,尤其是跟hibernate,事务,open session in view等机制结合在一起的时候,简洁代码的背后隐藏着太多的依赖关系,如果程序出了问题,排除这些魔法,一层一层地还原程序的本来面目,将是一件很需要耐心的事情
分享到:
相关推荐
杭州电子科技大学,期末考试资料,计算机专业期末考试试卷,试卷及答案,数据结构。
重庆大学期末考试试卷,重大期末考试试题,试题及答案
年会班会资料,节目策划,游戏策划,策划案,策划方案,活动方案,筹办,公司年会,开场白,主持人,策划主题,主持词,小游戏。
基于Django框架的博客系统.zip
【基于Springboot+Vue的Java毕业设计】校园服务平台项目实战(源码+录像演示+说明).rar 【项目技术】 开发语言:Java 框架:Spingboot+vue 架构:B/S 数据库:mysql 【演示视频-编号:321】 https://pan.quark.cn/s/8dea014f4d36 【实现功能】 系统可以提供信息显示和相应服务,其管理员增删改查接单员和接单员资料,审核接单员预订订单,查看订单评价和评分,通过留言功能回复用户提问。
Excel数据看板,Excel办公模板,Excel模板下载,Excel数据统计,数据展示
PTS技术内含数据集.zip
工作总结,新年计划,岗位总结,工作汇报,个人总结,述职报告,范文下载,新年总结,新建计划。
重庆大学期末考试试卷,重大期末考试试题,试题及答案
1.版本:matlab2014/2019a/2021a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。
空间复用的MIMO系统的信号检测OSIC检测方法内含数据集.zip
该毕业设计使用了比较受前端欢迎的vue框架技术,是一个纯前端的项目,没有使用后端java程序和数据库。如果你刚学完vue相关的知识,可以通过该项目源码对vue加以巩固。现在流行无纸化办公,该项目主要解决了问卷调查相关的问题。 主要功能包括:问卷发布,数据查看。其中数据查看以图表的方式展现,便于使用者查看调查结果。
工作总结,新年计划,岗位总结,工作汇报,个人总结,述职报告,范文下载,新年总结,新建计划。
空间复用的MIMO系统的信号检测MIMO系统的QRM-MLD检测器的软判决内含数据集.zip
重庆大学期末考试试卷,重大期末考试试题,试题及答案
数字政府建设实施方案建议.rar文件是一个综合性的数字化转型解决方案精品资料,旨在为政府部门提供一个详细的蓝图和指导方针,以推进公共服务的数字化进程。这个方案强调了数字化在提高政府效率、透明度以及民众参与度方面的重要性,并提出了具体的实施步骤,包括基础设施升级、数据管理、在线服务平台建设、网络安全保障等关键要素。通过整合现代信息技术,如云计算、大数据分析、人工智能和移动互联,本方案不仅致力于优化内部工作流程,还着眼于提升公众与政府的互动体验。它涵盖了从政策制定到技术执行的各个层面,确保了数字政府建设的全面性和系统性,同时考虑到了可持续性和未来的技术演进。这份资料是任何希望实现现代化治理和服务的政府机构不可或缺的参考资源,有助于构建一个更加智能化、高效和公民友好的数字政府环境。重新回答||
一款成人用品线上零售商城JAVA源码,支持h5+安卓+ios+微信小程序, 在线销售男士、女士避孕用品、情趣内衣和玩具类等两性健康产品, 客户有自己的货源为了扩大渠道,方便客户购买,开发本款小程序。 产品分类清晰明了,首页需突出主打产品,页面展示产品清楚明了; 购买流程不要繁琐;后期方便用户查看订单情况。有促销信息及优惠券可以提高刺激消费者
工作总结,新年计划,岗位总结,工作汇报,个人总结,述职报告,范文下载,新年总结,新建计划。
1.版本:matlab2014/2019a/2021a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。