12.2.1  概述

注解实现Bean配置主要用来进行如依赖注入、生命周期回调方法定义等,不能消除XML文件中的Bean元数据定义,且基于XML配置中的依赖注入的数据将覆盖基于注解配置中的依赖注入的数据

Spring3的基于注解实现Bean依赖注入支持如下三种注解:

  • Spring自带依赖注入注解: Spring自带的一套依赖注入注解;
  • JSR-250注解:Java平台的公共注解,是Java EE 5规范之一,在JDK6中默认包含这些注解,从Spring2.5开始支持。
  • JSR-330注解:Java 依赖注入标准,Java EE 6规范之一,可能在加入到未来JDK版本,从Spring3开始支持;
  • JPA注解:用于注入持久化上下文和尸体管理器。

这三种类型的注解在Spring3中都支持,类似于注解事务支持,想要使用这些注解需要在Spring容器中开启注解驱动支持,即使用如下配置方式开启:

java代码:

  1. <beans xmlns="http://www.springframework.org/schema/beans"
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xmlns:context="http://www.springframework.org/schema/context"
  4. xsi:schemaLocation=" http://www.springframework.org/schema/beans
  5. http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  6. http://www.springframework.org/schema/context
  7. http://www.springframework.org/schema/context/spring-context-3.0.xsd">
  8. <context:annotation-config/>
  9. </beans>

这样就能使用注解驱动依赖注入了,该配置文件位于“resources/ chapter12/dependecyInjectWithAnnotation.xml”。

12.2.2  Spring自带依赖注入注解

一、@Required:依赖检查;

对应于基于XML配置中的依赖检查,但XML配置的依赖检查将检查所有setter方法,详见【3.3.4  依赖检查】;

基于@Required的依赖检查表示注解的setter方法必 须,即必须通过在XML配置中配置setter注入,如果没有配置在容器启动时会抛出异常从而保证在运行时不会遇到空指针异常,@Required只能放 置在setter方法上,且通过XML配置的setter注入,可以使用如下方式来指定:

java代码:

  1. @Requried
  2. setter方法

1、准备测试Bean

java代码:

  1. package cn.javass.spring.chapter12;
  2. public class TestBean {
  3. private String message;
  4. @Required
  5. public void setMessage(String message) {
  6. this.message = message;
  7. }
  8. public String getMessage() {
  9. return message;
  10. }
  11. }

2、在Spring配置文件(chapter12/dependecyInjectWithAnnotation.xml)添加如下Bean配置:

java代码:

  1. <bean id="testBean" class="cn.javass.spring.chapter12.TestBean">
  2. <property name="message" ref="message"/>
  3. </bean>
  4. <bean id="message" class="java.lang.String">
  5. <constructor-arg index="0" value="hello"/>
  6. </bean>

3、测试类和测试方法如下:

java代码:

  1. package cn.javass.spring.chapter12;
  2. //省略import
  3. public class DependencyInjectWithAnnotationTest {
  4. private static String configLocation = "classpath:chapter12/dependecyInjectWithAnnotation.xml";
  5. private static ApplicationContext ctx = new ClassPathXmlApplicationContext("configLocation");
  6. //1、Spring自带依赖注入注解
  7. @Test
  8. public void testRequiredForXmlSetterInject() {
  9. TestBean testBean = ctx.getBean("testBean", TestBean.class);
  10. Assert.assertEquals("hello", testBean.getMessage());
  11. }
  12. }

在XML配置文件中必须指定setter注入,否则在Spring容器启动时将抛出如下异常:

java代码:

  1. org.springframework.beans.factory.BeanCreationException:
  2. Error creating bean with name 'testBean' defined in class path resource [chapter12/dependecyInjectWithAnnotation.xml]: Initialization of bean failed;
  3. nested exception is org.springframework.beans.factory.BeanInitializationException: Property 'message' is required for bean 'testBean'

二、@Autowired:自动装配

自动装配,用于替代基于XML配置的自动装配,详见【3.3.3  自动装配】。

基于@Autowired的自动装配,默认是根据类型注入,可以用于构造器、字段、方法注入,使用方式如下:

java代码:

  1. @Autowired(required=true)
  2. 构造器、字段、方法

@Autowired默认是根据参数类型进行自动装配,且必须有 一个Bean候选者注入,如果允许出现0个Bean候选者需要设置属性“required=false”,“required”属性含义和 @Required一样,只是@Required只适用于基于XML配置的setter注入方式。

