`
jinnianshilongnian
  • 浏览: 21503984 次
  • 性别: Icon_minigender_1
博客专栏
5c8dac6a-21dc-3466-8abb-057664ab39c7
跟我学spring3
浏览量:2418662
D659df3e-4ad7-3b12-8b9a-1e94abd75ac3
Spring杂谈
浏览量:3008768
43989fe4-8b6b-3109-aaec-379d27dd4090
跟开涛学SpringMVC...
浏览量:5639479
1df97887-a9e1-3328-b6da-091f51f886a1
Servlet3.1规范翻...
浏览量:259916
4f347843-a078-36c1-977f-797c7fc123fc
springmvc杂谈
浏览量:1597310
22722232-95c1-34f2-b8e1-d059493d3d98
hibernate杂谈
浏览量:250216
45b32b6f-7468-3077-be40-00a5853c9a48
跟我学Shiro
浏览量:5858947
Group-logo
跟我学Nginx+Lua开...
浏览量:701999
5041f67a-12b2-30ba-814d-b55f466529d5
亿级流量网站架构核心技术
浏览量:785222
社区版块
存档分类
最新评论

【第十二章】零配置 之 12.2 注解实现Bean依赖注入 ——跟我学spring3

阅读更多

 

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

 

java代码:
<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注入,可以使用如下方式来指定:

 

java代码:
@Requried
setter方法

 

1、准备测试Bean

 

java代码:
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配置:

 

java代码:
<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、测试类和测试方法如下:

 

java代码:
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容器启动时将抛出如下异常:

 

java代码:
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的自动装配,默认是根据类型注入,可以用于构造器、字段、方法注入,使用方式如下:

 

java代码:
@Autowired(required=true)
构造器、字段、方法

 

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

 

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

 

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

 

java代码:
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配置:

 

java代码:
<bean id="testBean11" class="cn.javass.spring.chapter12.TestBean11"/>

 

3、测试类如下:

 

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

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

 

 

 

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

 

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

 

java代码:
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配置:

 

java代码:
<bean id="testBean12" class="cn.javass.spring.chapter12.TestBean12"/>

 

3、测试方法如下:

 

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

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

 

 

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

 

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

 

java代码:
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;
    }
}

 

 

 

java代码:
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配置:

 

java代码:
<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、测试方法如下:

 

java代码:
@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表达式,可以放置在字段方法或参数上,使用方式如下:

 

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

 

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

 

java代码:
@Value(value = "#{message}")
private String message;

 

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

 

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

 

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

 

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

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

 

 

 

 

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

 

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

 

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

 

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

 

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

 

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

 

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

 

 

1、准备测试Bean:

 

java代码:
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配置:

 

java代码:
<bean id="testBean31" class="cn.javass.spring.chapter12.TestBean31"/>

 

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

 

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

 

3、测试方法如下:

 

java代码:
@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:

 

java代码:
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配置:

 

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

 

3、测试方法如下:

 

java代码:
@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数据源

 

java代码:
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 {
}

 

 

java代码:
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:

 

java代码:
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配置:

 

java代码:
<bean id="testBean33" class="cn.javass.spring.chapter12.TestBean33"/>

 

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

 

java代码:
<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、测试方法如下:

 

java代码:
@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、首先定义数据库类型:

 

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

 

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

 

java代码:
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:

 

java代码:
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配置:

 

java代码:
<bean id="testBean34" class="cn.javass.spring.chapter12.TestBean34"/>

 

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

 

java代码:
<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、测试方法如下:

 

java代码:
@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、首先使用如下方式定义一个自定义注解限定描述符:

 

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

 

 

2、准备测试Bean:

 

java代码:
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配置:

 

java代码:
<bean id="testBean35" class="cn.javass.spring.chapter12.TestBean35"/>

 

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

 

java代码:
<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、测试方法如下:

 

java代码:
@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属性将根据名字装配,可以使用如下方式来指定:

 

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

 

1、准备测试Bean:

 

java代码:
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配置:

 

java代码:
<bean id="testBean41" class="cn.javass.spring.chapter12.TestBean41"/>

 

3、测试方法如下: 

 

java代码:
@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中添加如下代码:

 

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

 

2、修改测试方法如下:

 

java代码:
@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数据源

 

java代码:
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:

 

 

java代码:
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配置:

 

java代码:
<bean id="testBean51" class="cn.javass.spring.chapter12.TestBean51"/>

 

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

 

java代码:
<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、测试方法如下:

 

java代码:
@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:

 

java代码:
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配置:

 

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

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

 

 

3、测试方法如下:

 

java代码:
@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容器中查找。

 

 

 

原创内容,转载请注明私塾在线【http://sishuok.com/forum/blogPost/list/0/2545.html

37
8
分享到:
评论
19 楼 sbpcx 2015-03-12  
一日一博 写道
JSR-250注解
一、@Resource:自动装配,默认根据类型装配,如果指定name属性将根据名字装配,可以使用如下方式来指定:


这一段写错了貌似,@Resource默认是先按名称找,找不到再byType


是的。
18 楼 lejingw 2014-02-13  
package cn.javass.spring.chapter12;  
import org.springframework.beans.factory.annotation.Autowired;  
public class TestBean12 {  
    @Autowired //字段注入  
    private String message;  
    [color=red]//省略getter和setter  [/color]
}  

经调试,字段注入的方式,如果遇到private类型的字段,会在底层修改该字段的写入属性
java.lang.reflect.Field.setAccessible(true);
,从而直接调用
java.lang.reflect.Field.set(bean, value);
,而不需要调用setter方法的
17 楼 307622798 2012-11-30  
jinnianshilongnian 写道
一日一博 写道
jinnianshilongnian 写道
307622798 写道
博主,你好!有个小小的问题想请教一下,呵呵!
位置:
二、@Autowired:自动装配
(1)、构造器注入:
在这个段落里  bean的配置是这样的
<bean id="testBean11" class="cn.javass.spring.chapter12.TestBean11"/> 
在TestBean11这个类里面并没有使用无参的构造方法而只是这样的一个构造方法
    @Autowired //构造器注入 
    private TestBean11(String message) { 
        this.message = message; 
    }
我记得网上有人解释@autowired是这样解释的,@autowired是bytype来进行注入的,spring首先获得类型这里我想应该是TestBean11吧,那么spring会去spring容器里面寻找有没有该类型的对象。可是该bean并没有一个无参的构造方法,也就无法实例化对象啊,那应该就找不到这样的对象啊,为什么这里却能成功呢?望博主指教,谢谢


  @Autowired //构造器注入 
    private TestBean11(String message) { 

会进行构造器注入啊   所以如果找到String类型的Bean 就能注入成功

LZ  他的意思是问你为什么没有无参数构造方法,还能得到实例化对象的。他可能还没理解spring的DI原理还有bean的生命周期

构造器注入嘛  你在构造器上加了@Autowire就相当于告诉spring我要构造器注入

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

明白了,多谢博主和另外一位好心人啊!(*^__^*) 嘻嘻!
16 楼 jinnianshilongnian 2012-11-30  
一日一博 写道
jinnianshilongnian 写道
307622798 写道
博主,你好!有个小小的问题想请教一下,呵呵!
位置:
二、@Autowired:自动装配
(1)、构造器注入:
在这个段落里  bean的配置是这样的
<bean id="testBean11" class="cn.javass.spring.chapter12.TestBean11"/> 
在TestBean11这个类里面并没有使用无参的构造方法而只是这样的一个构造方法
    @Autowired //构造器注入 
    private TestBean11(String message) { 
        this.message = message; 
    }
我记得网上有人解释@autowired是这样解释的,@autowired是bytype来进行注入的,spring首先获得类型这里我想应该是TestBean11吧,那么spring会去spring容器里面寻找有没有该类型的对象。可是该bean并没有一个无参的构造方法,也就无法实例化对象啊,那应该就找不到这样的对象啊,为什么这里却能成功呢?望博主指教,谢谢


  @Autowired //构造器注入 
    private TestBean11(String message) { 

会进行构造器注入啊   所以如果找到String类型的Bean 就能注入成功

LZ  他的意思是问你为什么没有无参数构造方法,还能得到实例化对象的。他可能还没理解spring的DI原理还有bean的生命周期

构造器注入嘛  你在构造器上加了@Autowire就相当于告诉spring我要构造器注入

请参考本章的
1)、构造器注入:通过将@Autowired注解放在构造器上来完成构造器注入,默认构造器参数通过类型自动装配,如下所示:
15 楼 一日一博 2012-11-30  
jinnianshilongnian 写道
307622798 写道
博主,你好!有个小小的问题想请教一下,呵呵!
位置:
二、@Autowired:自动装配
(1)、构造器注入:
在这个段落里  bean的配置是这样的
<bean id="testBean11" class="cn.javass.spring.chapter12.TestBean11"/> 
在TestBean11这个类里面并没有使用无参的构造方法而只是这样的一个构造方法
    @Autowired //构造器注入 
    private TestBean11(String message) { 
        this.message = message; 
    }
我记得网上有人解释@autowired是这样解释的,@autowired是bytype来进行注入的,spring首先获得类型这里我想应该是TestBean11吧,那么spring会去spring容器里面寻找有没有该类型的对象。可是该bean并没有一个无参的构造方法,也就无法实例化对象啊,那应该就找不到这样的对象啊,为什么这里却能成功呢?望博主指教,谢谢


  @Autowired //构造器注入 
    private TestBean11(String message) { 

会进行构造器注入啊   所以如果找到String类型的Bean 就能注入成功

LZ  他的意思是问你为什么没有无参数构造方法,还能得到实例化对象的。他可能还没理解spring的DI原理还有bean的生命周期
14 楼 jinnianshilongnian 2012-11-30  
307622798 写道
博主,你好!有个小小的问题想请教一下,呵呵!
位置:
二、@Autowired:自动装配
(1)、构造器注入:
在这个段落里  bean的配置是这样的
<bean id="testBean11" class="cn.javass.spring.chapter12.TestBean11"/> 
在TestBean11这个类里面并没有使用无参的构造方法而只是这样的一个构造方法
    @Autowired //构造器注入 
    private TestBean11(String message) { 
        this.message = message; 
    }
我记得网上有人解释@autowired是这样解释的,@autowired是bytype来进行注入的,spring首先获得类型这里我想应该是TestBean11吧,那么spring会去spring容器里面寻找有没有该类型的对象。可是该bean并没有一个无参的构造方法,也就无法实例化对象啊,那应该就找不到这样的对象啊,为什么这里却能成功呢?望博主指教,谢谢


  @Autowired //构造器注入 
    private TestBean11(String message) { 

会进行构造器注入啊   所以如果找到String类型的Bean 就能注入成功
13 楼 307622798 2012-11-30  
博主,你好!有个小小的问题想请教一下,呵呵!
位置:
二、@Autowired:自动装配
(1)、构造器注入:
在这个段落里  bean的配置是这样的
<bean id="testBean11" class="cn.javass.spring.chapter12.TestBean11"/> 
在TestBean11这个类里面并没有使用无参的构造方法而只是这样的一个构造方法
    @Autowired //构造器注入 
    private TestBean11(String message) { 
        this.message = message; 
    }
我记得网上有人解释@autowired是这样解释的,@autowired是bytype来进行注入的,spring首先获得类型这里我想应该是TestBean11吧,那么spring会去spring容器里面寻找有没有该类型的对象。可是该bean并没有一个无参的构造方法,也就无法实例化对象啊,那应该就找不到这样的对象啊,为什么这里却能成功呢?望博主指教,谢谢
12 楼 jinnianshilongnian 2012-11-30  
307622798 写道
博主,你好,请问@Required是不是表示在xml配置文件中只能通过<property>来注入不能通过<constructor-arg>来注入啊?还有如果有@Required就不能使用无参构造器来实例化bean啊?呵呵,望博主指教!

@Required只是表示必须的,@Autowire用于注入 可以完成构造器注入的
11 楼 307622798 2012-11-30  
博主,你好,请问@Required是不是表示在xml配置文件中只能通过<property>来注入不能通过<constructor-arg>来注入啊?还有如果有@Required就不能使用无参构造器来实例化bean啊?呵呵,望博主指教!
10 楼 jinnianshilongnian 2012-11-26  
zuishengmengsi1990 写道
LZ,提醒下有个小错误,DependencyInjectWithAnnotationTest 类中的 private static ApplicationContext ctx = new ClassPathXmlApplicationContext("configLocation");  双引号多了。。

谢谢啊
9 楼 zuishengmengsi1990 2012-11-26  
LZ,提醒下有个小错误,DependencyInjectWithAnnotationTest 类中的 private static ApplicationContext ctx = new ClassPathXmlApplicationContext("configLocation");  双引号多了。。
8 楼 jinnianshilongnian 2012-09-28  
chenxun101 写道
请问楼主 Dao类前加 @Repository   但是当前Dao有父类,应该如何配置??
比如
<bean id="baseiBatisDAO" abstract="true" ***></bean>
<bean id="applicationDao" class="*.dao.ApplicationDao" parent="baseiBatisDAO" />
现改成
<bean id="baseiBatisDAO" abstract="true" ***></bean>
@Repository("applicationDao") 这个parent该怎么写?
谢谢



xml方式是继承配置可以用你说的

而注解方式不用 继承子类后(自动会扫描子类中的如@Autowired注解 进行注入)
7 楼 chenxun101 2012-09-28  
请问楼主 Dao类前加 @Repository   但是当前Dao有父类,应该如何配置??
比如
<bean id="baseiBatisDAO" abstract="true" ***></bean>
<bean id="applicationDao" class="*.dao.ApplicationDao" parent="baseiBatisDAO" />
现改成
<bean id="baseiBatisDAO" abstract="true" ***></bean>
@Repository("applicationDao") 这个parent该怎么写?
谢谢

6 楼 一日一博 2012-09-06  
JSR-250注解
一、@Resource:自动装配,默认根据类型装配,如果指定name属性将根据名字装配,可以使用如下方式来指定:


这一段写错了貌似,@Resource默认是先按名称找,找不到再byType
5 楼 jinnianshilongnian 2012-03-20  
chjavach 写道
很好很强大

 
4 楼 jinnianshilongnian 2012-03-20  
vvv_110 写道

 
3 楼 chjavach 2012-03-19  
很好很强大
2 楼 liuyaxuan1234 2012-03-19  
讲的通俗易懂,多谢楼主分享自己的经验
1 楼 vvv_110 2012-03-19  

相关推荐

    spring3零配置注解实现Bean定义

    标题《spring3零配置注解实现Bean定义》中蕴含的知识点主要包括Spring框架中的Bean定义配置方法的演进,特别是从Spring 2.5到Spring 3版本的过渡过程中,对于注解方式实现Bean定义的支持如何被引入和优化。...

    跟我学spring

    12.1节概述零配置,12.2节和12.3节分别介绍注解实现Bean依赖注入和注解实现Bean定义。 在学习Spring的过程中,读者会从基础到高级,逐步掌握Spring框架的各个方面,最终能够熟练地应用Spring进行企业级应用的开发。...

    跟我学spring3(8-13)

    【第十二章】零配置: 1. **12.1 概述**:Spring 3引入了更多的注解支持,使得可以实现零XML配置,提高开发效率。 2. **12.2 注解实现Bean依赖注入**:通过@Component、@Autowired等注解,可以省去XML配置文件,直接...

    跟我学spring3(8-13).pdf

    《跟我学Spring3》这本书详细...《跟我学Spring3》全面讲解了Spring如何与ORM框架、Web框架集成,以及如何实现事务管理和零配置开发。通过案例实践,读者可以深入理解Spring在实际项目中的应用,提升Java EE开发技能。

    跟我学spring3(8-13)1

    5. **第十二章:零配置** - **12.1 概述**:介绍了Spring 2.5引入的基于注解的配置,减少了XML配置的复杂性。 - **12.2 注解实现Bean依赖注入**:解释了如何使用@Component、@Service、@Repository和@Controller...

    跟我学spring3(8-13)

    《跟我学Spring3》是一本全面介绍Spring框架的教程,主要涵盖了Spring对ORM支持、事务管理以及与其他Web框架的集成等内容。以下是对其中关键知识点的详细解析: 1. **Spring对ORM的支持**: - **8.1 概述**:这...

    跟我学spring3,很不错的spring学习资料

    #### 12.2 注解实现 Bean 依赖注入 - **依赖注入**:Spring 通过依赖注入机制实现了组件之间的解耦。通过注解(如 @Autowired、@Resource 等)可以简化依赖的声明和注入过程。 #### 12.3 注解实现 Bean 定义 - **...

    spring3 学习

    《跟我学Spring3》是一本全面介绍Spring框架的教程,主要涵盖了Spring对ORM支持、事务管理、Web框架集成以及SSH集成开发等多个方面。Spring作为Java领域最流行的应用框架之一,其强大的功能和灵活性使得它在企业级...

    Spring3(8-13)

    《跟我学Spring3》是一本详细讲解Spring 3.0框架的教程,涵盖了Spring对ORM支持、事务管理、Web框架集成以及SSH集成等多个方面。以下是其中一些核心知识点的详细解析: 1. **Spring对ORM的支持**: - **8.1 概述**...

    Spring.3.x企业应用开发实战(完整版).part2

    Spring3.0是Spring在积蓄了3年之久后,隆重推出的一个重大升级版本,进一步加强了Spring作为Java领域第一开源平台的翘楚地位。  Spring3.0引入了众多Java开发者翘首以盼的新功能和新特性,如OXM、校验及格式化框架...

    Spring3.x企业应用开发实战(完整版) part1

    Spring3.0是Spring在积蓄了3年之久后,隆重推出的一个重大升级版本,进一步加强了Spring作为Java领域第一开源平台的翘楚地位。  Spring3.0引入了众多Java开发者翘首以盼的新功能和新特性,如OXM、校验及格式化框架...

    JavaEE开发的颠覆者SpringBoot实战[完整版].part3

    第12 章 分布式系统开发 456 12.1 微服务、原生云应用 456 12.2 Spring Cloud 快速入门 457 12.2.1 配置服务 457 12.2.2 服务发现 457 12.2.3 路由网关 457 12.2.4 负载均衡 457 12.2.5 断路器 458 12.3 实战 458 ...

    Spring in Action(第二版 中文高清版).part2

    第12章 访问企业服务 12.1 从JNDI中获取对象 12.1.1 使用传统的JNDI 12.1.2 注入JNDI对象 12.1.3 在Spring 2中注入JNDI对象 12.2 发送电子邮件 12.2.1 配置邮件发送器 12.2.2 构建电子邮件 12.3 调度任务 ...

    JavaEE开发的颠覆者SpringBoot实战[完整版].part2

    第12 章 分布式系统开发 456 12.1 微服务、原生云应用 456 12.2 Spring Cloud 快速入门 457 12.2.1 配置服务 457 12.2.2 服务发现 457 12.2.3 路由网关 457 12.2.4 负载均衡 457 12.2.5 断路器 458 12.3 实战 458 ...

    Spring in Action(第2版)中文版

    第12章访问企业服务 12.1从jndi中获取对象 12.1.1使用传统的jndi 12.1.2注入jndi对象 12.1.3在spring2中注入jndi对象 12.2发送电子邮件 12.2.1配置邮件发送器 12.2.2构建电子邮件 12.3调度任务 12.3.1使用...

    SpingBoot整合oracle的ojdbc8-12.2.0.1.jar

    3. **使用JdbcTemplate或JPA**:Spring Boot提供了两种主要的方式来操作数据库,一是传统的JdbcTemplate,二是基于ORM(对象关系映射)的JPA。JdbcTemplate允许直接编写SQL语句,而JPA则支持更高级别的CRUD操作和...

    Spring in Action(第二版 中文高清版).part1

    第12章 访问企业服务 12.1 从JNDI中获取对象 12.1.1 使用传统的JNDI 12.1.2 注入JNDI对象 12.1.3 在Spring 2中注入JNDI对象 12.2 发送电子邮件 12.2.1 配置邮件发送器 12.2.2 构建电子邮件 12.3 调度任务 ...

    2018年秋八年级数学上册第十二章全等三角形12.2三角形全等的判定12.2.3利用两角一边判定三角形全等ASAAAS课时作业新

    2018年秋八年级数学上册第十二章全等三角形12.2三角形全等的判定12.2.3利用两角一边判定三角形全等ASAAAS课时作业新版新人教版2018082314

    2020秋八年级数学上册第12章一次函数12.2一次函数第3课时用待定系数法求一次函数的解析式学案无答案新版沪科版

    2020秋八年级数学上册第12章一次函数12.2一次函数第3课时用待定系数法求一次函数的解析式学案无答案新版沪科版

Global site tag (gtag.js) - Google Analytics