注释语法越来越多的被业界所使用,并且注释配置相对于 XML 配置具有很多的优势:它可以充分利用 Java 的反射机制获取类结构信息,这些信息可以有效减少配置的工作。注释和 Java 代码位于一个文件中,而 XML 配置采用独立的配置文件,大多数配置信息在程序开发完成后都不会调整,如果配置信息和 Java 代码放在一起,有助于增强程序的内聚性。而采用独立的 XML 配置文件,程序员在编写一个功能时,往往需要在程序文件和配置文件中不停切换,这种思维上的不连贯会降低开发效率。因此在很多情况下,注释配置比 XML 配置更受欢迎,注释配置有进一步流行的趋势。Spring 2.5 的一大增强就是引入了很多注释类,现在您已经可以使用注释配置完成大部分 XML 配置的功能。
首先,我们已经通过 传统的spring +hibernate方式构架成功了一个应用的后台体系。
这个体系里面 有这样几个重要的配置文件。
- hibernate.cfg.xml 。
里面通过 配置 mapping来指向每张数据表单生成配置文件.xxxx.hbm.xml文件 - applicaitonContex.xml。
里面通过定义一个一个bean 来配置 各个需要用到的 DAO 和 Service。 - <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
- <beans >
- <bean id="sessionFactory"
- class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
- <property name="configLocation"
- value="classpath:hibernate.cfg.xml">
- </property>
- </bean>
-
- <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
- <property name="sessionFactory">
- <ref local="sessionFactory"/>
- </property>
- </bean>
-
- <bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
- <!-- 事务拦截器bean需要依赖注入一个事务管理器 -->
- <property name="transactionManager">
- <ref local="transactionManager"/>
- </property>
- <property name="transactionAttributes">
- <!-- 下面定义事务传播属性-->
- <props>
- <prop key="insert*">PROPAGATION_REQUIRED</prop>
- <prop key="update*">PROPAGATION_REQUIRED</prop>
- <prop key="save*">PROPAGATION_REQUIRED</prop>
- <prop key="add*">PROPAGATION_REQUIRED</prop>
- <prop key="update*">PROPAGATION_REQUIRED</prop>
- <prop key="remove*">PROPAGATION_REQUIRED</prop>
- <prop key="delete*">PROPAGATION_REQUIRED</prop>
- <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
- <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
- <prop key="load*">PROPAGATION_REQUIRED,readOnly</prop>
- <prop key="change*">PROPAGATION_REQUIRED</prop>
- <prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
- </props>
- </property>
- </bean>
-
-
- <!-- 定义自动代理BeanNameAutoProxyCreator -->
- <bean id="beanNameAutoProxyCreator"
- class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
- <!-- 指定对满足哪些bean name的bean自动生成业务代理 -->
- <property name="beanNames">
- <list>
- <value>*Service</value>
- </list>
- </property>
- <!-- 下面定义BeanNameAutoProxyCreator所需的事务拦截器-->
- <property name="interceptorNames">
- <list>
- <!-- 此处可增加其他新的Interceptor -->
- <value>transactionInterceptor</value>
- </list>
- </property>
- </bean>
- <bean id="McCityInfoDAO"
- class="com.firemax.manatee.hibernate.McCityInfoDAO">
- <property name="sessionFactory">
- <ref bean="sessionFactory" />
- </property>
- </bean>
- <bean id="McMaterialInfoDAO"
- class="com.firemax.manatee.hibernate.McMaterialInfoDAO">
- <property name="sessionFactory">
- <ref bean="sessionFactory" />
- </property>
- </bean>
- </beans>
-
-
hibernate.cfg.xml要配置这么多 xxxxx.hbm.xml文件。每次数据结构发生变化的时候。要重新去改写pojo和dao以及这些xxxxx.hbm.xml
那么好。我们现在就用 注解的力量 去把这部分工作简化。
- hibernate3.2 以上版本的jar
- jdk 5 以上的环境
- spring2
- 然后我们修改pojo的java类。加上注解。使起通过注解来取代原先要xxxx.hbm.xml里面配置的指向的数据库表单结构的信息。
- package com.alcor.web.hibernate;
-
- import java.util.HashSet;
- import java.util.Set;
- import javax.persistence.CascadeType;
- import javax.persistence.Column;
- import javax.persistence.Entity;
- import javax.persistence.FetchType;
- import javax.persistence.Id;
- import javax.persistence.JoinColumn;
- import javax.persistence.ManyToOne;
- import javax.persistence.OneToMany;
- import javax.persistence.Table;
-
- /**
- * AlcorTCitys entity. @author MyEclipse Persistence Tools
- */
- @Entity
- @Table(name = "alcor_t_citys", catalog = "alcorweb")
- public class AlcorTCitys implements java.io.Serializable {
-
- // Fields
-
- private String cityCode;
- private AlcorTProvinces alcorTProvinces;
- private String cityName;
- private Set<AlcotTDistrict> alcotTDistricts = new HashSet<AlcotTDistrict>(0);
-
- // Constructors
-
- /** default constructor */
- public AlcorTCitys() {
- }
-
- /** minimal constructor */
- public AlcorTCitys(String cityCode, AlcorTProvinces alcorTProvinces,
- String cityName) {
- this.cityCode = cityCode;
- this.alcorTProvinces = alcorTProvinces;
- this.cityName = cityName;
- }
-
- /** full constructor */
- public AlcorTCitys(String cityCode, AlcorTProvinces alcorTProvinces,
- String cityName, Set<AlcotTDistrict> alcotTDistricts) {
- this.cityCode = cityCode;
- this.alcorTProvinces = alcorTProvinces;
- this.cityName = cityName;
- this.alcotTDistricts = alcotTDistricts;
- }
-
- // Property accessors
- @Id
- @Column(name = "city_code", unique = true, nullable = false, length = 32)
- public String getCityCode() {
- return this.cityCode;
- }
-
- public void setCityCode(String cityCode) {
- this.cityCode = cityCode;
- }
-
- @ManyToOne(fetch = FetchType.EAGER)
- @JoinColumn(name = "province_code", nullable = false)
- public AlcorTProvinces getAlcorTProvinces() {
- return this.alcorTProvinces;
- }
-
- public void setAlcorTProvinces(AlcorTProvinces alcorTProvinces) {
- this.alcorTProvinces = alcorTProvinces;
- }
-
- @Column(name = "city_name", nullable = false, length = 64)
- public String getCityName() {
- return this.cityName;
- }
-
- public void setCityName(String cityName) {
- this.cityName = cityName;
- }
-
- @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "alcorTCitys")
- public Set<AlcotTDistrict> getAlcotTDistricts() {
- return this.alcotTDistricts;
- }
-
- public void setAlcotTDistricts(Set<AlcotTDistrict> alcotTDistricts) {
- this.alcotTDistricts = alcotTDistricts;
- }
-
- }
- 修改hibernate.cfg.xml中的定义方式,把原来的maping source=“xxxxx.hbm.xml”修改成
<mapping class="com.alcor.web.hibernate.AlcorTCitys" />
这样我们就可以把原来的 xxxxx.hbm.xml全部删除了。
经过这个步骤。如果你原有的servcice层的功能能够正常使用。恭喜你。迈出了成功的第一步
===============================================================================================
通过上面一步骤。我们简化了hibernate中扰人的 xxxxx.hbm.xml文件。那么是否可以再进行简化呢?
那么,我们在这一步骤的目的,就是把整个 hibernate.cfg.xml都给简化了。
依然是利用注解注入的方式。通过jpa 我们可以把 hibernate.cfg.xml中那些 mapping classes再次简化与无形。
- 在applicationContext.xml中进行如下配置
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"
- xmlns:tx="http://www.springframework.org/schema/tx">
-
-
- <bean id="entityManagerFactory"
- class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
- <property name="persistenceUnitName" value="testerPU" />
- </bean>
- <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
- <property name="entityManagerFactory" ref="entityManagerFactory" />
- </bean>
-
- <tx:annotation-driven transaction-manager="transactionManager" />
-
- <bean id="transactionInterceptor"
- class="org.springframework.transaction.interceptor.TransactionInterceptor">
- <!-- 事务拦截器bean需要依赖注入一个事务管理器 -->
- <property name="transactionManager">
- <ref local="transactionManager" />
- </property>
- <property name="transactionAttributes">
- <!-- 下面定义事务(指service里面的方法)传播属性 -->
- <props>
- <prop key="insert*">PROPAGATION_REQUIRED</prop>
- <prop key="update*">PROPAGATION_REQUIRED</prop>
- <prop key="save*">PROPAGATION_REQUIRED</prop>
- <prop key="add*">PROPAGATION_REQUIRED</prop>
- <prop key="update*">PROPAGATION_REQUIRED</prop>
- <prop key="remove*">PROPAGATION_REQUIRED</prop>
- <prop key="delete*">PROPAGATION_REQUIRED</prop>
- <prop key="get*">PROPAGATION_REQUIRED,readOnly
- </prop>
- <prop key="find*">PROPAGATION_REQUIRED,readOnly
- </prop>
- <prop key="load*">PROPAGATION_REQUIRED,readOnly
- </prop>
- <prop key="change*">PROPAGATION_REQUIRED</prop>
- <prop key="count*">PROPAGATION_REQUIRED</prop>
- <prop key="*">PROPAGATION_REQUIRED</prop>
- </props>
- </property>
- </bean>
- <!-- 定义自动代理BeanNameAutoProxyCreator -->
- <bean id="beanNameAutoProxyCreator"
- class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
- <!-- 指定对满足哪些bean name的bean自动生成业务代理 -->
- <property name="beanNames">
- <list>
- <value>*Service</value>
- </list>
- </property>
- <!-- 下面定义BeanNameAutoProxyCreator所需的事务拦截器 -->
- <property name="interceptorNames">
- <list>
- <!-- 此处可增加其他新的Interceptor -->
- <value>transactionInterceptor</value>
- </list>
- </property>
- </bean>
-
-
-
-
-
- <bean id="AlcorTCountriesDAO" class="com.firemax.test.hibernate.AlcorTCountriesDAO">
- <property name="entityManagerFactory" ref="entityManagerFactory" />
- </bean>
- <bean id="AlcorTProvincesDAO" class="com.firemax.test.hibernate.AlcorTProvincesDAO">
- <property name="entityManagerFactory" ref="entityManagerFactory" />
- </bean>
- <bean id="AlcotTDistrictDAO" class="com.firemax.test.hibernate.AlcotTDistrictDAO">
- <property name="entityManagerFactory" ref="entityManagerFactory" />
- </bean>
- <bean id="AlcorTCitysDAO" class="com.firemax.test.hibernate.AlcorTCitysDAO">
- <property name="entityManagerFactory" ref="entityManagerFactory" />
- </bean>
-
- <bean id="CountryService" class="com.firemax.test.service.CountryService">
- <property name="alcorTCountriesDAO" ref="AlcorTCountriesDAO" />
- <property name="alcorTProvincesDAO" ref="AlcorTProvincesDAO" />
- <property name="alcorTCitysDAO" ref="AlcorTCitysDAO" />
- <property name="alcotTDistrictDAO" ref="AlcotTDistrictDAO" />
- </bean>
-
- </beans>
注意红色部分。这部分和(一)里面提到的那个applicationContext.xml中使用的bean是不同的。这里面已经用到了spring 的jpa部分。
其中 <property name="persistenceUnitName" value="testerPU" /> 是指向了一个 jpa的PU(Persistent Units)
那么这个 是在哪里定义的呢?
这里的定义是在你的 classes(src)目录下META-INF下的persistence.xml文件中来定义
persistence.xml文件内容如下:
- <?xml version="1.0" encoding="UTF-8"?>
- <persistence xmlns="http://java.sun.com/xml/ns/persistence"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
- http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
- version="1.0">
-
- <persistence-unit name="testerPU"
- transaction-type="RESOURCE_LOCAL">
- <provider>org.hibernate.ejb.HibernatePersistence</provider>
- <class>com.firemax.test.hibernate.AlcorTCountries</class>
- <class>com.firemax.test.hibernate.AlcorTProvinces</class>
- <class>com.firemax.test.hibernate.AlcotTDistrict</class>
- <class>com.firemax.test.hibernate.AlcorTCitys</class>
- <properties>
- <property name="hibernate.connection.driver_class"
- value="com.mysql.jdbc.Driver" />
- <property name="hibernate.connection.url"
- value="jdbc:mysql://localhost:3306/alcorweb?useUnicode=true&characterEncoding=utf-8" />
- <property name="hibernate.connection.username"
- value="alcorweb" />
- <property name="hibernate.connection.password"
- value="alcorweb" />
- <property name="hibernate.connection.provider_class" value="org.hibernate.connection.C3P0ConnectionProvider"/>
- <property name="hibernate.c3p0.max_size" value="100"/>
- <property name="hibernate.c3p0.min_size" value="20"/>
- <property name="hibernate.c3p0.timeout" value="120"/>
- <property name="hibernate.c3p0.max_statements" value="0"/>
- <property name="hibernate.c3p0.idle_test_period" value="120"/>
- <property name="hibernate.c3p0.acquire_increment" value="5 "/>
-
- <property name="hibernate.cache.provider_class" value="org.hibernate.cache.EhCacheProvider"/>
- <property name="hibernate.cache.use_query_cache" value="false"/>
- <property name="hibernate.show_sql" value="false"/>
- <property name="hibernate.useUnicode" value="true"/>
- <property name="hibernate.characterEncoding" value="utf8"/>
- </properties>
- </persistence-unit>
- </persistence>
仔细观察他的代码,我们发现其实和hibernate.cfg.xml和相似。都有指向pojo的定义 和 database连接的定义。先别着急。我们这次的优化,就先完成这个目标。主要是引入的spring的jpa框架。
后面将介绍更进一步的优化。来展示jpa 和 注释注入的能力。
- ===========================================================================
- 通过 (一),(二)的介绍。我们已经做了初步的简化程序。
但是在我们编写spring 框架的代码时候。一直遵循是这样一个规则:所有在spring中注入的bean 都建议定义成私有的域变量。并且要配套写上 get 和 set方法。虽然 可以通过eclipse等工具来自动生成。但是还是会引起程序阅读性上的不便。那么既然注解这么强大。是否可以也把他精简掉呢?
当然可以。这个标签就是@Autowired
Spring 2.5 引入了 @Autowired 注释,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。
要实现我们要精简程序的目的。需要这样来处理:
o 在applicationContext.xml中加入:
2. <!-- 该 BeanPostProcessor 将自动对标注 @Autowired 的 Bean 进行注入 -->
3. <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
o 修改在原来注入spirng容器中的bean的方法。在域变量上加上标签@Autowired,并且去掉 相应的get 和set方法
1. /*国家,省份,城市,城区信息维护服务
2. * Created on 2008-9-26
3. *
4. * 徐泽宇 roamer
5. */
6. package com.firemax.test.service;
7.
8. import java.util.ArrayList;
9. import java.util.Iterator;
10. import java.util.List;
11.
12. import org.apache.commons.logging.Log;
13. import org.apache.commons.logging.LogFactory;
14. import org.dom4j.Document;
15. import org.dom4j.DocumentHelper;
16. import org.dom4j.Element;
17. import org.springframework.beans.factory.annotation.Autowired;
18.
19. import com.firemax.test.hibernate.AlcorTCitys;
20. import com.firemax.test.hibernate.AlcorTCitysDAO;
21. import com.firemax.test.hibernate.AlcorTCountries;
22. import com.firemax.test.hibernate.AlcorTCountriesDAO;
23. import com.firemax.test.hibernate.AlcorTProvinces;
24. import com.firemax.test.hibernate.AlcorTProvincesDAO;
25. import com.firemax.test.hibernate.AlcotTDistrict;
26. import com.firemax.test.hibernate.AlcotTDistrictDAO;
27.
28.
29. public class CountryService {
30. private static Log logger = LogFactory.getLog(CountryService.class);
31. @Autowired
32. private AlcorTCountriesDAO alcorTCountriesDAO;
33. @Autowired
34. private AlcorTProvincesDAO alcorTProvincesDAO;
35. @Autowired
36. private AlcorTCitysDAO alcorTCitysDAO;
37. @Autowired
38. private AlcotTDistrictDAO alcotTDistrictDAO;
39.
40. public CountryService(){
41.
42. }
43.
44. /**修改一个国家信息
45. * @param alcorTCountries
46. * @throws Exception
47. */
48. public void updateCountry(AlcorTCountries alcorTCountries ) throws Exception{
49. this.alcorTCountriesDAO.update(alcorTCountries);
50. }
51.
52. ....
53. //这里去掉了哪些DAO 变量的get 和set 方法。
54.
55.
56.
57.
58. }
59.
60.
o 在applicatonContext.xml中 把原来 引用的<porpery >标签也去掉。
1. <bean id="CountryService" class="com.firemax.test.service.CountryService">
2. <property name="alcorTCountriesDAO" ref="AlcorTCountriesDAO" />
3. <property name="alcorTProvincesDAO" ref="AlcorTProvincesDAO" />
4. <property name="alcorTCitysDAO" ref="AlcorTCitysDAO" />
5. <property name="alcotTDistrictDAO" ref="AlcotTDistrictDAO" />
6. </bean>
修改成
7. <bean id="CountryService" class="com.firemax.test.service.CountryService">
8.
9. </bean>
当然,我们也可以在构造函数上使用@Auwowired 注解 。如果构造函数有两个入参,分别是 bean1 和 bean2,@Autowired 将分别寻找和它们类型匹配的 Bean,将它们作为 CountryService (Bean1 bean1 ,Bean2 bean2) 的入参来创建 CountryService Bean。
在运行一下你的业务程序。如果没有错误。恭喜你。这个步骤我们又完成了。
======================================================================
在(三)里面。我们引入了 <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>这个bean 来处理@Autowired注解。
其实在spring 里面还有其他三个BeanPostProcessor 。总共有四个,分别是:
AutowiredAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor
PersistenceAnnotationBeanPostProcessor
equiredAnnotationBeanPostProcessor
但是直接在 Spring 配置文件中定义这些 Bean 显得比较笨拙。Spring 为我们提供了一种方便的注册这些 BeanPostProcessor 的方式,这就是 <context:annotation-config/>
Spring 2.1 添加了一个新的 context 的 Schema 命名空间,该命名空间对注释驱动、属性文件引入、加载期织入等功能提供了便捷的配置。我们知道注释本身是不会做任何事情的,它仅提供元数据信息。要使元数据信息真正起作用,必须让负责处理这些元数据的处理器工作起来。
这段代码就是 启用了这个命名空间后的applicationContext.xml文件
0. <?xml version="1.0" encoding="UTF-8"?>
1. <beans xmlns="http://www.springframework.org/schema/beans"
2. xmlns:context="http://www.springframework.org/schema/context"
3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4. xmlns:tx="http://www.springframework.org/schema/tx"
5. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
6. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
7. http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"
8. >
9.
10.
11. <bean id="entityManagerFactory"
12. class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
13. <property name="persistenceUnitName" value="testerPU" />
14. </bean>
15. <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
16. <property name="entityManagerFactory" ref="entityManagerFactory" />
17. </bean>
18.
19. <tx:annotation-driven transaction-manager="transactionManager" />
20.
21. <bean id="transactionInterceptor"
22. class="org.springframework.transaction.interceptor.TransactionInterceptor">
23. <!-- 事务拦截器bean需要依赖注入一个事务管理器 -->
24. <property name="transactionManager">
25. <ref local="transactionManager" />
26. </property>
27. <property name="transactionAttributes">
28. <!-- 下面定义事务(指service里面的方法)传播属性 -->
29. <props>
30. <prop key="insert*">PROPAGATION_REQUIRED</prop>
31. <prop key="update*">PROPAGATION_REQUIRED</prop>
32. <prop key="save*">PROPAGATION_REQUIRED</prop>
33. <prop key="add*">PROPAGATION_REQUIRED</prop>
34. <prop key="update*">PROPAGATION_REQUIRED</prop>
35. <prop key="remove*">PROPAGATION_REQUIRED</prop>
36. <prop key="delete*">PROPAGATION_REQUIRED</prop>
37. <prop key="get*">PROPAGATION_REQUIRED,readOnly
38. </prop>
39. <prop key="find*">PROPAGATION_REQUIRED,readOnly
40. </prop>
41. <prop key="load*">PROPAGATION_REQUIRED,readOnly
42. </prop>
43. <prop key="change*">PROPAGATION_REQUIRED</prop>
44. <prop key="count*">PROPAGATION_REQUIRED</prop>
45. <prop key="*">PROPAGATION_REQUIRED</prop>
46. </props>
47. </property>
48. </bean>
49.
50. <!-- 该 BeanPostProcessor 将自动对标注 @Autowired 的 Bean 进行注入 -->
51. <!-- 这个Processor 已经被 <context:annotation-config/> 所简化
52. <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
53. -->
54. <context:annotation-config/>
55.
56.
57. <!-- 定义自动代理BeanNameAutoProxyCreator -->
58. <bean id="beanNameAutoProxyCreator"
59. class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
60. <!-- 指定对满足哪些bean name的bean自动生成业务代理 -->
61. <property name="beanNames">
62. <list>
63. <value>*Service</value>
64. </list>
65. </property>
66. <!-- 下面定义BeanNameAutoProxyCreator所需的事务拦截器 -->
67. <property name="interceptorNames">
68. <list>
69. <!-- 此处可增加其他新的Interceptor -->
70. <value>transactionInterceptor</value>
71. </list>
72. </property>
73. </bean>
74.
75.
76.
77.
78.
79. <bean id="AlcorTCountriesDAO" class="com.firemax.test.hibernate.AlcorTCountriesDAO">
80. <property name="entityManagerFactory" ref="entityManagerFactory" />
81. </bean>
82. <bean id="AlcorTProvincesDAO" class="com.firemax.test.hibernate.AlcorTProvincesDAO">
83. <property name="entityManagerFactory" ref="entityManagerFactory" />
84. </bean>
85. <bean id="AlcotTDistrictDAO" class="com.firemax.test.hibernate.AlcotTDistrictDAO">
86. <property name="entityManagerFactory" ref="entityManagerFactory" />
87. </bean>
88. <bean id="AlcorTCitysDAO" class="com.firemax.test.hibernate.AlcorTCitysDAO">
89. <property name="entityManagerFactory" ref="entityManagerFactory" />
90. </bean>
91.
92. <bean id="CountryService" class="com.firemax.test.service.CountryService"/>
93.
94.
95. </beans>
注意2段标红的内容,就是这次更新的配置内容。在配置文件中使用 context 命名空间之前,必须在 <beans> 元素中声明 context 命名空间。
===========================================================================================
虽然我们可以通过 @Autowired 在 Bean 类中使用自动注入功能,但是 Bean 还是在 applicatonContext.xml 文件中通过 <bean> 进行定义 —— 在前面的例子中,我们还是在配置文件中定义 Bean,通过 @Autowired为 Bean 的成员变量、方法形参或构造函数形参提供自动注入的功能。
那么能不是也可以通过注解定义 Bean,从 XML 配置文件中完全移除 Bean 定义的配置呢?
答案是肯定的,我们通过 Spring 2.5 提供的 @Component 注释就可以达到这个目标了。
修改Bean的java类的代码如下,在类名前面加上 @Component注解
0. package com.firemax.test.service;
1.
2. import java.util.ArrayList;
3. import java.util.Iterator;
4. import java.util.List;
5.
6. import org.apache.commons.logging.Log;
7. import org.apache.commons.logging.LogFactory;
8. import org.dom4j.Document;
9. import org.dom4j.DocumentHelper;
10. import org.dom4j.Element;
11. import org.springframework.beans.factory.annotation.Autowired;
12. import org.springframework.stereotype.Component;
13.
14.
15. import com.firemax.test.hibernate.AlcorTCitys;
16. import com.firemax.test.hibernate.AlcorTCitysDAO;
17. import com.firemax.test.hibernate.AlcorTCountries;
18. import com.firemax.test.hibernate.AlcorTCountriesDAO;
19. import com.firemax.test.hibernate.AlcorTProvinces;
20. import com.firemax.test.hibernate.AlcorTProvincesDAO;
21. import com.firemax.test.hibernate.AlcotTDistrict;
22. import com.firemax.test.hibernate.AlcotTDistrictDAO;
23.
24. @Component
25. public class CountryService {
26. private static Log logger = LogFactory.getLog(CountryService.class);
27. @Autowired
28. private AlcorTCountriesDAO alcorTCountriesDAO;
29. @Autowired
30. private AlcorTProvincesDAO alcorTProvincesDAO;
31. @Autowired
32. private AlcorTCitysDAO alcorTCitysDAO;
33. @Autowired
34. private AlcotTDistrictDAO alcotTDistrictDAO;
35.
36. public CountryService(){
37.
38. }
39. //这里是业务逻辑的方法
40. 。。。。。
41. }
然后,我们修改配置文件applicatonContext.xml中,启用自动注入的功能,而放弃原来的<bean>方式的配置
42. <?xml version="1.0" encoding="UTF-8"?>
43. <beans xmlns="http://www.springframework.org/schema/beans"
44. xmlns:context="http://www.springframework.org/schema/context"
45. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
46. xmlns:tx="http://www.springframework.org/schema/tx"
47. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
48. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
49. http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"
50. default-autowire="autodetect">
51. <bean id="entityManagerFactory"
52. class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
53. <property name="persistenceUnitName" value="testerPU" />
54. </bean>
55. <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
56. <property name="entityManagerFactory" ref="entityManagerFactory" />
57. </bean>
58. <tx:annotation-driven transaction-manager="transactionManager" />
59. <bean id="transactionInterceptor"
60. class="org.springframework.transaction.interceptor.TransactionInterceptor">
61. <!-- 事务拦截器bean需要依赖注入一个事务管理器 -->
62. <property name="transactionManager">
63. <ref local="transactionManager" />
64. </property>
65. <property name="transactionAttributes">
66. <!-- 下面定义事务(指service里面的方法)传播属性 -->
67. <props>
68. <prop key="insert*">PROPAGATION_REQUIRED</prop>
69. <prop key="update*">PROPAGATION_REQUIRED</prop>
70. <prop key="save*">PROPAGATION_REQUIRED</prop>
71. <prop key="add*">PROPAGATION_REQUIRED</prop>
72. <prop key="update*">PROPAGATION_REQUIRED</prop>
73. <prop key="remove*">PROPAGATION_REQUIRED</prop>
74. <prop key="delete*">PROPAGATION_REQUIRED</prop>
75. <prop key="get*">PROPAGATION_REQUIRED,readOnly
76. </prop>
77. <prop key="find*">PROPAGATION_REQUIRED,readOnly
78. </prop>
79. <prop key="load*">PROPAGATION_REQUIRED,readOnly
80. </prop>
81. <prop key="change*">PROPAGATION_REQUIRED</prop>
82. <prop key="count*">PROPAGATION_REQUIRED</prop>
83. <prop key="*">PROPAGATION_REQUIRED</prop>
84. </props>
85. </property>
86. </bean>
87.
88. <!-- 该 BeanPostProcessor 将自动对标注 @Autowired 的 Bean 进行注入 -->
89. <!-- 这个Processor 已经被 <context:annotation-config/> 所简化
90. <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
91. -->
92. <!-- <context:component-scan/> 配置项不但启用了对类包进行扫描以实施注释驱动 Bean 定义的功能,同时还启用了注释驱动自动注入的功能(即还隐式地在内部注册了 AutowiredAnnotationBeanPostProcessor 和 CommonAnnotationBeanPostProcessor),因此当使用 <context:component-scan/> 后,就可以将 <context:annotation-config/> 移除了。 -->
93. <context:component-scan base-package ="com.firemax"/>
94.
95.
96. <!-- 定义自动代理BeanNameAutoProxyCreator -->
97. <bean id="beanNameAutoProxyCreator"
98. class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
99. <!-- 指定对满足哪些bean name的bean自动生成业务代理 -->
100. <property name="beanNames">
101. <list>
102. <value>*Service</value>
103. </list>
104. </property>
105. <!-- 下面定义BeanNameAutoProxyCreator所需的事务拦截器 -->
106. <property name="interceptorNames">
107. <list>
108. <!-- 此处可增加其他新的Interceptor -->
109. <value>transactionInterceptor</value>
110. </list>
111. </property>
112. </bean>
113. <!--
114. <bean id="AlcorTCountriesDAO" class="com.firemax.test.hibernate.AlcorTCountriesDAO">
115. <property name="entityManagerFactory" ref="entityManagerFactory" />
116. </bean>
117. <bean id="AlcorTProvincesDAO" class="com.firemax.test.hibernate.AlcorTProvincesDAO">
118. <property name="entityManagerFactory" ref="entityManagerFactory" />
119. </bean>
120. <bean id="AlcotTDistrictDAO" class="com.firemax.test.hibernate.AlcotTDistrictDAO">
121. <property name="entityManagerFactory" ref="entityManagerFactory" />
122. </bean>
123. <bean id="AlcorTCitysDAO" class="com.firemax.test.hibernate.AlcorTCitysDAO">
124. <property name="entityManagerFactory" ref="entityManagerFactory" />
125. </bean>
126.
127. <bean id="CountryService" class="com.firemax.test.service.CountryService"/>
128. -->
129. </beans>
新的applicaitonContext.xml 配置文件中蓝色的部分就是原来的<bean>的注入方式,现在已经给屏蔽了。不需要再写。而红色部分就是使用了<context:component-scan base-package ="com.firemax"/> ,让spirng自动搜索,然后注入。
注意:
o 这里注入的bean 的名称是按照类的名称,把第一个字母改成小写来命名的。比如例子中的CountryService的bean的名称就是countryService.
o 我们也可以通过@Component("countryService") 这种方式来显示的定义一个bean的注入名称。但是在大多数情况下没有必要。
<context:component-scan/> 的 base-package 属性指定了需要扫描的类包,类包及其递归子包中所有的类都会被处理。
<context:component-scan/> 还允许定义过滤器将基包下的某些类纳入或排除。Spring 支持以下 4 种类型的过滤方式,通过下表说明:
扫描过滤方式
过滤器类型 | 说明 |
注释 | 假如 com.firemax.test.SomeAnnotation 是一个注释类,我们可以将使用该注释的类过滤出来。 |
类名指定 | 通过全限定类名进行过滤,如您可以指定将 com.firemax.test.IncludeService纳入扫描,而将 com.firemax.test.NotIncludeService 排除在外。 |
正则表达式 | 通过正则表达式定义过滤的类,如下所示: com/.firemax/.test/.Default.* |
AspectJ 表达式 | 通过 AspectJ 表达式定义过滤的类,如下所示: com. firemax.test..*Service+ |
下面是一个简单的例子:
默认情况下通过 @Component 定义的 Bean 都是 singleton 的,如果需要使用其它作用范围的 Bean,可以通过 @Scope 注释来达到目标,如以下代码所示:
通过 @Scope 指定 Bean 的作用范围
这样,当从 Spring 容器中获取 boss Bean 时,每次返回的都是新的实例了。
在Spring2.5中引入了更多的典型化注解,@Repository ,@Service,@Controler是@Component的细化。分别表示持久层,服务层,控制层。建议使用这个注解来取代@Component
附上一个java Applicaiton的简单测试程序
132. /*
133. * Created on 2008-9-28
134. *
135. * 徐泽宇 roamer
136. */
137. package com.firemax.test.tester;
138.
139. import java.util.Iterator;
140.
141. import org.springframework.context.ApplicationContext;
142. import org.springframework.context.support.FileSystemXmlApplicationContext;
143.
144. import com.firemax.test.hibernate.AlcorTCitys;
145. import com.firemax.test.hibernate.AlcorTCitysDAO;
146. import com.firemax.test.hibernate.AlcorTCountries;
147. import com.firemax.test.hibernate.AlcorTProvinces;
148. import com.firemax.test.hibernate.AlcotTDistrict;
149. import com.firemax.test.hibernate.AlcotTDistrictDAO;
150. import com.firemax.test.service.CountryService;
151.
152.
153.
154. public class Tester {
155.
156. /**
157. * @param args
158. */
159. public static void main(String[] args) throws Exception{
160. // TODO Auto-generated method stub
161. ApplicationContext ctx = new FileSystemXmlApplicationContext("/WebContent/WEB-INF/classes/applicationContext*.xml");
162. String[] beans = ctx.getBeanDefinitionNames();
163. for (int i = 0 ; i < beans.length;i++)
164. {
165. System.out.println(beans[i]);
166. }
167. CountryService countryService= (CountryService)ctx.getBean("countryService");
168.
169. AlcorTCountries alcorTCountries= countryService.getCountriesInfo("CN");
170. System.out.println(alcorTCountries.getCountry());
171. System.out.println("开始调用子类");
172. System.out.println(alcorTCountries.getAlcorTProvinceses().size());
173. Iterator<AlcorTProvinces> it = alcorTCountries.getAlcorTProvinceses().iterator();
174. while (it.hasNext()){
175. AlcorTProvinces alcorTProvinces= (AlcorTProvinces)it.next();
176. System.out.println(alcorTProvinces.getProvinceName());
177. }
178. AlcotTDistrict alcotTDistrict= new AlcotTDistrict();
179. alcotTDistrict.setDistrictCode("22");
180. alcotTDistrict.setDistrictName("浦东");
181. AlcorTCitys alcorTCitys =countryService.getCityInfo("021");
182. alcotTDistrict.setAlcorTCitys(alcorTCitys);
183. countryService.saveProvinces(alcotTDistrict);
184.
185. }
186. }
187.
188.
在所有的JPOPO中,我们可以使用@Entity 这个注解来注入 JOPO。这样我们在 Persistent.xml中就不需要在 定义哪些POJO的类了。
感谢 JPA 感谢Spring ,终于不要频繁的去定义和修改这些Bean了