那些年我们一起着迷的Spring:bean的注解实现(六)

spring–bean的定义及作用域的注解实现

1.Classpath扫描和组件管理

3.0以后,通过java的注解而不是xml来定义bean,如:
@configuration @Bean @Import @DependsOn

  • @Component是一个通用注解,可用于任何bean
  • @Respority通常注解DAO类,既持久层
  • @Service通常用于注解Service类,既服务层
  • @Controller通常用于Controller类,既控制层(mvc)

2.元注解

1.许多Spring提供的注解可以作为自己的代码,即”元数据注解”,元注解是一个简单的注解,可以应用到另一个注解
2.除了value(),元注解还可以有其它属性,允许订制

四个元注解分别是:@Target,@Retention,@Documented,@Inherited ,是专门用来定义注解的注解,其作用分别如下:
@Target 表示该注解用于什么地方,可能的值在枚举类 ElemenetType 中,包括:

ElemenetType 说明
ElemenetType.CONSTRUCTOR 构造器声明
ElemenetType.FIELD 域声明(包括 enum 实例)
ElemenetType.LOCAL_VARIABLE 局部变量声明
ElemenetType.METHOD 方法声明
ElemenetType.PACKAGE 包声明
ElemenetType.PARAMETER 参数声明
ElemenetType.TYPE 类,接口(包括注解类型)或enum声明

@Retention 表示在什么级别保存该注解信息。
可选的参数值在枚举类型 RetentionPolicy 中,包括:

RetentionPolicy 说明
RetentionPolicy.SOURCE 注解将被编译器丢弃
RetentionPolicy.CLASS 注解在class文件中可用,但会被VM丢弃
RetentionPolicy.RUNTIME VM 将在运行期也保留注释,因此可以通过反射机制读取注解的信息。

@Documented 将此注解包含在 javadoc 中 ,它代表着此注解会被javadoc工具提取成文档。
在doc文档中的内容会因为此注解的信息内容不同而不同。相当与@see,@param 等。
@Inherited 允许子类继承父类中的注解。

3.类的自动检测及bean注册

spring可以自动检测类并注册bean到ApplicationContext中
类加@Service@Controller等注解

<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>可以实现基于类的注解,
而<context:annotation-config>只能在完成了bean的注册配置之后实现对成员变量和方法的注解,
前者包含后者,一般配置了前者之后就不再配置后者了。
AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor也会被包含 -->
	<context:component-scan base-package:"org.example"/>
<beans>

4.使用过滤器进行自定义扫描

默认情况下,类被自动发现并注册bean的条件是:使用@component @repository @service @controller或者使用@Component的自定义注解

可以通过过滤器修改上面的行为,如下xml配置,忽略所有的@resporitory注解(context:exclude-filter)并用stub代替

<beans>
	<context:component-scan base-package:"org.example">
	<!--包含过滤器 -->
	<context:include-filter type="regex"--通配符
	expression=".Stub.*Respository"/>
	<!--排除过滤器 -->
	<context:exclude-filter type="annotation"
	expression="org.springframework.stereotype.Respository"/>
	</context:component-scan>
<beans>

还可以使用user-default-filter:false禁用自动发现和注册

5.定义bean

定义bean

6.作用域(scope)

作用域(scope)

7.spring 代理方式

scoped-proxy 属性指定代理,有三个值可选:no(默认) interface ,target-class

<beans>
	<context:component-scan base-package:"org.example"  scoped-proxy="interface">
</beans>

1.Required

@Required注解适用于bean属性的setter方法
这个注解仅仅表示,受影响的bean属性**必须在配置时被填充(赋值),**通过在bean定义或通过自动装配一个明确的属性值

public class SimpleMovieLister{
    
    
	private MovieFinder  movieFinder;	
	@Required
	public void setMovieFinder(MovieFinder movieFinder){
    
    
		this.movieFinder=movieFinder;
	}
}

2.AutoWired

可以将@AutoWired注解为”传统”的setter方法

private MovieFinder  movieFinder;	
@AutoWired
public void setMovieFinder(MovieFinder movieFinder){
    
    
		this.movieFinder=movieFinder;
	}

也可以用在构造器或成员变量上

@AutoWired
private MovieFinder  movieFinder;	

private Customer**Dao  customer**Dao;
@AutoWired
public  ***(Customer**Dao  customer**Dao){
    
    
		this.customer**Dao=customer**Dao;
	}

默认情况下,如果因为找不到合适的bean将会导致autowiring失败抛出异常,可以通过在注解上设置required属性为false

