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

12.2  注解实现Bean依赖注入

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容器中开启注解驱动支持,即使用如下配置方式开启:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation=" http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-3.0.xsd">  

    <context:annotation-config/>  

</beans>
   

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

12.2.2  Spring自带依赖注入注解

一、@Required:依赖检查;

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

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

@Requried
setter方法

1、准备测试Bean

    package cn.javass.spring.chapter12;
    public class TestBean {
        private String message;
        @Required
        public void setMessage(String message) {
            this.message = message;
        }
        public String getMessage() {
            return message;
        }
    }  

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

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

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

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

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

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

二、@Autowired:自动装配

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

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

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

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

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

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

    package cn.javass.spring.chapter12;
    import org.springframework.beans.factory.annotation.Autowired;
    public class TestBean11 {
        private String message;
        @Autowired //构造器注入
        private TestBean11(String message) {
            this.message = message;
        }
        //省略message的getter和setter
    }  

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

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

3、测试类如下:

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

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

注意,因为上面,所以直接注入进来

<bean id="message" class="java.lang.String">
    <constructor-arg index="0" value="hello"/>
</bean>  

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

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

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

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

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

3、测试方法如下:

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

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

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

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

    package cn.javass.spring.chapter12;
    import org.springframework.beans.factory.annotation.Autowired;
    public class TestBean13 {
        private String message;
        @Autowired //setter方法注入
        public void setMessage(String message) {
            this.message = message;
        }
        public String getMessage() {
            return message;
        }
    }  
    package cn.javass.spring.chapter12;
    //省略import
    public class TestBean14 {
        private String message;
        private List<String> list;
        @Autowired(required = true) //任意一个或多个参数方法注入
        private void initMessage(String message, ArrayList<String> list) {
            this.message = message;
            this.list = list;
        }
        //省略getter和setter
    }  

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

<bean id="testBean13" class="cn.javass.spring.chapter12.TestBean13"/>
<bean id="testBean14" class="cn.javass.spring.chapter12.TestBean14"/>
<bean id="list" class="java.util.ArrayList">
    <constructor-arg index="0">
        <list>
            <ref bean="message"/>
            <ref bean="message"/>
        </list>
   </constructor-arg>
</bean> 

3、测试方法如下:

@Test
public void testAutowiredForMethod() {
    TestBean13 testBean13 = ctx.getBean("testBean13", TestBean13.class);
    Assert.assertEquals("hello", testBean13.getMessage());  

    TestBean14 testBean14 = ctx.getBean("testBean14", TestBean14.class);
    Assert.assertEquals("hello", testBean14.getMessage());
    Assert.assertEquals(ctx.getBean("list", List.class), testBean14.getList());
}  

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1、准备测试Bean:

    package cn.javass.spring.chapter12;
    import javax.sql.DataSource;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;  

    public class TestBean31 {
        private DataSource dataSource;
        @Autowired
        //根据<qualifier>标签指定Bean限定标识符
        public void initDataSource(@Qualifier("mysqlDataSource") DataSource dataSource) {
            this.dataSource = dataSource;
        }
        public DataSource getDataSource() {
            return dataSource;
        }
    }  

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

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

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

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

3、测试方法如下:

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

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

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

1、准备测试Bean:

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

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

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

3、测试方法如下

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

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

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

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

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

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

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

2、准备测试Bean:

    package cn.javass.spring.chapter12;
    //省略import
    public class TestBean33 {
        private DataSource mysqlDataSource;
        private DataSource oracleDataSource;
        @Autowired
        public void initDataSource(@Mysql DataSource mysqlDataSource, @Oracle DataSource oracleDataSource) {
            this.mysqlDataSource = mysqlDataSource;
            this.oracleDataSource = oracleDataSource;
        }
        public DataSource getMysqlDataSource() {
            return mysqlDataSource;
        }
        public DataSource getOracleDataSource() {
            return oracleDataSource;
        }
    }  

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

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

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

    <bean id="mysqlDataSourceBean" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
         <qualifier value="mysqlDataSource"/>
         <qualifier type="cn.javass.spring.chapter12.qualifier.Mysql"/>
    </bean>
    <bean id="oracleDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
          <qualifier type="cn.javass.spring.chapter12.qualifier.Oracle"/>
    </bean>  

5、测试方法如下:

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

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

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

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

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

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

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

3、准备测试Bean:

package cn.javass.spring.chapter12;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import cn.javass.spring.chapter12.qualifier.DataBase;
import cn.javass.spring.chapter12.qualifier.DataSourceType;
public class TestBean34 {
    private DataSource mysqlDataSource;
    private DataSource oracleDataSource;
    @Autowired
    public void initDataSource(
            @DataSourceType(ip="localhost", database=DataBase.MYSQL)
            DataSource mysqlDataSource,
            @DataSourceType(ip="localhost", database=DataBase.ORACLE)
            DataSource oracleDataSource) {
        this.mysqlDataSource = mysqlDataSource;
        this.oracleDataSource = oracleDataSource;
    }
      //省略getter方法
} 

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

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

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

    <bean id="mysqlDataSourceBean" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <qualifier value="mysqlDataSource"/>
        <qualifier type="cn.javass.spring.chapter12.qualifier.Mysql"/>
        <qualifier type="cn.javass.spring.chapter12.qualifier.DataSourceType">
            <attribute key="ip" value="localhost"/>
            <attribute key="database" value="MYSQL"/>
        </qualifier>
    </bean>
    <bean id="oracleDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <qualifier type="cn.javass.spring.chapter12.qualifier.Oracle"/>
        <qualifier type="cn.javass.spring.chapter12.qualifier.DataSourceType">
            <attribute key="ip" value="localhost"/>
            <attribute key="database" value="ORACLE"/>
        </qualifier>
    </bean>  

6、测试方法如下:

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

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

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

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

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

2、准备测试Bean:

    package cn.javass.spring.chapter12;
    //省略import
    public class TestBean35 {
        private DataSource dataSoruce;
        @Autowired
        public TestBean35(@CustomQualifier("oracleDataSource") DataSource dataSource) {
            this.dataSoruce = dataSource;
        }
        public DataSource getDataSoruce() {
            return dataSoruce;
        }
    }  

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

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

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

    <bean id="customAutowireConfigurer" class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">
        <property name="customQualifierTypes">
            <set>
                <value>cn.javass.spring.chapter12.qualifier.CustomQualifier</value>
            </set>
       </property>
    </bean>  

5、测试方法如下:

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

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

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

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

12.2.3  JSR-250注解

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

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

1、准备测试Bean:

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

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

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

3、测试方法如下:

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

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

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

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

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

 

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

    @PostConstruct
    public void init() {
        System.out.println("==========init");
    }
    @PreDestroy
    public void destroy() {
        System.out.println("==========destroy");
    }  

2、修改测试方法如下:

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

类似于通过<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数据源

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

2、准备测试Bean:

    package cn.javass.spring.chapter12;
    import javax.inject.Inject;
    import javax.inject.Named;
    import javax.sql.DataSource;
    import cn.javass.spring.chapter12.qualifier.JSR330Mysql;
    public class TestBean51 {
        private DataSource mysqlDataSource;
        private DataSource oracleDataSource;
        @Inject
        public void initDataSoruce(
                @JSR330Mysql  DataSource mysqlDataSource,
                @Named("oracleDataSource") DataSource oracleDataSource) {
            this.mysqlDataSource = mysqlDataSource;
            this.oracleDataSource = oracleDataSource;  

        }
        //省略getter
    }  

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

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

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

    <bean id="mysqlDataSourceBean" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
             <qualifier value="mysqlDataSource"/>
             <qualifier type="cn.javass.spring.chapter12.qualifier.Mysql"/>
             <qualifier type="cn.javass.spring.chapter12.qualifier.DataSourceType">
                 <attribute key="ip" value="localhost"/>
                 <attribute key="database" value="MYSQL"/>
             </qualifier>
             <qualifier type="cn.javass.spring.chapter12.qualifier.JSR330Mysql"/>
    </bean>  

5、测试方法如下:

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

测试也通过了,说明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:

    package cn.javass.spring.chapter12;
    //省略import
    public class TestBean61 {
        @PersistenceContext(unitName = "entityManagerFactory")
        private EntityManager entityManager;  

        @PersistenceUnit(unitName = "entityManagerFactory")
        private EntityManagerFactory entityManagerFactory;  

        public EntityManager getEntityManager() {
            return entityManager;
        }
        public EntityManagerFactory getEntityManagerFactory() {
            return entityManagerFactory;
        }
    }  

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

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

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

3、测试方法如下:

    @Test
    public void testJpaInject() {
        TestBean61 testBean61 = ctx.getBean("testBean61", TestBean61.class);
        Assert.assertNotNull(testBean61.getEntityManager());
        Assert.assertNotNull(testBean61.getEntityManagerFactory());
    }  

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

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

时间: 2024-12-14 17:43:34

开涛spring3(12.2) - 零配置 之 12.2 注解实现Bean依赖注入的相关文章

开涛spring3(12.3) - 零配置 之 12.3 注解实现Bean定义

