Spring--注解配置(@Component,@Scope,@PostConstruct,@PreDestroy,@Value,@Autowired,@Qualifier,@Resource)

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配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
		xmlns="http://www.springframework.org/schema/beans" 
		xmlns:context="http://www.springframework.org/schema/context" 
		xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd ">

	<!-- 指定扫描pers.zhang.bean报下的所有类中的注解.
		 注意:扫描包时.会扫描指定报下的所有子孙包
 	-->
	<context:component-scan base-package="pers.zhang.bean"></context:component-scan>

</beans>

创建一个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的实例:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
		xmlns="http://www.springframework.org/schema/beans" 
		xmlns:context="http://www.springframework.org/schema/context" 
		xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd ">

	<!-- 指定扫描cn.itcast.bean报下的所有类中的注解.
		 注意:扫描包时.会扫描指定报下的所有子孙包
	 -->
	<context:component-scan base-package="pers.zhang.bean"></context:component-scan>

	<bean name="car2" class="pers.zhang.bean.Car"  >
		<property name="name" value="car2:9手夏利" ></property>
		<property name="color" value="屎黄色"  ></property>
	</bean>
</beans>

修改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=呕吐绿]]
我是销毁方法!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值