(1)、构造器注入:通过将@Autowired注解放在构造器上来完成构造器注入,默认构造器参数通过类型自动装配,如下所示:

1、准备测试Bean,在构造器上添加@AutoWired注解:

java代码:

  1. package cn.javass.spring.chapter12;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. public class TestBean11 {
  4. private String message;
  5. @Autowired //构造器注入
  6. private TestBean11(String message) {
  7. this.message = message;
  8. }
  9. //省略message的getter和setter
  10. }

2、在Spring配置文件(chapter12/dependecyInjectWithAnnotation.xml)添加如下Bean配置:

java代码:

  1. <bean id="testBean11" class="cn.javass.spring.chapter12.TestBean11"/>

3、测试类如下:

java代码:

  1. @Test
  2. public void testAutowiredForConstructor() {
  3. TestBean11 testBean11 = ctx.getBean("testBean11", TestBean11.class);
  4. Assert.assertEquals("hello", testBean11.getMessage());
  5. }

在Spring配置文件中没有对“testBean11”进行构造器注入和setter注入配置,而是通过在构造器上添加@ Autowired来完成根据参数类型完成构造器注入。

(2)、字段注入:通过将@Autowired注解放在构造器上来完成字段注入。

1、准备测试Bean,在字段上添加@AutoWired注解:

java代码:

  1. package cn.javass.spring.chapter12;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. public class TestBean12 {
  4. @Autowired //字段注入
  5. private String message;
  6. //省略getter和setter
  7. }

2、在Spring配置文件(chapter12/dependecyInjectWithAnnotation.xml)添加如下Bean配置:

java代码:

  1. <bean id="testBean12" class="cn.javass.spring.chapter12.TestBean12"/>

3、测试方法如下:

java代码:

  1. @Test
  2. public void testAutowiredForField() {
  3. TestBean12 testBean12 = ctx.getBean("testBean12", TestBean12.class);
  4. Assert.assertEquals("hello", testBean12.getMessage());
  5. }

字段注入在基于XML配置中无相应概念,字段注入不支持静态类型字段的注入。

(3)、方法参数注入:通过将@Autowired注解放在方法上来完成方法参数注入。

1、准备测试Bean,在方法上添加@AutoWired注解:

java代码:

  1. package cn.javass.spring.chapter12;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. public class TestBean13 {
  4. private String message;
  5. @Autowired //setter方法注入
  6. public void setMessage(String message) {
  7. this.message = message;
  8. }
  9. public String getMessage() {
  10. return message;
  11. }
  12. }
java代码:

  1. package cn.javass.spring.chapter12;
  2. //省略import
  3. public class TestBean14 {
  4. private String message;
  5. private List<String> list;
  6. @Autowired(required = true) //任意一个或多个参数方法注入
  7. private void initMessage(String message, ArrayList<String> list) {
  8. this.message = message;
  9. this.list = list;
  10. }
  11. //省略getter和setter
  12. }

2、在Spring配置文件(chapter12/dependecyInjectWithAnnotation.xml)添加如下Bean配置:

java代码:

  1. <bean id="testBean13" class="cn.javass.spring.chapter12.TestBean13"/>
  2. <bean id="testBean14" class="cn.javass.spring.chapter12.TestBean14"/>
  3. <bean id="list" class="java.util.ArrayList">
  4. <constructor-arg index="0">
  5. <list>
  6. <ref bean="message"/>
  7. <ref bean="message"/>
  8. </list>
  9. </constructor-arg>
  10. </bean>

3、测试方法如下:

java代码:

  1. @Test
  2. public void testAutowiredForMethod() {
  3. TestBean13 testBean13 = ctx.getBean("testBean13", TestBean13.class);
  4. Assert.assertEquals("hello", testBean13.getMessage());
  5. TestBean14 testBean14 = ctx.getBean("testBean14", TestBean14.class);
  6. Assert.assertEquals("hello", testBean14.getMessage());
  7. Assert.assertEquals(ctx.getBean("list", List.class), testBean14.getList());
  8. }

方法参数注入除了支持setter方法注入,还支持1个或多个参数的普通方法注入,在基于XML配置中不支持1个或多个参数的普通方法注入,方法注入不支持静态类型方法的注入。

注意“initMessage(String message, ArrayList<String> list)”方法签名中为什么使用ArrayList而不是List呢?具体参考【3.3.3  自动装配】一节中的集合类型注入区别。

三、@Value:注入SpEL表达式;

