很久之前写过两篇博客:
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

  1. @WebServlet(urlPatterns="/hello")
  2. public class HelloServlet extends HttpServlet {}

servlet3.0增加了@WebServlet, @WebFilter,
@WebListener等注解,servlet容器会在classpath扫描并注册所有的标注好的servlet,
filter和listener。这种方法只针对你能访问源代码的情况,对于像spring_mvc用到的DispatcherServlet,无法在源码上加annotation,可以用第二种方法来实现bootstrap

(二)ServletContainerInitializer

这是servlet3的一个接口,我们来看看spring-web提供的实现

  1. @HandlesTypes(WebApplicationInitializer.class)
  2. public class SpringServletContainerInitializer implements ServletContainerInitializer {
  3. public void onStartup(Set<Class<?>> webAppInitializerClasses,
  4. ServletContext servletContext) throws ServletException {
  5. //implemention omitted
  6. }
  7. }

@HandlesTypes也是servlet3中的注解,这里它处理的是WebApplicationInitializer,也就是说servlet容器会扫描classpath,将所有实现了WebApplicationInitializer接口的类传给onStartup方法中的webAppInitializerClasses,并调用onStartup方法来注册servlet。具体的注册代码可以这样写:

  1. public class WebInit implements WebApplicationInitializer {
  2. @Override
  3. public void onStartup(ServletContext sc) throws ServletException {
  4. sc.addFilter("hibernateFilter", OpenSessionInViewFilter.class).addMappingForUrlPatterns(null, false, "/*");
  5. // Create the 'root' Spring application context
  6. AnnotationConfigWebApplicationContext root = new AnnotationConfigWebApplicationContext();
  7. root.scan("septem.config.app");
  8. // Manages the lifecycle of the root application context
  9. sc.addListener(new ContextLoaderListener(root));
  10. AnnotationConfigWebApplicationContext webContext = new AnnotationConfigWebApplicationContext();
  11. webContext.setConfigLocation("septem.config.web");
  12. ServletRegistration.Dynamic appServlet = sc.addServlet("appServlet", new DispatcherServlet(webContext));
  13. appServlet.setLoadOnStartup(1);
  14. appServlet.addMapping("/");
  15. }
  16. }

以上的代码分别调用了sc.addFilter, sc.addListener, sc.addServlet来注册filter, listener和servlet.

用以上的方法就能将WEB-INF/web.xml删除了.spring3.1.M2开始增加了一系列annotation来实现声明性事务及简化spring_mvc配置。WebInit中注册的DispatcherServlet所对应的配置在septem.config.web包里面:

  1. @Configuration
  2. @ComponentScan(basePackages="septem.controller")
  3. @EnableWebMvc
  4. public class WebConfig {
  5. }

一行@EnableWebMvc就导入了spring_mvc需要的诸多bean,再配合@ComponentScan扫描septem.controller包里面所有的@Controller,基本的mvc配置就完成了。

