Spring框架学习笔记-基于注解的配置

1.使用注解定义Bean

我们知道,Spring容器成功启动的三大要件是:Bean定义信息、Bean实现类以及Spring本身。如果要采用基于XML的配置,Bean定义信息和Bean实现类本身是分离的,而采用基于注解的配置方式时,Bean定义信息即通过在Bean的实现类上标注注解实现。
下面是使用注解定义一个DAO(数据访问对象)的Bean:

package com.baobaotao.anno;
import org.springframework.stereotype.Component;
@Component("userDao")
public class UserDao{
}

我们使用@Component注解在UserDao类声明处对类进行标注,它可以被Spring容器识别,
Spring容器自动将POJO(简单Java对象)转换为容器管理的Bean。
它和下面的XML配置是等效的:

<bean id="userDao" class="com.baobaotao.anno.UserDao"/>

除了@Component之外,Spring提供了三个功能基本与@Component等效的注解,它们分别用于对DAO、Service以及Web层的Controller进行注解:
@Repository:用于对DAO实现层进行标注:
@Service:用于对Service实现层进行标注:
@Controller:用于对Controller实现层进行标注:

2.使用注解配置信息启动Spring容器

Spring在2.5之后提供了一个context的命名空间,它提供了通过扫描类包以应用注解定义Bean的形式:
即通过注解配置文件扫描Bean所在的包去启动Spring容器。

<?xml version="1.0" encoding="UTF-8"?>
<!-- 1.声明context的命名空间 -->
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    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.1.xsd 
     http://www.springframework.org/schema/context             
      http://www.springframework.org/schema/context/spring-context-3.1.xsd">
    <!-- 2. 扫描类包以应用注解定义的Bean -->
    <context:component-scan base-package="com.baobaotao.anno" />
</beans>

context命名空间的component-scan的base-package属性指定了一个要扫描的类包,spring容器会扫描这个类包所有的类,并且从类的注解中获取Bean的定义信息。
如果仅仅希望扫描特定的类包,而非基类包的所有的类,那么使用resource-pattern="anno/*.class"这样则会扫描类包下的anno类包下的所有的类。

<context:component-scan base-package="com.baobaotao" resource-pattern="anno/*.class"/>

通过resource-pattern属性仅可按资源名称对基包中的类进行过滤,如果仅使用它,我们会发现很多时候它并不能满足要求,如仅过滤基类包中实现了XXX接口的类或标注了某个特定注解的类。
不过这些需求可以很容易地通过< context:component-scan >的过滤子元素实现:

<context:component-scan base-package="com.baobaotao">
	<context:include-filter type="regex" expression="com\.baobaotao\.anno.*"/>
	<context:exclude-filter type="aspectj" expression="com.baobaotao..*Controller+"/>
</context:component-scan>

< context:include-filter >表示要包含的目标类,< context:include-filter>表示要排除在外的目标类。
一个< context:component-scan >下可以拥有若干个< context:include-filter >或
< context:include-filter>元素。

3.自动装配Bean

3.1 使用@Autowired进行自动注入

Spring通过@Autowired注解实现Bean的依赖注入,来看一个LogonService的例子:

package com.baobaotao.anno;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class LogonService{
	@Autowired
	private LogDao logDao;
	@Autowired
	private UserDao userDao;
}

我们使用@Service将LogonService标注为一个Bean,又通过@Autowired注入LogDao以及UserDao的Bean。
@Autowired默认按类型匹配的方式,在容器查找匹配的Bean,当有且仅有一个匹配的Bean时,Spring将其注入到到@Autowired标注的变量之中。

3.2 使用@Autowired的required属性
如果容器中没有一个和标注变量类型匹配的Bean,Spring容器启动时将报NoSuchBeanDefinitionException的异常。如果希望Spring即使找不到匹配的Bean完成注入时也不要抛出异常,那么可以使用@Autowired(required=false)进行标注:

@Service
public class LogonService{
	@Autowired(required=false)
	private LogDao logDao;
}

默认情况下,@Autowired的required属性的值为true,即要求一定要找到匹配的Bean,否则就会抛出异常。

3.3使用@Qualifier指定注入Bean的名称

如果容器中有一个以上匹配的Bean时,则可以通过@Qualifier注解限定Bean的名称,如下所示:

package com.baobaotao.anno;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@Service
public class LogonService{
	@Autowired
	private LogDao logDao;
	@Autowired
	@Qualifier("userDao")
	private UserDao userDao;
}