用于注入SpEL表达式,可以放置在字段方法或参数上,使用方式如下:

java代码:

  1. @Value(value = "SpEL表达式")
  2. 字段、方法、参数

1、可以在类字段上使用该注解:

java代码:

  1. @Value(value = "#{message}")
  2. private String message;

2、可以放置在带@Autowired注解的方法的参数上:

java代码:

  1. @Autowired
  2. public void initMessage(@Value(value = "#{message}#{message}") String message) {
  3. this.message = message;
  4. }

3、还可以放置在带@Autowired注解的构造器的参数上:

java代码:

  1. @Autowired
  2. private TestBean43(@Value(value = "#{message}#{message}") String message) {
  3. this.message = message;
  4. }

具体测试详见DependencyInjectWithAnnotationTest 类的testValueInject测试方法。

四、@Qualifier:限定描述符,用于细粒度选择候选者;

@Autowired默认是根据类型进行注入的,因此如果有多个类型一样的Bean候选者,则需要限定其中一个候选者,否则将抛出异常,详见【3.3.3  自动装配】中的根据类型进行注入;

@Qualifier限定描述符除了能根据名字进行注入,但能进行更细粒度的控制如何选择候选者,具体使用方式如下:

java代码:

  1. @Qualifier(value = "限定标识符")
  2. 字段、方法、参数

(1)、根据基于XML配置中的<qualifier>标签指定的名字进行注入,使用如下方式指定名称:

java代码:

  1. <qualifier  type="org.springframework.beans.factory.annotation.Qualifier"  value="限定标识符"/>

其中type属性可选,指定类型,默认就是Qualifier注解类,name就是给Bean候选者指定限定标识符,一个Bean定义中只允许指定类型不同的<qualifier>,如果有多个相同type后面指定的将覆盖前面的。

1、准备测试Bean:

java代码:

  1. package cn.javass.spring.chapter12;
  2. import javax.sql.DataSource;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.beans.factory.annotation.Qualifier;
  5. public class TestBean31 {
  6. private DataSource dataSource;
  7. @Autowired
  8. //根据<qualifier>标签指定Bean限定标识符
  9. public void initDataSource(@Qualifier("mysqlDataSource") DataSource dataSource) {
  10. this.dataSource = dataSource;
  11. }
  12. public DataSource getDataSource() {
  13. return dataSource;
  14. }
  15. }

2、在Spring配置文件(chapter12/dependecyInjectWithAnnotation.xml)添加如下Bean配置:

java代码:

  1. <bean id="testBean31" class="cn.javass.spring.chapter12.TestBean31"/>

我们使用@Qualifier("mysqlDataSource")来指定候选Bean的限定标识符,我们需要在配置文件中使用<qualifier>标签来指定候选Bean的限定标识符“mysqlDataSource”:

java代码:

  1. <bean id="mysqlDataSourceBean" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
  2. <qualifier value="mysqlDataSource"/>
  3. </bean>

3、测试方法如下:

java代码:

  1. @Test
  2. public void testQualifierInject1() {
  3. TestBean31 testBean31 = ctx.getBean("testBean31", TestBean31.class);
  4. try {
  5. //使用<qualifier>指定的标识符只能被@Qualifier使用
  6. ctx.getBean("mysqlDataSource");
  7. Assert.fail();
  8. } catch (Exception e) {
  9. //找不到该Bean
  10. Assert.assertTrue(e instanceof NoSuchBeanDefinitionException);
  11. }
  12. Assert.assertEquals(ctx.getBean("mysqlDataSourceBean"), testBean31.getDataSource());
  13. }

从测试可以看出使用<qualifier>标签指定的限定标识符只能被@Qualifier使用,不能作为Bean的标识符,如“ctx.getBean("mysqlDataSource")”是获取不到Bean的。

(2)、缺省的根据Bean名字注入:最基本方式,是在Bean上没有指定<qualifier>标签时一种容错机制,即缺省情况下使用Bean标识符注入,但如果你指定了<qualifier>标签将不会发生容错。

1、准备测试Bean:

java代码:

  1. package cn.javass.spring.chapter12;
  2. //省略import
  3. public class TestBean32 {
  4. private DataSource dataSource;
  5. @Autowired
  6. @Qualifier(value = "mysqlDataSource2") //指定Bean限定标识符
  7. //@Qualifier(value = "mysqlDataSourceBean")
  8. //是错误的注入,不会发生回退容错,因为你指定了<qualifier>
  9. public void initDataSource(DataSource dataSource) {
  10. this.dataSource = dataSource;
  11. }
  12. public DataSource getDataSource() {
  13. return dataSource;
  14. }
  15. }

