1.介绍
1.1 目标
通过本系列文章能够熟悉并掌握Spring注解驱动开发。本小结将介绍通过注解给容器中注册组件;通过本小结,将了解如下注解:
- AnnotationConfigApplicationContext
组件添加
- @ComponentScan
- @Bean
- @PostConstruct
- @PreDestroy
- BeanPostProcessor
- @Configuration
- @Component
- @Service
- @Controller
- @Repository
- @Conditional
- @Primary
- @Lazy
@Scope
@Import
- ImportSelector
- FactoryBean
1.2 环境信息
环境信息如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.20.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
2.传统方式使用spring配置文件的方式给容器注入bean
- (1)定义一个Java类,如定义一个Person类
1 | public class Person { |
- (2)在maven工程的resources文件夹下定义XML文件,如定义beans.xml,并在xml文件中引入命名空间,同时定义bean组件,即Person类的Bean。
1 | <?xml version="1.0" encoding="UTF-8"?> |
- (3)通过ApplicationContext 获取bean,并打印,代码如下:
1 |
|
3.注解式开发-通过配置类方式给容器注入bean
- (1)定义@Configuration 注解标注的配置类,告诉Spring这是一个配置类。
- (2)通过@Bean 注解给容器中注册一个Bean;类型返回值的类型,id默认是用方法名作为id。也可以通过value属性重新定义id。
1 |
|
通过AnnotationConfigApplicationContext 类型的上下文获取bean,测试结果如下:1
2
3
4
5ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
Person p = (Person) applicationContext.getBean("person1");
System.out.println(p);
//结果为Person{name='lisi', age=26}
4.@ComponentScan包扫描
4.1 原有配置文件方式包扫描:
1 | <!--包扫描:只要标注了@Controller、@Service、@Repository、@Component--> |
4.2 @ComponentScan基本使用
注解方式通过@ComponentScan(value = “com.rocklei123”)设置,value指定要扫描的包
1 |
|
4.3 @ComponentScan高级用法-ComponentScans 等介绍
- @ComponentScans通过源码可以需要封装ComponentScan[],即可以定义多个ComponentScan
- includeFilters = Filter[] :指定扫描的时候只需要包含哪些组件
- excludeFilters = Filter[] :指定扫描的时候按照什么规则排除那些组件
- FilterType.ANNOTATION:按照注解
- FilterType.ASSIGNABLE_TYPE:按照给定的类型;
- FilterType.ASPECTJ:使用ASPECTJ表达式
- FilterType.REGEX:使用正则指定
- FilterType.CUSTOM:使用自定义规则
4.4 includeFilters
- includeFilters = Filter[] :指定扫描的时候只需要包含哪些组件
示例1 :只包含Controller注解的类注入到Spring容器中
1 |
|
4.5 excludeFilters
excludeFilters = Filter[] :指定扫描的时候按照什么规则排除那些组件
useDefaultFilters 默认为true
示例2 :所有PersonService 类型(包括子类)注不入到Spring容器中
1 |
|
4.6 自定义TypeFilter
示例3 :只包含Controller注解的类、PersonService类或其子类、及匹配自定义注解的类。注入到Spring容器中
1 |
|
自定义过滤规则
1 | package com.rocklei123.config; |
5. @Scope
@Scope:注解可以调整作用域
prototype:多实例的:ioc容器启动并不会去调用方法创建对象放在容器中。每次获取的时候才会调用方法创建对象;
singleton:单实例的(默认值):ioc容器启动会调用方法创建对象放到ioc容器中。以后每次获取就是直接从容器(map.get())中拿。
request:同一次请求创建一个实例
session:同一个session创建一个实例 默认是单实例的
1 | * ConfigurableBeanFactory#SCOPE_PROTOTYPE |
5.1 singleton(默认)测试示例
1 |
|
5.2 @Scope(value = “prototype”)测试示例
1 |
|
6.@Lazy 注解
懒加载:
单实例bean:默认在容器启动的时候创建对象;
懒加载:容器启动不创建对象。第一次使用(获取)Bean创建对象,并初始化;
通过以下测试代码,可以很清楚的看到容器启动不创建对象。第一次使用(获取)Bean创建对象。测试代码如下:
1 |
|
测试结果(过滤Spring自动注入容器的的Bean打印信息)1
2
3
4
5
6
7
8
9
10IOC容器准备初始化...
IOC容器初始化已经完成...打印当前容器中的Bean名称
mainConfig2
person
通过applicationContext.getBean方法获取Person Bean
Person Bean Lazy注解标注的Bean添加到容器中...
给容器中添加person bean...
打印当前容器中的Bean名称...
mainConfig2
person
7.@Conditional
7.1 @Conditional 注解介绍
@Conditional 注解: 按照一定的条件进行判断,满足条件给容器中注册bean
可通过实现org.springframework.context.annotation.Condition接口,重写public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata)方法,判断是否加入容器中。返回true表示条件成立,向容器中注入Bean。
ConditionContext conditionContext 判断条件能使用的上下文
AnnotatedTypeMetadata annotatedTypeMetadata 注释信息
1 | //1、能获取到ioc使用的beanfactory |
7.2 @Conditional 注解示例
本例根据操作系统环境信息 os.name 确定加载的Person Bean信息。因为开发环境为Windows 10 操作系统,故本例结果将加载Person Bean为bill。
1 | public class LinuxCondition implements Condition { |
运行结果(过滤Spring自动注入的类)
1 | 环境信息为:Windows 10 |
8.@Import
@Import[快速给容器中导入一个组件]
- 1)、@Import(要导入到容器中的组件);容器中就会自动注册这个组件,id默认是全类名
- 2)、ImportSelector:返回需要导入的组件的全类名数组;
- 3)、ImportBeanDefinitionRegistrar:手动注册bean到容器中
8.1 @Import 使用
@Import 的Value是一个Class[] 数组,可以传入多个值,也可以传入单个值。
1 | public Import { |
向Spring容器中导入一个Color组件
1 | public class Color { |
测试结果
1 | mainConfigImport |
8.2 ImportSelector接口
ImportSelector 自定义逻辑返回需要导入的组件。返回值,就是到导入到容器中的组件全类名,方法不要返回null值,否则报空指针。
1 | public class MyImportSelector implements ImportSelector { |
测试结果
1 | ---------com.rocklei123.config.MainConfigImport |
8.3 ImportBeanDefinitionRegistrar接口
- AnnotationMetadata:当前类的注解信息
- BeanDefinitionRegistry:BeanDefinition注册类;
- 把所有需要添加到容器中的bean;调用BeanDefinitionRegistry.registerBeanDefinition手工注册进来
1 | package com.rocklei123.importSelector; |
9 FactoryBean 接口
通过实现Spring提供的FactoryBean
9.1 FactoryBean方法介绍
1 |
|
9.2 要获取工厂Bean本身
- 我们需要给id前面加一个&(如&colorFactoryBean)
1 | public interface BeanFactory { |
9.3 FactoryBean测试代码及结果
1 | import org.springframework.beans.factory.FactoryBean; |
测试结果:
1 | mainConfigBeanFactory |
10. Spring容器注册组件总结
给容器中注册组件;
- 1)、包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)[自己写的类]
- 2)、@Bean[导入的第三方包里面的组件]
3)、@Import[快速给容器中导入一个组件]
- 1)、@Import(要导入到容器中的组件);容器中就会自动注册这个组件,id默认是全类名
- 2)、ImportSelector:返回需要导入的组件的全类名数组;
- 3)、ImportBeanDefinitionRegistrar:手动注册bean到容器中
4)、使用Spring提供的FactoryBean(工厂Bean);
- 1)、默认获取到的是工厂bean调用getObject创建的对象
- 2)、要获取工厂Bean本身,我们需要给id前面加一个&(如&colorFactoryBean)