Spring--注解配置详解

Spring注解配置

从 Spring 2.5 开始就可以使用注解来配置依赖注入。使用注解的方式使我们无需在XML中配置一个Bean引用,更加简单和方便。
首先要引入context名称空间:

xmlns:context="http://www.springframework.org/schema/context" 

声明context命名空间后,即可通过context命名空间的component-scanbase-package属性指定一个需要扫描的基类包,Spring容器将会扫描这个基类包里的所有类,并从类的注解信息中获取Bean的定义信息。若希望仅扫描特定的类而非基包下所有的类,那么可以使用resource-pattern属性过滤出特定的类 。< context:include-filter > 表示要包含的目标类,而 < context:exclude-filter > 表示要抛出在外的目标类。一个< context:component-scan >下可以拥有若干个< context:exclude-filter >和< context:include-filter >元素,这两个元素均支持多种类型的过滤表达式。

applicationContext.xml配置如下:




    
    


创建一个User类:

package pers.zhang.bean;

public class User {

    private String name;
    private Integer age;
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public void init(){
        System.out.println("我是初始化方法!");
    }
    public void destory(){
        System.out.println("我是销毁方法!");
    }
    @Override
    public String toString() {
        return "User [name=" + name + ", age=" + age + ", car=" + car + "]";
    }
    
}

@Component

@Component 作用在类上,相当于 xml 中的 < bean id="..." name="..." class="..." / >。@Component(str) 可以填写一个参数,相当于 name 属性。
同时,Spring 中还提供了@Component 的三个衍生注解:

  • @Controller: 用于Controller层
  • @Service: 用于业务层
  • @Repository: 用于持久层

这三个注解是为了让注解本身的用途更加清晰,功能上目前来讲是一致的。

@Scope

@Scope 作用于类上,用于指定Bean的作用范围,取值有如下几个:

  • singleton(默认): Spring IOC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id(name)与该bean定义相匹配,则只会返回bean的同一实例,一个容器对应一个bean。
  • prototype: 表示多例,每一次请求(将其注入到另一个bean中,或者以程序的方式调用容器的 getBean()方法)都会产生一个新的bean实例,相当与一个new的操作。
  • request: 表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效。
  • session: 表示作用域表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP session内有效。
  • global session: 作用域类似于标准的HTTP Session作用域,不过它仅仅在基于portlet的web应用中才有意义。Portlet规范定义了全局Session的概念,它被所有构成某个 portlet web应用的各种不同的portlet所共享。在global session作用域中定义的bean被限定于全局portlet Session的生命周期范围内。如果你在web中使用global session作用域来标识bean,那么web会自动当成session类型来使用。

@PostConstruct 和 @PreDestroy

@PostConstruct 用于在依赖关系注入完成之后需要执行的方法上,以执行任何初始化。相当于 init-method
@PreDestroy 用于在对象销毁之前需要执行的方法上,以执行释放资源等操作。相当于 destroy-method

package pers.zhang.bean;

@Repository("user")
@Scope(scopeName="singleton")
public class User {

    private String name;
    private Integer age;
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    @PostConstruct
    public void init(){
        System.out.println("我是初始化方法!");
    }
    @PreDestroy
    public void destory(){
        System.out.println("我是销毁方法!");
    }
    @Override
    public String toString() {
        return "User [name=" + name + ", age=" + age + ", car=" + car + "]";
    }
    
}

测试方法:

package pers.zhang.test;

import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import pers.zhang.bean.User;

public class Demo {
    @Test
    public void fun1(){
        
        //1 创建容器对象
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2 向容器"要"user对象
        User u1 = (User) ac.getBean("user");
        User u2 = (User) ac.getBean("user");
        
        System.out.println(u1==u2);
        //3 打印user对象
        System.out.println(u1);
        
        ac.close();
            
    }
    
}

运行JUnit测试输出:

我是初始化方法!
true
User [name=null, age=null, car=null]
我是销毁方法!

@Value

@Value 一般作用在属性上或 set 方法上,用于值的注入。@Value的作用位置不同,其实现原理也不同:

  • 作用在属性上: 使用反射技术,操作Field对字段直接赋值,但是破坏了对象的封装性。
  • 作用在set方法上: 使用set方法赋值,但是不够直观,不够一目了然。
package pers.zhang.bean;

@Repository("user")
@Scope(scopeName="singleton")
public class User {

    private String name;
    @Value("18")
    private Integer age;
    
    public String getName() {
        return name;
    }
    @Value("tom")   
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    @PostConstruct
    public void init(){
        System.out.println("我是初始化方法!");
    }
    @PreDestroy
    public void destory(){
        System.out.println("我是销毁方法!");
    }
    @Override
    public String toString() {
        return "User [name=" + name + ", age=" + age + ", car=" + car + "]";
    }
    
}

测试方法:

package pers.zhang.test;

import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import pers.zhang.bean.User;