2、在Spring配置文件(chapter12/dependecyInjectWithAnnotation.xml)添加如下Bean配置:

java代码:

  1. <bean id="testBean32" class="cn.javass.spring.chapter12.TestBean32"/>
  2. <bean id="oracleDataSource"  class="org.springframework.jdbc.datasource.DriverManagerDataSource"/>

3、测试方法如下:

java代码:

  1. @Test
  2. public void testQualifierInject2() {
  3. TestBean32 testBean32 = ctx.getBean("testBean32", TestBean32.class);
  4. Assert.assertEquals(ctx.getBean("oracleDataSource"), testBean32.getDataSource());
  5. }

默认情况下(没指定<qualifier>标签)@Qualifier的value属性将匹配Bean 标识符。

(3)、扩展@Qualifier限定描述符注解:对@Qualifier的扩展来提供细粒度选择候选者;

具体使用方式就是自定义一个注解并使用@Qualifier注解其即可使用。

首先让我们考虑这样一个问题,如果我们有两个数据源,分别为Mysql和Oracle,因此注入两者相关资源时就牵扯到数据库相关,如在DAO层注入SessionFactory时,当然可以采用前边介绍的方式,但为了简单和直观我们希望采用自定义注解方式。

1、扩展@Qualifier限定描述符注解来分别表示Mysql和Oracle数据源

java代码:

  1. package cn.javass.spring.chapter12.qualifier;
  2. import org.springframework.beans.factory.annotation.Qualifier;
  3. /** 表示注入Mysql相关 */
  4. @Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER})
  5. @Retention(RetentionPolicy.RUNTIME)
  6. @Qualifier
  7. public @interface Mysql {
  8. }
java代码:

  1. package cn.javass.spring.chapter12.qualifier;
  2. import org.springframework.beans.factory.annotation.Qualifier;
  3. /** 表示注入Oracle相关 */
  4. @Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER})
  5. @Retention(RetentionPolicy.RUNTIME)
  6. @Qualifier
  7. public @interface Oracle {
  8. }

 

2、准备测试Bean:

java代码:

  1. package cn.javass.spring.chapter12;
  2. //省略import
  3. public class TestBean33 {
  4. private DataSource mysqlDataSource;
  5. private DataSource oracleDataSource;
  6. @Autowired
  7. public void initDataSource(@Mysql DataSource mysqlDataSource, @Oracle DataSource oracleDataSource) {
  8. this.mysqlDataSource = mysqlDataSource;
  9. this.oracleDataSource = oracleDataSource;
  10. }
  11. public DataSource getMysqlDataSource() {
  12. return mysqlDataSource;
  13. }
  14. public DataSource getOracleDataSource() {
  15. return oracleDataSource;
  16. }
  17. }

3、在Spring配置文件(chapter12/dependecyInjectWithAnnotation.xml)添加如下Bean配置:

java代码:

  1. <bean id="testBean33" class="cn.javass.spring.chapter12.TestBean33"/>

4、在Spring修改定义的两个数据源:

java代码:

  1. <bean id="mysqlDataSourceBean" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
  2. <qualifier value="mysqlDataSource"/>
  3. <qualifier type="cn.javass.spring.chapter12.qualifier.Mysql"/>
  4. </bean>
  5. <bean id="oracleDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
  6. <qualifier type="cn.javass.spring.chapter12.qualifier.Oracle"/>
  7. </bean>

5、测试方法如下:

java代码:

  1. @Test
  2. public void testQualifierInject3() {
  3. TestBean33 testBean33 = ctx.getBean("testBean33", TestBean33.class);
  4. Assert.assertEquals(ctx.getBean("mysqlDataSourceBean"), testBean33.getMysqlDataSoruce());
  5. Assert.assertEquals(ctx.getBean("oracleDataSource"), testBean33.getOracleDataSoruce());
  6. }

测试也通过了,说明我们扩展的@Qualifier限定描述符注解也能很好工作。

前边演示了不带属性的注解,接下来演示一下带参数的注解:

1、首先定义数据库类型:

java代码:

  1. package cn.javass.spring.chapter12.qualifier;
  2. public enum DataBase {
  3. ORACLE, MYSQL;
  4. }

2、其次扩展@Qualifier限定描述符注解