@AutoWired(required=false)
public void setXX(XX xx){
    
    
    this.xx = xx
}

每个类只能有一个构造器被标记为required=true{每个类下可以有多个构造器}
AutoWired的必要属性,建议使用@Required注解(上面情况下用Required代替AutoWired。一般使用AutoWired)

3.@AutoWired和@Resource注解的区别

  • Spring不但支持自己定义的@Autowired注解,还支持几个由JSR-250规范定义的注解,它们分别是@Resource、@PostConstruct以及@PreDestroy。
  • @Resource的作用相当于@Autowired,只不过@Autowired按byType(即class)自动注入,而@Resource默认按byName(即ID)自动注入罢了。
  • @Resource有两个属性是比较重要的,分是name和type,Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。

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

@Resource装配顺序

如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配;

@Autowired 与@Resource的区别:

  1. @Autowired与@Resource都可以用来装配bean. 都可以写在字段上,或写在setter方法上
  2. @Autowired默认按类型装配(这个注解是属于spring的),默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,如:@Autowired(required=false),如果我们想使用名称装配可以结合@Qualifier注解进行使用
  3. @Resource(这个注解属于J2EE的),默认按照名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
  4. 使用范围的区别
    @AutoWired适用于fields,constructors,multi-argument, methods这些允许在参数级别使用@Qualifier注解缩小范围的情况
    @Resource适用于成员变量,只有一个参数的setter方法,所以在目标是构造器或一个多参数方法时,最好的方式是使用qualifiers

推荐使用:@Resource注解在字段上,这样就不用写setter方法了,并且这个注解是属于J2EE的,减少了与spring的耦合。这样代码看起就比较优雅。

4.其他用途

可以使用@Autowired注解那些众所周知的解析依赖性接口,比如:BeanFactory,ApplicationContext,Environment,ResourceLoader,ApplicationEventPublisher,MessageSource;

这里写图片描述
但是Order只对数组有效,对map集合无效

BeanOneImpl 和 BeanTwoImpl都 implements BeanInterface

 @Autowired
 private List<BeanInterface> list;
//遍历list
 for (BeanInterface bean : list) {
    
    
     System.out.println(bean.getClass().getName());
}
//输出
com.zjx.multibean.BeanTwoImpl
com.zjx.multibean.BeanOneImpl

@Autowired
private Map<String, BeanInterface> map;
//遍历map
 for (Map.Entry<String, BeanInterface> entry : map.entrySet()) {
    
    
       System.out.println(entry.getKey() + "   "
                  + entry.getValue().getClass().getName());
	}
//输出
beanOneImpl   com.zjx.multibean.BeanOneImpl
beanTwoImpl   com.zjx.multibean.BeanTwoImpl

5.注意

@Autowired是由Spring BeanPostProcessor处理的,所以不能在自己的BeanPostProcessor或BeanFactoryPostProcessor类型应用这些注解,这些类型必须通过XML或者Spring的@Bean注解加载

@Qualifier

类型自动装配可能会有多个bean实例的情况,可以使用Spring的 @Qualifier注解缩小范围(或指定唯一),也可以用于指定单独的构造器参数或方法参数

// 在BeanInvoker类中增加一个成员变量,因为我们不知道BeanInterface的实现类是哪一个
 //(beanOneImpl、beanTwoImpl),通过@Qualifier注解缩小范围为id为”beanTwoImpl”的这个实现类
	@Autowired
    @Qualifier("beanTwoImpl")
    private BeanInterface beanInterface;

@Autowired
private void setComedyCatalog(@Qualifier("对应id") MovieCatalog comedyCatalog){
    
    
    this.comedyCatalog = comedyCatalog;
}

可以用于注解集合类型变量

如果通过名字进行注解注入,主要是使用的不是@Autowired(即使在技术上能够通过@Qualifier指定bean的名字),替代方式是使用JSR-250@Resource注解,通过其独特的名称来识别特定的目标(这是一个与所声明的类型是无关的匹配过程)

使用@Resource注解,通过唯一名称引用集合或Map的bean

spring用@Autowired注入map出现的问题
当我们用Autowired注入一个map或者其他集合类型时,spring不是根据beanName取bean然后赋值,而是根据设置的type从容器中一次性取出所有符合的bean直接放入到集合中。
【Spring】@Autowired 注入类的集合类型深度解剖

猜你喜欢

转载自blog.csdn.net/eluanshi12/article/details/86477908