spring3.0使用annotation完全代替XML(三)
很久之前写过两篇博客:
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等机制结合在一起的时候,简洁代码的背后隐藏着太多的依赖关系,如果程序出了问题,排除这些魔法,一层一层地还原程序的本来面目,将是一件很需要耐心的事情
spring3.0使用annotation完全代替XML(三)的更多相关文章
- spring3.0使用annotation完全代替XML
@Service与@Component有什么不同?那天被问到这个问题,一时之间却想不起来,就利用这篇文章来纪录spring3.0中常用的annotation. 从spring2.5开始,annotat ...
- spring3.0使用annotation完全代替XML(续)
从回帖的反应来看,大多数人还是不赞成完全代替XML的,这点倒是在意料之中.我个人还是倾向于用代码来取代XML的Bean定义,当然这更多的是关乎个人偏好,不代表与我观点不同的人就是错的. 先来说说代码相 ...
- 缓存初解(三)---Spring3.0基于注解的缓存配置+Ehcache和OScache
本文将构建一个普通工程来说明spring注解缓存的使用方式,关于如何在web应用中使用注解缓存,请参见: Spring基于注解的缓存配置--web应用实例 一.简介 在spring的modules包中 ...
- 开发基础框架: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 二 ...
- MyEclipse-10.0下Struts2.1+Spring3.0+Hibernate3.3整合过程
新建web project: 命名为SSH,做如下设置: 新建后的工程目录如下: 然后开始添加SSH框架,这里我按照struts-spring-hibernate顺序进行添加. 首先添加struts2 ...
- Spring3.0 与 MyBatis框架 整合小实例
本文将在Eclipse开发环境下,采用Spring MVC + Spring + MyBatis + Maven + Log4J 框架搭建一个Java web 项目. 1. 环境准备: 1.1 创建数 ...
- spring3.0+Atomikos 构建jta的分布式事务 -- NO
摘自: http://gongjiayun.iteye.com/blog/1570111 spring3.0+Atomikos 构建jta的分布式事务 spring3.0已经不再支持jtom了,不过我 ...
- 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 ...
- spring3.0+Atomikos 构建jta的分布式事务
摘自: http://gongjiayun.iteye.com/blog/1570111 spring3.0+Atomikos 构建jta的分布式事务 spring3.0已经不再支持jtom了,不过我 ...
随机推荐
- linux Mint mysql 安装
sudo apt-get install mysql-server 之后按照提示,输入root的密码,再次输入密码,就好了. mysql -uroot -p**** //连接数据库 show data ...
- html5--canvas绘制简单的时钟
http://5227788.cn/static/time.html <!DOCTYPE html> <html lang="en"> <head&g ...
- nginx配置反向代理解决前后端分离跨域问题
摘自<AngularJS深度剖析与最佳实践>P132 nginx配置文件如下: server { listen ; server_name your.domain.name; locati ...
- Mosquitto搭建Android推送服务(二)Mosquitto简介及搭建
文章钢要: 1.了解Mosquitto服务器 2.在Liunx中搭建Mosquitto服务器 3.设置Mosquitto集群 一.Mosquitto简介 一款实现了消息推送协议 MQTT v3.1 的 ...
- C++根据图片url下载图片
需要使用到URLDownloadToFile()函数,该函数在头文件<urlmon.h>中声明. URLDownloadToFile()函数的定义如下: HRESULT URLDownlo ...
- Vue.js与MVVM
MVVM 是Model-View-ViewModel 的缩写,它是一种基于前端开发的架构模式,其核心是提供对View 和 ViewModel 的双向数据绑定,这使得ViewModel 的状态改变可以自 ...
- mysql深入浅出的笔记(存储过程二)
1.条件的定义和处理可以用来定义在处理过程中遇到问题时相应的处理步揍: DECLARE condition_name CONDITION FOR condition_value condition_v ...
- 【转】arm 开发工具比较(ADS vs RealviewMDK vs RVDS)
ADS REALVIEW MDK RVDS 公司 ARM Keil(后被ARM收购) ARM 版本 最新1.2 ,被RVDS取代 最新4.0 是否免费 破解情况 有 有 工程管理 CodeWarr ...
- B/S系统常见缺陷整理和解决方案
最近部门整理了今年所有项目测试团队提出的BUG,筛选了几十个作为常规通用的缺陷,我根据这些缺陷内容,去掉和业务相关的知识,整理出了一份缺陷描述和解决方案. 其实WEB系统中常规的缺陷分类后也就那么多, ...
- 获取系统中所有进程&线程信息
读书笔记--[计算机病毒解密与对抗] 目录: 遍历进程&线程程序 终止进程 获取进程信息 获取进程内模块信息 获取进程命令行参数 代码运行环境:Win7 x64 VS2012 Update3 ...