java代码:

  1. package cn.javass.spring.chapter12.qualifier;
  2. //省略import
  3. @Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER})
  4. @Retention(RetentionPolicy.RUNTIME)
  5. @Qualifier
  6. public @interface DataSourceType {
  7. String ip();      //指定ip,用于多数据源情况
  8. DataBase database();//指定数据库类型
  9. }

3、准备测试Bean:

java代码:

  1. package cn.javass.spring.chapter12;
  2. import javax.sql.DataSource;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import cn.javass.spring.chapter12.qualifier.DataBase;
  5. import cn.javass.spring.chapter12.qualifier.DataSourceType;
  6. public class TestBean34 {
  7. private DataSource mysqlDataSource;
  8. private DataSource oracleDataSource;
  9. @Autowired
  10. public void initDataSource(
  11. @DataSourceType(ip="localhost", database=DataBase.MYSQL)
  12. DataSource mysqlDataSource,
  13. @DataSourceType(ip="localhost", database=DataBase.ORACLE)
  14. DataSource oracleDataSource) {
  15. this.mysqlDataSource = mysqlDataSource;
  16. this.oracleDataSource = oracleDataSource;
  17. }
  18. //省略getter方法
  19. }

4、在Spring配置文件(chapter12/dependecyInjectWithAnnotation.xml)添加如下Bean配置:

java代码:

  1. <bean id="testBean34" class="cn.javass.spring.chapter12.TestBean34"/>

5、在Spring修改定义的两个数据源:

java代码:

  1. <bean id="mysqlDataSourceBean" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
  2. <qualifier value="mysqlDataSource"/>
  3. <qualifier type="cn.javass.spring.chapter12.qualifier.Mysql"/>
  4. <qualifier type="cn.javass.spring.chapter12.qualifier.DataSourceType">
  5. <attribute key="ip" value="localhost"/>
  6. <attribute key="database" value="MYSQL"/>
  7. </qualifier>
  8. </bean>
  9. <bean id="oracleDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
  10. <qualifier type="cn.javass.spring.chapter12.qualifier.Oracle"/>
  11. <qualifier type="cn.javass.spring.chapter12.qualifier.DataSourceType">
  12. <attribute key="ip" value="localhost"/>
  13. <attribute key="database" value="ORACLE"/>
  14. </qualifier>
  15. </bean>

6、测试方法如下:

java代码:

  1. @Test
  2. public void testQualifierInject3() {
  3. TestBean34 testBean34 = ctx.getBean("testBean34", TestBean34.class);
  4. Assert.assertEquals(ctx.getBean("mysqlDataSourceBean"), testBean34.getMysqlDataSource());
  5. Assert.assertEquals(ctx.getBean("oracleDataSource"), testBean34.getOracleDataSoruce());
  6. }

测试也通过了,说明我们扩展的@Qualifier限定描述符注解也能很好工作。

 

  

四、自定义注解限定描述符:完全不使用@Qualifier,而是自己定义一个独立的限定注解;

1、首先使用如下方式定义一个自定义注解限定描述符:

java代码:

  1. package cn.javass.spring.chapter12.qualifier;
  2. //省略import
  3. @Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER})
  4. @Retention(RetentionPolicy.RUNTIME)
  5. public @interface CustomQualifier {
  6. String value();
  7. }

2、准备测试Bean:

java代码:

  1. package cn.javass.spring.chapter12;
  2. //省略import
  3. public class TestBean35 {
  4. private DataSource dataSoruce;
  5. @Autowired
  6. public TestBean35(@CustomQualifier("oracleDataSource") DataSource dataSource) {
  7. this.dataSoruce = dataSource;
  8. }
  9. public DataSource getDataSoruce() {
  10. return dataSoruce;
  11. }
  12. }

3、在Spring配置文件(chapter12/dependecyInjectWithAnnotation.xml)添加如下Bean配置:

java代码:

  1. <bean id="testBean35" class="cn.javass.spring.chapter12.TestBean35"/>

4、然后在Spring配置文件中注册CustomQualifier自定义注解限定描述符,只有注册了Spring才能识别:

java代码:

  1. <bean id="customAutowireConfigurer" class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">
  2. <property name="customQualifierTypes">
  3. <set>
  4. <value>cn.javass.spring.chapter12.qualifier.CustomQualifier</value>
  5. </set>
  6. </property>
  7. </bean>

5、测试方法如下:

