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容器中查找。

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

  1. 开涛spring3(12.1) - 零配置 之 12.1 概述

    12.1  概述 12.1.1  什么是零配置 在SSH集成一章中大家注意到项目结构和包结构是不是很有规律,类库放到WEB-INF/lib文件夹下,jsp文件放到WEB-INF/jsp文件夹下,web ...

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

    12.3  注解实现Bean定义 12.3.1  概述 前边介绍的Bean定义全是基于XML方式定义配置元数据,且在[12.2注解实现Bean依赖注入]一节中介绍了通过注解来减少配置数量,但并没有完全 ...

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

    12.4  基于Java类定义Bean配置元数据 12.4.1  概述 基于Java类定义Bean配置元数据,其实就是通过Java类定义Spring配置元数据,且直接消除XML配置文件. 基于Java ...

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

    5.4.1  xml风格的配置 SpEL支持在Bean定义时注入,默认使用“#{SpEL表达式}”表示,其中“#root”根对象默认可以认为是 ApplicationContext,只有Applica ...

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

    3.1.1  依赖和依赖注入 传统应用程序设计中所说的依赖一般指“类之间的关系”,那先让我们复习一下类之间的关系: 泛化:表示类与类之间的继承关系.接口与接口之间的继承关系: 实现:表示类对接口的实现 ...

  6. 开涛spring3(2.3) - IoC的配置使用

    2.3.1  XML配置的结构 一般配置文件结构如下: <beans> <import resource=”resource1.xml”/> <bean id=”bean ...

  7. 开涛spring3(1) - Spring概述

    1.1.1  Spring是什么 Spring是一个开源的轻量级Java SE(Java 标准版本)/Java EE(Java 企业版本)开发应用框架,其目的是用于简化企业级应用程序开发.应用程序是由 ...

  8. 开涛spring3(3.3) - DI 之 3.3 更多DI的知识

    3.3.1  延迟初始化Bean 延迟初始化也叫做惰性初始化,指不提前初始化Bean,而是只有在真正使用时才创建及初始化Bean. 配置方式很简单只需在<bean>标签上指定 “lazy- ...

  9. 跟开涛老师学shiro -- INI配置

    之前章节我们已经接触过一些INI配置规则了,如果大家使用过如spring之类的IoC/DI容器的话,Shiro提供的INI配置也是非常类似的,即可以理解为是一个IoC/DI容器,但是区别在于它从一个根 ...

随机推荐

  1. MVC 5 + EF6 完整教程15 -- 使用DI进行解耦

    如果大家研究一些开源项目,会发现无处不在的DI(Dependency Injection依赖注入). 本篇文章将会详细讲述如何在MVC中使用Ninject实现DI 文章提纲 场景描述 & 问题 ...

  2. MYSQL中 ENUM 类型的详细解释

    ENUM 是一个字符串对象,其值通常选自一个允许值列表中,该列表在表创建时的列规格说明中被明确地列举. 在下列某些情况下,值也可以是空串("") 或 NULL: 如果将一个无效值插 ...

  3. HNOI2017前被虐记及感悟

    本文所记录的时间以HNOI2017第一天考试时间为DAY1,前一天为DAY0,以此类推. 本文记载了博主从HNOI2017开始前一周进行全真模拟考试的被虐过程和结果.文章内可能包含博主的不良情绪,如果 ...

  4. 数据泵 TTS(传输表空间技术)

    1.源库准备环境 --创建被传输的表空间create tablespace tts logging datafile '/home/oracle/app/oradata/orcl/tts01.dbf' ...

  5. 处理json数据的空数据为任意字符

    处理json数据的空数据为任意字符 有时候从后台返回来的数据需要处理一下,根据实际开发需求,不能在页面上直接显示空字符,需要显示为"无内容"或者其他字段,而有些json数据结构比较 ...

  6. 表单的序列化ajax

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...

  7. AngularJS学习笔记5

    11.AngularJS  HTML DOM ng-disabled 指令直接绑定应用程序数据到 HTML 的 disabled 属性. <button ng-disabled="my ...

  8. ios系统判断某些适配 __IPHONE_OS_VERSION_MAX_ALLOWED

    由于app的最新设计字体是ios9之后的平方字体,但app最低支持ios7,so...想在常量配置文件类里统一适配下字体,如下: //适配字体,ios9及以上系统使用新字体--平方字体 #if __I ...

  9. python——面向对象基础

    概述 面向过程:根据业务逻辑从上到下写垒代码 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函数进行分类和封装,让开发“更快更好更强...” 面向过程编程最易被初学 ...

  10. 消息队列NetMQ 原理分析3-命令产生/处理和回收线程

    消息队列NetMQ 原理分析3-命令产生/处理和回收线程 前言 介绍 目的 命令 命令结构 命令产生 命令处理 创建Socket(SocketBase) 创建连接 创建绑定 回收线程 释放Socket ...