12.3  注解实现Bean定义 12.3.1  概述 前边介绍的Bean定义全是基于XML方式定义配置元数据,且在[12.2注解实现Bean依赖注入]一节中介绍了通过注解来减少配置数量,但并没有完全消除在XML配置文件中的Bean定义,因此有没有方式完全消除XML配置Bean定义呢? Spring提供通过扫描类路径中的特殊注解类来自动注册 Bean定义.同注解驱动事务一样需要开启自动扫描并注册Bean定义支持,使用方式如下(resources/chapter12/ componentDefin

开涛spring3(12.4) - 零配置 之 12.4 基于Java类定义Bean配置元数据

12.4  基于Java类定义Bean配置元数据 12.4.1  概述 基于Java类定义Bean配置元数据,其实就是通过Java类定义Spring配置元数据,且直接消除XML配置文件. 基于Java类定义Bean配置元数据中的@Configuration注解的类等价于XML配置文件,@Bean注解的方法等价于XML配置文件中的Bean定义. 基于Java类定义Bean配置元数据需要通过AnnotationConfigApplicationContext加载配置类及初始化容器,类似于XML配置文

开涛spring3(5.4) - Spring表达式语言 之 5.4在Bean定义中使用EL

5.4.1  xml风格的配置 SpEL支持在Bean定义时注入,默认使用“#{SpEL表达式}”表示,其中“#root”根对象默认可以认为是 ApplicationContext,只有ApplicationContext实现默认支持SpEL,获取根对象属性其实是获取容器中的Bean. 首先看下配置方式(chapter5/el1.xml)吧: <bean id="world" class="java.lang.String"> <construct

开涛spring3(3.1) - DI的配置使用

3.1.1  依赖和依赖注入 传统应用程序设计中所说的依赖一般指“类之间的关系”,那先让我们复习一下类之间的关系: 泛化:表示类与类之间的继承关系.接口与接口之间的继承关系: 实现:表示类对接口的实现: 依赖:当类与类之间有使用关系时就属于依赖关系,不同于关联关系,依赖不具有“拥有关系”,而是一种“相识关系”,只在某个特定地方(比如某个方法体内)才有关系. 关联:表示类与类或类与接口之间的依赖关系,表现为“拥有关系”:具体到代码可以用实例变量来表示: 聚合:属于是关联的特殊情况,体现部分-整体关

开涛spring3(1) - Spring概述

1.1.1  Spring是什么 Spring是一个开源的轻量级Java SE(Java 标准版本)/Java EE(Java 企业版本)开发应用框架,其目的是用于简化企业级应用程序开发.应用程序是由一组相互协作的对象组成.而在传统应用程序开发中,一个完整的应用是由一组相 互协作的对象组成.所以开发一个应用除了要开发业务逻辑之外,最多的是关注如何使这些对象协作来完成所需功能,而且要低耦合.高内聚.业务逻辑开发是不可 避免的,那如果有个框架出来帮我们来创建对象及管理这些对象之间的依赖关系.可能有人

开涛spring3(2.1) - IoC基础

2.1.1  IoC是什么 Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想.在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对 象内部直接控制.如何理解好Ioc呢?理解好Ioc的关键是要明确“谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了”,那我们 来深入分析一下: ●谁控制谁,控制什么:传 统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象:而IoC

开涛spring3(2.2) - IoC 容器基本原理及其helloword

2.2.1  IoC容器的概念 IoC容器就是具有依赖注入功能的容器,IoC容器负责实例化.定位.配置应用程序中的对象及建立这些对象间的依赖.应用程序无需直接在代码中new相关的对象,应用程序由IoC容器进行组装.在Spring中BeanFactory是IoC容器的实际代表者. Spring IoC容器如何知道哪些是它管理的对象呢?这就需要配置文件,Spring IoC容器通过读取配置文件中的配置元数据,通过元数据对应用中的各个对象进行实例化及装配.一般使用基于xml配置文件进行配置元数据,而且

开涛spring3(3.4) - DI 之 3.4 Bean的作用域

3.4  Bean的作用域 什么是作用域呢?即“scope”,在面向对象程序设计中一般指对象或变量之间的可见范围.而在Spring容器中是指其创建的Bean对象相对于其他Bean对象的请求可见范围. Spring提供“singleton”和“prototype”两种基本作用域,另外提供“request”.“session”.“global session”三种web作用域:Spring还允许用户定制自己的作用域. 3.4.1  基本的作用域        一.singleton:指“single

spring(读取外部数据库配置信息、基于注解管理bean、DI)

###解析外部配置文件在resources文件夹下,新建db.properties(和数据库连接相关的信息) driverClassName=com.mysql.jdbc.Driverurl=jdbc:mysql://localhost:3306/dbusername=rootpassword=root 开发步骤1)创建maven工程添加web.xml添加tomcat运行环境添加jar spring-webmvc,junit,commons-dbcp,mysql添加application.xml