java代码:

  1. @Test
  2. public void testQualifierInject5() {
  3. TestBean35 testBean35 = ctx.getBean("testBean35", TestBean35.class);
  4. Assert.assertEquals(ctx.getBean("oracleDataSource"), testBean35.getDataSource());
  5. }

从测试中可看出,自定义的和Spring自带的没什么区别,因此如果没有足够的理由请使用Spring自带的Qualifier注解。

到此限定描述符介绍完毕,在此一定要注意以下几点:

  • 限定标识符和Bean的描述符是不一样的;
  • 多个Bean定义中可以使用相同的限定标识符;
  • 对于集合、数组、字典类型的限定描述符注入,将注入多个具有相同限定标识符的Bean。

12.2.3  JSR-250注解

一、@Resource:自动装配,默认根据类型装配,如果指定name属性将根据名字装配,可以使用如下方式来指定:

java代码:

  1. @Resource(name = "标识符")
  2. 字段或setter方法

1、准备测试Bean:

java代码:

  1. package cn.javass.spring.chapter12;
  2. import javax.annotation.Resource;
  3. public class TestBean41 {
  4. @Resource(name = "message")
  5. private String message;
  6. //省略getter和setter
  7. }

2、在Spring配置文件(chapter12/dependecyInjectWithAnnotation.xml)添加如下Bean配置:

java代码:

  1. <bean id="testBean41" class="cn.javass.spring.chapter12.TestBean41"/>

3、测试方法如下:

java代码:

  1. @Test
  2. public void testResourceInject1() {
  3. TestBean41 testBean41 = ctx.getBean("testBean41", TestBean41.class);
  4. Assert.assertEquals("hello", testBean41.getMessage());
  5. }

使用非常简单,和@Autowired不同的是可以指定name来根据名字注入。

使用@Resource需要注意以下几点:

  • @Resource注解应该只用于setter方法注入,不能提供如@Autowired多参数方法注入;
  • @Resource在没有指定name属性的情况下首先将根据setter方法对于的字段名查找资源,如果找不到再根据类型查找;
  • @Resource首先将从JNDI环境中查找资源,如果没找到默认再到Spring容器中查找,因此如果JNDI环境中有和Spring容器同名的资源时需要注意。

二、@PostConstruct和PreDestroy:通过注解指定初始化和销毁方法定义;

 

1、在测试类TestBean41中添加如下代码:

java代码:

  1. @PostConstruct
  2. public void init() {
  3. System.out.println("==========init");
  4. }
  5. @PreDestroy
  6. public void destroy() {
  7. System.out.println("==========destroy");
  8. }

2、修改测试方法如下:

java代码:

  1. @Test
  2. public void resourceInjectTest1() {
  3. ((ClassPathXmlApplicationContext) ctx).registerShutdownHook();
  4. TestBean41 testBean41 = ctx.getBean("testBean41", TestBean41.class);
  5. Assert.assertEquals("hello", testBean41.getMessage());
  6. }

类似于通过<bean>标签的init-method和destroy-method属性指定的初始化和销毁方法,但具有更高优先级,即注解方式的初始化和销毁方法将先执行。

12.2.4  JSR-330注解

在测试之前需要准备JSR-330注解所需要的jar包,到spring-framework-3.0.5.RELEASE-dependencies.zip中拷贝如下jar包到类路径:

com.springsource.javax.inject-1.0.0.jar

一、@Inject等价于默认的@Autowired,只是没有required属性;

二、@Named指定Bean名字,对应于Spring自带@Qualifier中的缺省的根据Bean名字注入情况;

三、@Qualifier只对应于Spring自带@Qualifier中的扩展@Qualifier限定描述符注解,即只能扩展使用,没有value属性。

1、首先扩展@Qualifier限定描述符注解来表示Mysql数据源

java代码:

  1. package cn.javass.spring.chapter12.qualifier;
  2. //省略部分import
  3. import javax.inject.Qualifier;
  4. @Target({ElementType.FIELD, ElementType.PARAMETER})
  5. @Retention(RetentionPolicy.RUNTIME)
  6. @Qualifier
  7. public @interface JSR330Mysql {
  8. }

 

2、准备测试Bean:

java代码:

  1. package cn.javass.spring.chapter12;
  2. import javax.inject.Inject;
  3. import javax.inject.Named;
  4. import javax.sql.DataSource;
  5. import cn.javass.spring.chapter12.qualifier.JSR330Mysql;
  6. public class TestBean51 {
  7. private DataSource mysqlDataSource;
  8. private DataSource oracleDataSource;
  9. @Inject
  10. public void initDataSoruce(
  11. @JSR330Mysql  DataSource mysqlDataSource,
  12. @Named("oracleDataSource") DataSource oracleDataSource) {
  13. this.mysqlDataSource = mysqlDataSource;
  14. this.oracleDataSource = oracleDataSource;
  15. }
  16. //省略getter
  17. }

3、在Spring配置文件(chapter12/dependecyInjectWithAnnotation.xml)添加如下Bean配置:

java代码:

  1. <bean id="testBean51" class="cn.javass.spring.chapter12.TestBean51"/>

4、在Spring修改定义的mysqlDataSourceBean数据源:

java代码:

  1. <bean id="mysqlDataSourceBean" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
  2. <qualifier value="mysqlDataSource"/>
  3. <qualifier type="cn.javass.spring.chapter12.qualifier.Mysql"/>
  4. <qualifier type="cn.javass.spring.chapter12.qualifier.DataSourceType">
  5. <attribute key="ip" value="localhost"/>
  6. <attribute key="database" value="MYSQL"/>
  7. </qualifier>
  8. <qualifier type="cn.javass.spring.chapter12.qualifier.JSR330Mysql"/>
  9. </bean>

5、测试方法如下:

java代码:

  1. @Test
  2. public void testInject() {
  3. TestBean51 testBean51 = ctx.getBean("testBean51", TestBean51.class);
  4. Assert.assertEquals(ctx.getBean("mysqlDataSourceBean"), testBean51.getMysqlDataSource());
  5. Assert.assertEquals(ctx.getBean("oracleDataSource"), testBean51.getOracleDataSource());
  6. }

测试也通过了,说明JSR-330注解也能很好工作。

从测试中可以看出JSR-330注解和Spring自带注解依赖注入时主要有以下特点:

  • Spring自带的@Autowired的缺省情况等价于JSR-330的@Inject注解;
  • Spring自带的@Qualifier的缺省的根据Bean名字注入情况等价于JSR-330的@Named注解;
  • Spring自带的@Qualifier的扩展@Qualifier限定描述符注解情况等价于JSR-330的@Qualifier注解。

12.2.5  JPA注解

用于注入EntityManagerFactory和EntityManager。

1、准备测试Bean:

java代码:

  1. package cn.javass.spring.chapter12;
  2. //省略import
  3. public class TestBean61 {
  4. @PersistenceContext(unitName = "entityManagerFactory")
  5. private EntityManager entityManager;
  6. @PersistenceUnit(unitName = "entityManagerFactory")
  7. private EntityManagerFactory entityManagerFactory;
  8. public EntityManager getEntityManager() {
  9. return entityManager;
  10. }
  11. public EntityManagerFactory getEntityManagerFactory() {
  12. return entityManagerFactory;
  13. }
  14. }

2、在Spring配置文件(chapter12/dependecyInjectWithAnnotation.xml)添加如下Bean配置:

java代码:

  1. <import resource="classpath:chapter7/applicationContext-resources.xml"/>
  2. <import resource="classpath:chapter8/applicationContext-jpa.xml"/>
  3. <bean id="testBean61" class="cn.javass.spring.chapter12.TestBean61"/>

此处需要引用第七章和八章的配置文件,细节内容请参考七八两章。

3、测试方法如下:

java代码:

  1. @Test
  2. public void testJpaInject() {
  3. TestBean61 testBean61 = ctx.getBean("testBean61", TestBean61.class);
  4. Assert.assertNotNull(testBean61.getEntityManager());
  5. Assert.assertNotNull(testBean61.getEntityManagerFactory());
  6. }

测试也通过了,说明JPA注解也能很好工作。

JPA注解类似于@Resource注解同样是先根据unitName属性去JNDI环境中查找,如果没找到在到Spring容器中查找。