声明性事务也是类似,通过spring root application context扫描包septem.config.app:

  1. @Configuration
  2. @EnableTransactionManagement
  3. public class DataConfig {
  4. @Bean public AnnotationSessionFactoryBean sessionFactory() {
  5. AnnotationSessionFactoryBean sessionFactoryBean = new AnnotationSessionFactoryBean();
  6. sessionFactoryBean.setDataSource(dataSource());
  7. sessionFactoryBean.setNamingStrategy(new ImprovedNamingStrategy());
  8. sessionFactoryBean.setPackagesToScan("septem.model");
  9. sessionFactoryBean.setHibernateProperties(hProps());
  10. return sessionFactoryBean;
  11. }
  12. private DataSource dataSource() {
  13. BasicDataSource source = new BasicDataSource();
  14. source.setDriverClassName("org.hsqldb.jdbcDriver");
  15. source.setUrl("jdbc:hsqldb:mem:s3demo_db");
  16. source.setUsername("sa");
  17. source.setPassword("");
  18. return source;
  19. }
  20. @Bean public HibernateTransactionManager transactionManager() {
  21. HibernateTransactionManager hibernateTransactionManager = new HibernateTransactionManager();
  22. hibernateTransactionManager.setSessionFactory(sessionFactory().getObject());
  23. return hibernateTransactionManager;
  24. }
  25. private Properties hProps() {
  26. Properties p = new Properties();
  27. p.put("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
  28. p.put("hibernate.cache.use_second_level_cache", "true");
  29. p.put("hibernate.cache.use_query_cache", "true");
  30. p.put("hibernate.cache.provider_class",
  31. "org.hibernate.cache.EhCacheProvider");
  32. p.put("hibernate.cache.provider_configuration_file_resource_path",
  33. "ehcache.xml");
  34. p.put("hibernate.show_sql", "true");
  35. p.put("hibernate.hbm2ddl.auto", "update");
  36. p.put("hibernate.generate_statistics", "true");
  37. p.put("hibernate.cache.use_structured_entries", "true");
  38. return p;
  39. }
  40. }

DataConfig定义了所有与数据库和hibernate相关的bean,通过@EnableTransactionManagement实现声明性事务。

service是如何注册的呢?

  1. @Configuration
  2. @ComponentScan(basePackages="septem.service")
  3. public class AppConfig {
  4. }

通过@ComponentScan扫描包septem.service里定义的所有service,一个简单service实现如下:

  1. @Service @Transactional
  2. public class GreetingService {
  3. @Autowired
  4. private SessionFactory sessionFactory;
  5. @Transactional(readOnly=true)
  6. public String greeting() {
  7. return "spring without xml works!";
  8. }
  9. @Transactional(readOnly=true)
  10. public Book getBook(Long id) {
  11. return (Book) getSession().get(Book.class, id);
  12. }
  13. @Transactional(readOnly=true)
  14. public Author getAuthor(Long id){
  15. return (Author) getSession().get(Author.class, id);
  16. }
  17. public Book newBook() {
  18. Book book = new Book();
  19. book.setTitle("java");
  20. getSession().save(book);
  21. return book;
  22. }
  23. public Author newAuthor() {
  24. Book book = newBook();
  25. Author author = new Author();
  26. author.setName("septem");
  27. author.addBook(book);
  28. getSession().save(author);
  29. return author;
  30. }
  31. private Session getSession() {
  32. return sessionFactory.getCurrentSession();
  33. }
  34. }

这样整个项目中就没有XML文件了。在写这些代码的过程中也碰到不少问题,纪录如下:

(一)项目没有web.xml,maven的war插件要加上failOnMissingWebXml=false

  1. <plugin>
  2. <groupId>org.apache.maven.plugins</groupId>
  3. <artifactId>maven-war-plugin</artifactId>
  4. <version>2.1.1</version>
  5. <configuration>
  6. <failOnMissingWebXml>false</failOnMissingWebXml>
  7. </configuration>
  8. </plugin>

(二) tomcat-embeded7.0.16还有点小BUG,不能把DispatcherServlet映射为"/",所以代码里把它映射为"/s3/"

  1. appServlet.addMapping("/s3/");

(三) 如果要使用spring提供的OpenSessionInViewFilter,在定义Hibernate SessionFactory的时候,不能直接new SessionFactory出来,即以下代码是不能实现声明性事务的:

  1. @Bean public SessionFactory sessionFactory() {
  2. org.hibernate.cfg.Configuration config = new org.hibernate.cfg.Configuration();
  3. config.setProperties(hProps());
  4. config.addAnnotatedClass(Book.class);
  5. return config.buildSessionFactory();
  6. }

必须使用spring提供的FactoryBean:

  1. @Bean public AnnotationSessionFactoryBean sessionFactory() {
  2. AnnotationSessionFactoryBean sessionFactoryBean = new AnnotationSessionFactoryBean();
  3. sessionFactoryBean.setDataSource(dataSource());
  4. sessionFactoryBean.setNamingStrategy(new ImprovedNamingStrategy());
  5. sessionFactoryBean.setPackagesToScan("septem.model");
  6. sessionFactoryBean.setHibernateProperties(hProps());
  7. return sessionFactoryBean;
  8. }

后记:在spring3.1以servlet3中annotation已经是一等公民了,可以实现任何原先只能在xml文件中配置的功能,并具有简洁,静态检查及重构友好等优点。总体上来讲spring提供的“魔法”还是太多了,尤其是跟hibernate,事务,open
session in
view等机制结合在一起的时候,简洁代码的背后隐藏着太多的依赖关系,如果程序出了问题,排除这些魔法,一层一层地还原程序的本来面目,将是一件很需要耐心的事情

spring3.0使用annotation完全代替XML(三)的更多相关文章

  1. spring3.0使用annotation完全代替XML

    @Service与@Component有什么不同?那天被问到这个问题,一时之间却想不起来,就利用这篇文章来纪录spring3.0中常用的annotation. 从spring2.5开始,annotat ...

  2. spring3.0使用annotation完全代替XML(续)

    从回帖的反应来看,大多数人还是不赞成完全代替XML的,这点倒是在意料之中.我个人还是倾向于用代码来取代XML的Bean定义,当然这更多的是关乎个人偏好,不代表与我观点不同的人就是错的. 先来说说代码相 ...

  3. 缓存初解(三)---Spring3.0基于注解的缓存配置+Ehcache和OScache

    本文将构建一个普通工程来说明spring注解缓存的使用方式,关于如何在web应用中使用注解缓存,请参见: Spring基于注解的缓存配置--web应用实例 一.简介 在spring的modules包中 ...

  4. 开发基础框架:mybatis-3.2.8 +hibernate4.0+spring3.0+struts2.3

    一:项目下载地址(点击 Source code(zip)) https://github.com/fzxblgong/frame_2014-12-15/releases 版本:v1.2大小:20M 二 ...

  5. MyEclipse-10.0下Struts2.1+Spring3.0+Hibernate3.3整合过程

    新建web project: 命名为SSH,做如下设置: 新建后的工程目录如下: 然后开始添加SSH框架,这里我按照struts-spring-hibernate顺序进行添加. 首先添加struts2 ...

  6. Spring3.0 与 MyBatis框架 整合小实例

    本文将在Eclipse开发环境下,采用Spring MVC + Spring + MyBatis + Maven + Log4J 框架搭建一个Java web 项目. 1. 环境准备: 1.1 创建数 ...

  7. spring3.0+Atomikos 构建jta的分布式事务 -- NO

    摘自: http://gongjiayun.iteye.com/blog/1570111 spring3.0+Atomikos 构建jta的分布式事务 spring3.0已经不再支持jtom了,不过我 ...

  8. Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1.8整合例子(附完整的请假流程例子,jbpm基础,常见问题解决)

    Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1.8 整合例子(附完整的请假流程例子). 1.jbpm4.4 测试环境搭建 2.Jbpm4.4+hibernat ...

  9. spring3.0+Atomikos 构建jta的分布式事务

    摘自: http://gongjiayun.iteye.com/blog/1570111 spring3.0+Atomikos 构建jta的分布式事务 spring3.0已经不再支持jtom了,不过我 ...

随机推荐

  1. grep

    http://www.cnblogs.com/ggjucheng/archive/2013/01/13/2856896.html

  2. EndNote(二)之英文引文导入方式

    在上一篇EndNote教程(一)--基本介绍中介绍了基本使用,今天将来介绍如何将常用文献引文导入EndNote中. EndNote在文献管理方面有着很多优点,可以节约很多精力.但是,不同文献查询网站可 ...

  3. rsa密钥文件转化为tortoise认可的pak密钥文件

    原贴地址: http://www.vectorns.com/blog/technical-articles/1-tortoisesvn-over-ssh-on-windows-via-putty Ne ...

  4. Mac 使用Sublime Text 3 搭建C开发环境

    Sublime Text 3  (安装包,注册码 ,汉化包) 1)工具-编译系统-新建编译器 { "cmd" : ["gcc -o ${file_base_name} $ ...

  5. 排序之----插入排序(C#实现)

    算法步骤:(从小到大) 1:将第一个元素与第二个元素比较大小,如果第一个元素小于等于第二个元素,不做处理,继续比较第二个元素和第三个元素. 如果第三个元素小于第二个元素,保存要移动的元素(第三个元素) ...

  6. 「LeetCode」全部题解

    花了将近 20 多天的业余时间,把 LeetCode 上面的题目做完了,毕竟还是针对面试的题目,代码量都不是特别大,难度和 OJ 上面也差了一大截. 关于二叉树和链表方面考察变成基本功的题目特别多,其 ...

  7. vba 相关

    返回当前默认文件路径: Application.DefaultFilePath 返回应用程序完整路径 Application.Path 返回当前工作薄的路径 ThisWorkbook.Path App ...

  8. RakNet发送与接收数据

    http://www.jenkinssoftware.com/raknet/manual/creatingpackets.html Creating Packets with Bitstreams W ...

  9. React学习笔记-5-初始化阶段介绍

    初始化阶段可以使用的函数:getDefaultProps:只调用一次,实例之间共享引用.只有在组件的第一个实例被初始化的时候,才会调用他,然后react会把这个函数的返回结果保存起来,从第二个实例开始 ...

  10. 关于sql的执行顺序

    标准sql的解析顺序为 1)FROM子句,组装来自不同数据源的数据 2)WHERE子句 基于制定的条件对记录进行筛选 3)GROUP BY 子句将数据划分为多个分组 4)使用聚合函数进行计算 5) 使 ...