springNote3 - juedaiyuer/researchNote GitHub Wiki
#spring笔记[三]---基于注解的Bean装配#
##ClassPath扫描与组件管理##
从Spring3.0开始,Spring JavaConfig项目提供了很多特性,包括使用java而不是XML定义bean
@Component 是一个通用注解,可用于任何bean
@Repository 通常用于注解DAO类,即持久层
@Service 注解Service类,即服务层
@Controller 控制层,MVC
@Configuration
@Bean
@Import
@DependsOn
##类的自动检测及Bean的注册##
spring可以自动检测类并注册Bean到ApplicationContext
<context:component-scan>
<context:annotation-config/>
使用过滤器进行自定义扫描
默认情况下,类被自动发现并注册bean的条件是:使用@component,@Repository,@Controller注解或者使用@Component的自定义注解
可以通过过滤器修改上面的行为
use-default-filters="false" 禁用自动发现与注册
using filters to customize scanning
##定义Bean##
扫描过程中组件被自动检测,那么Bean名称是由BeanNameGenerator生成的
@Component
@Repository
@Service
@Controller
上面的注解都会有name属性用于显式设置Bean Name,相当于XML定义的id
@Service("myMovieListener")
public class SimpleMovieListener
{
//TODO
}
可自定义bean命名策略,实现BeanNameGenerator接口,并一定要包含一个无参数构造
<beans>
<context:component-scan base-package="org.example"
name-generator="org.example.MyNameGenerator"/>
</beans>
##作用域##
通常情况下自动查找的Spring组件,其scope是singleton,Spring2.5提供了一个标识scope的注解@Scope
@Scope("prototype")
也可以自定义scope策略,实现ScopeMetadataResolver接口并提供一个无参构造器
<beans>
<context:component-scan base-package="org.example"
scope-resolver="org.example.MyScopeResolver" />
</beans>
##代理方式##
可以使用scoped-proxy属性指定代理,有三个值可选:no,interfaces,targetClass
<beans>
<context:component-scan base-package="org.example"
scoped-proxy="interfaces"/>
</beans>
##代码示例##
package juedaiyuer.annotation;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
//@Component("bean")
@Scope
@Component
public class BeanAnnotation {
public void say(String arg) {
System.out.println("BeanAnnotation : " + arg);
}
public void myHashCode() {
System.out.println("BeanAnnotation : " + this.hashCode());
}
}
<?xml version="1.0" encoding="UTF-8"?>
<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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd" >
<context:component-scan base-package="juedaiyuer.annotation"></context:component-scan>
</beans>
package test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.BlockJUnit4ClassRunner;
import juedaiyuer.annotation.BeanAnnotation;
@RunWith(BlockJUnit4ClassRunner.class)
public class TestBeanAnnotation extends UnitTestBase {
public TestBeanAnnotation() {
super("classpath*:spring-beanannotation.xml");
}
@Test
public void testSay() {
BeanAnnotation bean = super.getBean("beanAnnotation");
bean.say("This is test.");
bean = super.getBean("bean");
bean.say("This is test.");
}
@Test
public void testScpoe() {
BeanAnnotation bean = super.getBean("beanAnnotation");
bean.myHashCode();
bean = super.getBean("beanAnnotation");
bean.myHashCode();
}
}
##Required注解##
适用于bean属性的setter方法
这个注解仅仅表示,受影响的bean属性必须在配置时被填充,通过在bean定义或者通过自动装配一个明确的属性值
实际开发中,并不常用
public class SimpleMovieListener{
private MovieFinder movieFinder;
@Required
public void setMovieFinder(MovieFinder movieFinder)
{
this.movieFinder = movieFinder;
}
//...
}
##Autowired注解##
public class SimpleMovieListener{
private MovieFinder movieFinder;
@Autowired
public void setMovieFinder(MovieFinder movieFinder)
{
this.movieFinder = movieFinder;
}
//...
}
可以注解到传统的setter方法
可用于构造器或成员变量
默认情况下,如果因找不到合适的bean将会导致autowiring失败抛出异常,可以通过下面的方式避免
public class SimpleMovieListener{
private MovieFinder movieFinder;
@Autowired(required=false)
public void setMovieFinder(MovieFinder movieFinder)
{
this.movieFinder = movieFinder;
}
//...
}
每一个类只能有一个构造器被标记为required=ture
@autowired的必要属性,建议使用@Required注解
##代码示例##
xml配置文件只需要配置需要扫描的包即可
<?xml version="1.0" encoding="UTF-8"?>
<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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd" >
<context:component-scan base-package="juedaiyuer.annotation"></context:component-scan>
</beans>
DAO的一个接口
package juedaiyuer.annotation.injection.dao;
public interface InjectionDAO {
public void save(String arg);
}
DAO接口实现类
package juedaiyuer.annotation.injection.dao;
import org.springframework.stereotype.Repository;
@Repository
public class InjectionDAOImpl implements InjectionDAO {
public void save(String arg) {
//模拟数据库保存操作
System.out.println("保存数据:" + arg);
}
}
Service的一个接口
package juedaiyuer.annotation.injection.service;
public interface InjectionService {
public void save(String arg);
}
Service接口实现类
package juedaiyuer.annotation.injection.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import juedaiyuer.annotation.injection.dao.InjectionDAO;
@Service
public class InjectionServiceImpl implements InjectionService {
// @Autowired
private InjectionDAO injectionDAO;
@Autowired
public InjectionServiceImpl(InjectionDAO injectionDAO) {
this.injectionDAO = injectionDAO;
}
// @Autowired
public void setInjectionDAO(InjectionDAO injectionDAO) {
this.injectionDAO = injectionDAO;
}
public void save(String arg) {
//模拟业务操作
System.out.println("Service接收参数:" + arg);
arg = arg + ":" + this.hashCode();
injectionDAO.save(arg);
}
}
单元测试子类
package test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.BlockJUnit4ClassRunner;
import juedaiyuer.annotation.injection.service.InjectionService;
@RunWith(BlockJUnit4ClassRunner.class)
public class TestInjection extends UnitTestBase {
public TestInjection() {
super("classpath:spring-beanannotation.xml");
}
@Test
public void testAutowired() {
InjectionService service = super.getBean("injectionServiceImpl");
service.save("This is autowired.");
}
// @Test
// public void testMultiBean() {
// BeanInvoker invoker = super.getBean("beanInvoker");
// invoker.say();
// }
}
##Autowired注解##
- 解析依赖性接口(beanfactory,applicationContext,environment,resourceloader,applicationEventPublisher,messagesource...)
- 可以用于装配key为string的Map
- 如果希望数组有序,可以让bean实现org.springframework.core.Ordered接口或使用@Order注解
- Spring BeanPostProcessor处理,不能在自己的BeanPostProcessor或BeanfactoryBeanPostProcessor类型应用该注解,这些类型必须通过XML或Spring的@Bean注解
- order注解只对数组有效
###数组及map的自动注入###
package juedaiyuer.annotation.multibean;
public interface BeanInterface {
}
package juedaiyuer.annotation.multibean;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
//@Order(2)
@Component
public class BeanImplOne implements BeanInterface {
}
package juedaiyuer.annotation.multibean;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
//@Order(1)
@Component
public class BeanImplTwo implements BeanInterface {
}
package juedaiyuer.annotation.multibean;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component
public class BeanInvoker {
@Autowired
private List<BeanInterface> list;
@Autowired
private Map<String, BeanInterface> map;
@Autowired
@Qualifier("beanImplTwo")
private BeanInterface beanInterface;
public void say() {
if (null != list && 0 != list.size()) {
System.out.println("list...");
for (BeanInterface bean : list) {
System.out.println(bean.getClass().getName());
}
} else {
System.out.println("List<BeanInterface> list is null !!!!!!!!!!");
}
System.out.println();
if (null != map && 0 != map.size()) {
System.out.println("map...");
for (Map.Entry<String, BeanInterface> entry : map.entrySet()) {
System.out.println(entry.getKey() + " " + entry.getValue().getClass().getName());
}
} else {
System.out.println("Map<String, BeanInterface> map is null !!!!!!!!!!");
}
System.out.println();
if (null != beanInterface) {
System.out.println(beanInterface.getClass().getName());
} else {
System.out.println("beanInterface is null...");
}
}
}
package test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.BlockJUnit4ClassRunner;
import juedaiyuer.annotation.injection.service.InjectionService;
import juedaiyuer.annotation.multibean.BeanInvoker;
@RunWith(BlockJUnit4ClassRunner.class)
public class TestInjection extends UnitTestBase {
public TestInjection() {
super("classpath:spring-beanannotation.xml");
}
@Test
public void testMultiBean() {
BeanInvoker invoker = super.getBean("beanInvoker");
invoker.say();
}
}
##Qualifier注解##
按照类型自动装配可能多个bean实例的情况,可以使用spring的qualifier注解缩小范围(或指定唯一),也可以用于制定单独的构造器参数或方法参数
可用于注解集合类型变量
如果通过名字进行注解注入,主要使用的不是@autowired(即使在技术上能够通过@qualifier指定bean的名字),替代方法是使用JSR-250的@Resource注解,它通过其独特的名称来定义识别特定的目标.
因语义差异,集合或Map类型的bean无法通过@autowired来注入,因为没有类型匹配这样的bean,@resource注解通过唯一名称引用集合或map的bean
适用于fields,constructors,multi-argument mehods这些允许在参数级别使用qualifier注解缩小范围
@resource适用于成员变量,只有一个参数的setter方法,所以在目标是构造器或一个多参数方法时,最好的方式是使用qualifiers