注解实现Bean依赖注入的更多相关文章

  1. 开涛spring3(12.2) - 零配置 之 12.2 注解实现Bean依赖注入

    12.2  注解实现Bean依赖注入 12.2.1  概述 注解实现Bean配置主要用来进行如依赖注入.生命周期回调方法定义等,不能消除XML文件中的Bean元数据定义,且基于XML配置中的依赖注入的 ...

  2. 002-Spring4 快速入门-项目搭建、基于注解的开发bean,Bean创建和装配、基于注解的开发bean,Bean初始化销毁、Bean装配,注解、Bean依赖注入

    一.项目搭建 1.项目创建 eclipse→project explorer→new→Project→Maven Project 默认配置即可创建项目 2.spring配置 <dependenc ...

  3. Spring bean依赖注入、bean的装配及相关注解

    依赖注入 Spring主要提供以下两种方法用于依赖注入 基于属性Setter方法注入 基于构造方法注入 Setter方法注入 例子: public class Communication { priv ...

  4. Spring学习3—控制反转(IOC)基于Annotation(注解)的依赖注入实现

    一.依赖注入--手工装配—注解方式 在java代码中使用@Autowired或@Resource注解方式进行装配的前提条件是:   1.引入context命名空间 需要在xml配置文件中配置以下信息: ...

  5. Spring实战2:装配bean—依赖注入的本质

    主要内容 Spring的配置方法概览 自动装配bean 基于Java配置文件装配bean 控制bean的创建和销毁 任何一个成功的应用都是由多个为了实现某个业务目标而相互协作的组件构成的,这些组件必须 ...

  6. Spring 源码分析之 bean 依赖注入原理(注入属性)

         最近在研究Spring bean 生命周期相关知识点以及源码,所以打算写一篇 Spring bean生命周期相关的文章,但是整理过程中发现涉及的点太多而且又很复杂,很难在一篇文章中把Spri ...

  7. Spring_02 注入类型值、利用引用注入类型值、spring表达式、与类相关的注解、与依赖注入相关的注解、注解扫描

    注意:注入基本类型值在本质上就是依赖注入,而且是利用的set方式进行的依赖注入 1 注入基本类型的值 <property name="基本类型的成员变量名" value=&q ...

  8. Spring4学习回顾之路03—XML配置Bean ,依赖注入的方式

    配置Bean的形式可以基于XML文件的方式,也可以基于注解的方式,而Bean的配置方式可以通过全类名(反射),通过工厂方式和FactoryBean. XML形式 <?xml version=&q ...

  9. Spring之使用注解实例化Bean并注入属性

    1.准备工作 (1)导入jar包 除了上篇文章使用到的基本jar包外,还得加入aop的jar包,所有jar包如下 所需jar包 (2)配置xml <?xml version="1.0& ...

随机推荐

  1. [NOIp2012提高组]借教室

    OJ题号:洛谷1083 思路:ZKW线段树 #include<cstdio> #include<cctype> #include<algorithm> inline ...

  2. iOS主流机型更新

    主流机型更新后,舍弃了原有的iPhone 4 ,iPhone 4s, iPhone 5 ,iPhone 5s.增加了iPhone X,iPhone 8和iPhone 8 plus. 总体上屏幕趋于一个 ...

  3. db2调优

    系统上线两个月左右,请IBM工程师对数据库进行了一次调优,主要收获感觉有以下几点: 1,应用服务器一定要与数据库服务器分开 2,如果存在多个数据库,一定要硬盘分开(io忙) 3,每个数据库的数据与日志 ...

  4. Compile SQLite3 from individual files

    下载非Amalgamation SQLite3源码 安装tcl, apt-get instal tcl 解压 mkdir build cd build ../configure make #make ...

  5. 5款替代微软Visio的开源免费软件

    提到流程图和图表设计,自然会想到微软出品的Office Visio,它是一款强大的流程图设计工具.Visio并不在Office标准套装中,需要额外付费购买,这可能会带来某些不便.一方面,并不是所有人都 ...

  6. 在ASP.NET Core2.0中使用百度在线编辑器UEditor(转)

    一.起因 UEditor是百度旗下的富文本编辑器,对于后端上传处理仅提供了Asp.Net 版的支持. 如果想在.Net Core项目中使用,那么后台上传接口需要重构. UEditorNetCore:百 ...

  7. WIN10平板如何打开文件夹选项

    打开计算机,然后查看,最后可以找到选项  

  8. Certificate Formats | Converting Certificates between different Formats

    Different Platforms & Devices requires SSL certificates in different formatseg:- A Windows Serve ...

  9. sql server Local Service, Local System or Network Service

    local system account local system 选项指定一个不需要密码的本地系统账号去连接同一台电脑的sql server.local system account会限制sql s ...

  10. Android BLE蓝牙开发-读写数据 获取UUID

    https://www.jianshu.com/p/3711cfbf7128 一个ble蓝牙设备有多个包括多个Profile 一个Profile中有多个服务Service(通过服务的uuid找到对应的 ...