这时,假设容器有两个类型为UserDao的Bean,一个名为userDao,另一个名为otherUserDao,则会注入名为userDao的Bean。

3.4 对类方法进行标注

@Autowired可以对类成员变量及方法的入参进行标注,下面我们在类的方法上使用@Autowired注解:

package com.baobaotao.anno;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@Service
public class LogonService{
	private LogDao logDao;
	private UserDao userDao;
	@Autowired
	public void setLogDao(LogDao logDao){
		this.logDao=logDao;
	}
	@Autowired
	@Qualifier("userDao")
	public void setUserDao(UserDao userDao){
		this.userDao=userDao;
	}
}

3.5 对集合类进行标注

如果对类中集合类的变量或方法入参进行@Autowired标注,Spring容器会将容器中类型匹配的所有Bean都自动注入进来:

package com.baobaotao.anno;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@Component
public class MyComponent{
	@Autowired(required=false)
	private List<Plugin> plugins;
	publuc List<Plugin> getPlugins(){
		return plugins;
	}
}

Spring如果发现变量是一个集合类,则它会将容器中匹配集合元素类型的所有Bean都注入进来。在这里,Plugin是一个接口,它拥有两个实现类,分别是OnePlugin以及TwoPlugin,这两个实现类都通过@Component标注为Bean,则Spring会将这两个Bean都注入到plugins中。

3.6 对标准注解的支持

此外,Spring还支持JSR-250中定义的@Resource和JSR-300中定义的@Inject注解,这两个标准注解和@Autowired注解的功能类似,都是对类变量及方法入参提供自动注入的功能。
@Resource要求提供一个Bean名称的属性,如果属性为空,则自动采用标注处的变量名或方法名作为Bean的名称:

package com.baobaotao.anno;
import javax.annotation.Resource;
import org.springframework.stereotype.Component;
@Component
public class Boss{
	private Car car;
	@Resource("car")
	private void setCar(Car car){
		System.out.println("execute in setCar");
		this.car=car;
	}
}

注意:@Autowired默认按照类型注入Bean,@Resource默认按照名称匹配注入Bean,@Inject默认按照类型注入Bean,只不过没有required属性。

4.Bean作用范围及生命进程方法

通过注解配置的Bean和通过< bean >配置的Bean一样,默认的作用范围都是singleton,Spring为注解配置提供了一个@scope的注解,可通过它显示指定Bean的作用范围:

package com.baobaotao.anno;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Scope("prototype")
@Component
public class Car{
}

在使用< bean >进行配置时,我们可以通过init-method以及destory-method属性指定Bean的初始化及容器销毁前执行的办法。Spring从2.5开始支持JSR-250中定义的@PostConstruct以及@PreDestroy注解,在Spring中它们相当于init-method以及destroy-method属性的功能,不过在使用注解时,可以在一个Bean中定义多个@PostConstruct和@PreDestroy方法:

package com.baobaotao.anno;
import javax.annotation.PostConstruct;
import javax.annotation.PreConstruct;

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

@Component
public class Boss{
	private Car car;
	public Boss(){
		System.out.println("construct...");
	}
	@Autowired
	private void setCar(Car car){
		System.out.println("execute in setCar");
		this.car=car;
	}
	@PostConstruct
	private boid init1(){
		System.out.println("execute in init1");
	}
	@PostConstruct
	private boid init2(){
		System.out.println("execute in init2");
	}
	@PreConstruct
	private boid destroy1(){
		System.out.println("execute in destroy1");
	}
	@PreConstruct
	private boid destroy2(){
		System.out.println("execute in destroy2");
	}
}

我们在Boss类中分别定义了两个@PostConstruct和两个@PreConstruct。

package com.baobaotao.anno;
import org.springframework.comtext.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.util.Assert;
public class Test{
	public static void main(String[] args){
		ApplicationContext ctx=new ClassPathXmlApplicationContext("com/baobaotao/anno/beans.xml");
		((ClassPathXmlApplicationContext)ctx).destroy();
	}
}

运行这个测试类:

construct...
execute in setCar...
execute in init1
execute in init2
execute in destroy1
execute in destroy2

说明Spring先调用Boss的构造函数实例化Bean,再执行@Autowired进行自动注入,然后分别执行了标注@PostConstruct的方法,当容器关闭时,再分别执行标注了@PreConstruct的方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值