public class Demo {
    @Test
    public void fun1(){
        
        //1 创建容器对象
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2 向容器"要"user对象
        User u1 = (User) ac.getBean("user");
        User u2 = (User) ac.getBean("user");
        
        System.out.println(u1==u2);
        //3 打印user对象
        System.out.println(u1);
        
        ac.close();
            
    }
    
}

运行JUnit测试输出:

我是初始化方法!
true
User [name=tom, age=18, car=null]
我是销毁方法!

@Autowired 和 @Qualifier

@Autowired ,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。 通过 @Autowired的使用来消除 set ,get方法。
但需要注意的是,@Autowired是通过类型来进行匹配的。如果Spring容器中有多个同类型的对象,使用@Autowired装配得到的结果将不确定。
这时就需要使用 @Qualifier,限定描述符能根据名字进行注入,更能进行更细粒度的控制如何选择注入对象。

创建一个Car类,并使用注解配置一个实例:

package pers.zhang.bean;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Repository("car1")
public class Car {
    @Value("car1:二手捷达")
    private String  name;
    @Value("呕吐绿")
    private String color;
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getColor() {
        return color;
    }
    public void setColor(String color) {
        this.color = color;
    }
    @Override
    public String toString() {
        return "Car [name=" + name + ", color=" + color + "]";
    }
    
}

在applicationContext.xml中再配置一个Car的实例:




    
    

    
        
        
    

修改User类如下:

package pers.zhang.bean;

@Repository("user")
@Scope(scopeName="singleton")
public class User {
    @Value("tom")   
    private String name;
    @Value("18")
    private Integer age;

    @Autowired //自动装配,问题:如果匹配多个类型一致的对象.将无法选择具体注入哪一个对象.
    @Qualifier("car2")//使用@Qualifier注解告诉spring容器自动装配哪个名称的对象
    private Car car;
    
    public Car getCar() {
        return car;
    }
    public void setCar(Car car) {
        this.car = car;
    }
    public String getName() {
        return name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    @PostConstruct
    public void init(){
        System.out.println("我是初始化方法!");
    }
    @PreDestroy
    public void destory(){
        System.out.println("我是销毁方法!");
    }
    @Override
    public String toString() {
        return "User [name=" + name + ", age=" + age + ", car=" + car + "]";
    }
    
}

测试方法:

package pers.zhang.test;

import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import pers.zhang.bean.User;

public class Demo {
    @Test
    public void fun1(){
        
        //1 创建容器对象
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2 向容器"要"user对象
        User u1 = (User) ac.getBean("user");
        User u2 = (User) ac.getBean("user");
        
        System.out.println(u1==u2);
        //3 打印user对象
        System.out.println(u1);
        
        ac.close();
            
    }
    
}

运行JUnit测试输出:

我是初始化方法!
true
User [name=tom, age=18, car=Car [name=car2:9手夏利, color=屎黄色]]
我是销毁方法!

@Resource

@Resource,手动注入,默认是按照byName自动注入。
@Resource有两个重要的属性,name和type:

  • name: name属性解析为bean的名字.
  • type: type属性解析为bean的类型。

如果使用name属性,则使用byName的自动注入策略;而使用type属性则使用byType自动注入策略;如果既不指定name也不指定type属性,这时通过反射机制使用byName自动注入策略。

@Resource装配的顺序:

  • 如果同时指定了name和type属性,则从spring上下问中找到唯一匹配的bean进行装配,如果没有找到,则会抛出异常。
  • 如果指定了name属性,则从spring上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常。
  • 如果指定type属性,则从spring上下文中找到类型匹配的唯一bean进行装配,找不到或者是找到多个,则抛出异常。
  • 如果既没有指定name属性,也没有指定type属性,则默认是按照byName的方式进行装配;如果没有匹配,则返回一个原始的类型进行装配,如果匹配则自动装配。
package pers.zhang.bean;

@Repository("user")
@Scope(scopeName="singleton")
public class User {
    @Value("tom")   
    private String name;
    @Value("18")
    private Integer age;
    
    @Resource(name="car1")//手动注入
    private Car car;
    
    public Car getCar() {
        return car;
    }
    public void setCar(Car car) {
        this.car = car;
    }
    public String getName() {
        return name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    @PostConstruct
    public void init(){
        System.out.println("我是初始化方法!");
    }
    @PreDestroy
    public void destory(){
        System.out.println("我是销毁方法!");
    }
    @Override
    public String toString() {
        return "User [name=" + name + ", age=" + age + ", car=" + car + "]";
    }
    
}

测试方法:

package pers.zhang.test;

import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import pers.zhang.bean.User;

public class Demo {
    @Test
    public void fun1(){
        
        //1 创建容器对象
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2 向容器"要"user对象
        User u1 = (User) ac.getBean("user");
        User u2 = (User) ac.getBean("user");
        
        System.out.println(u1==u2);
        //3 打印user对象
        System.out.println(u1);
        
        ac.close();
            
    }
    
}

运行JUnit测试输出:

我是初始化方法!
true
User [name=tom, age=18, car=Car [name=car1:2手捷达, color=呕吐绿]]
我是销毁方法!

你可能感兴趣的:(Spring--注解配置详解)