本文是尚硅谷雷丰阳老师《尚硅谷Spring注解驱动教程》课程的笔记
系列文章目录
1.Spring注解驱动-组件注册部分
2.Spring注解驱动-属性赋值和自动装配部分
文章目录
- Spring注解驱动开发
- 核心容器
- 组件注册-@Configuration&@Bean给容器注册组件
- 组件注册-@ComponentScan自动扫描组件&指定扫描规则
- 组件注册-自定义TypeFilter指定过滤规则
- 组件注册-@Scope
- 组件注册-@Lazy-bean
- 组件注册-@Conditional-按条件注册bean
- 组件注册-@Import-给容器中快速导入一个组件
- 组件注册-@Import-使用ImportSelector
- 组件注册-@Import-使用ImportBeanDefinitionRegistrar
- 组件注册-使用FactoryBean注册组件
- 生命周期-@Bean指定初始化和销毁方法
- 生命周期-InitializingBean和DisposableBean
- 生命周期-@PostConstruct&@PreDestroy
- 生命周期-BeanPostProcessor-后置处理器
- 生命周期-BeanPostProcessor原理
- 生命周期-BeanPostProcessor在Spring底层的使用
Spring注解驱动开发
核心容器
Spring认为所有的组件都应该放在Ioc容器中,组件之间的关系通过容器进行装配。
组件注册-@Configuration&@Bean给容器注册组件
传统的Spring配置
目录:
Spring-annotation
- src
-m ain
- java
- com.atguigu.bean
- MainTest
- Person
- resources
- beans.xml
- pom.xml
1)步骤一:引入Maven依赖------pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.atguigu</groupId>
<artifactId>Spring-annotation</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
</project>
2)步骤二:引入Spring配置文件------beans.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id = "person" class="com.atguigu.bean.Person">
<property name="age" value="18"></property>
<property name="name" value="zhansan"></property>
</bean>
</beans>
3)步骤三:定义Person------Person
package com.atguigu.bean;
/**
* @version 1.0
* @description:
* @date 2023/1/7 15:06
*/
public class Person {
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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
public Person() {
}
}
4)步骤四:使用Ioc容器获取Person------MainTest
package com.atguigu.bean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @version 1.0
* @description:
* @date 2023/1/7 15:19
*/
public class MainTest {
public static void main(String[] args) {
// 传入配置文件
ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("beans.xml");
Person person = (Person) classPathXmlApplicationContext.getBean("person");
System.out.println(person);
}
}
结果
使用注解开发
使用配置类代替配置文件,实际上配置类==配置文件
使用注解@Configuration和@Bean
其中:@Configuration用于告诉Spring这是一个配置类;@Bean则是向Ioc容器注册一个Bean
1)步骤一:新建配置类------com/atguigu/config/MainConfig.java
package com.atguigu.config;
import org.springframework.context.annotation.Configuration;
import com.atguigu.bean.Person;
import org.springframework.context.annotation.Bean;
// 告诉Spring这是一个配置类
@Configuration
public class MainConfig {
// 给容器中注册一个Bean; 类型为返回值的类型,id默认是使用方法名作为id
@Bean
public Person person(){
return new Person("lisi", 24);
}
}
2)步骤二:测试
package com.atguigu.bean;
import com.atguigu.config.MainConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @version 1.0
* @description:
* @date 2023/1/7 15:19
*/
public class MainTest {
public static void main(String[] args) {
// // 传入配置文件
// ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("beans.xml");
// Person person = (Person) classPathXmlApplicationContext.getBean("person");
// System.out.println(person);
ApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
Person bean = annotationConfigApplicationContext.getBean(Person.class);
System.out.println(bean);
}
}
结果
bean
改名
查看bean注解可知----》指定名字
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
@AliasFor("name")
String[] value() default {};
@AliasFor("value")
String[] name() default {};
Autowire autowire() default Autowire.NO;
String initMethod() default "";
String destroyMethod() default "(inferred)";
}
@Bean("ho")
public Person person(){
return new Person("lisi", 24);
}
public class MainTest {
public static void main(String[] args) {
// // 传入配置文件
// ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("beans.xml");
// Person person = (Person) classPathXmlApplicationContext.getBean("person");
// System.out.println(person);
ApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
Person bean = annotationConfigApplicationContext.getBean(Person.class);
System.out.println(bean);
String[] beanNamesForType = annotationConfigApplicationContext.getBeanNamesForType(Person.class);
for (String beans:beanNamesForType) {
System.out.println(beans);
}
}
}
结果
组件注册-@ComponentScan自动扫描组件&指定扫描规则
传统情况---》src/main/resources/beans.xml
加入一行
<!-- 包扫描,只要标注了@Controller、@Service、@Repository、@Component都会被自动扫描装配进容器中-->
<!-- 注意:只有标注了才能被扫描,为什么要有多种,是为了分层标识,而且为不同的层可能有特定的用处和功能-->
<context:component-scan base-package="com.atguigu"></context:component-scan>
src/main/java/com/atguigu/config/MainConfig.java
加入注解@ComponentScan(value = "xxx"),value用于指定要扫描的包的路径
// 告诉Spring这是一个配置类
@Configuration
@ComponentScan(value = "com.atguigu")
public class MainConfig {
// 给容器中注册一个Bean; 类型为返回值的类型,id默认是使用方法名作为id
@Bean("ho")
public Person person(){
return new Person("lisi", 24);
}
}
例子:更新目录
Spring-annotation
- src
-m ain
- java
- com.atguigu
- bean
- MainTest
- Person
- controller
- BookController
- dao
- BookDao
- service
- BookService
- resources
- beans.xml
- pom.xml
对应的BookDao加上@Repository、BookService加上@Service、BookController加上@Controller
新建一个测试类
src/test/java/com/atguigu/test/IOCTest.java
package com.atguigu.test;
import com.atguigu.config.MainConfig;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import javax.lang.model.element.VariableElement;
/**
* @version 1.0
* @description:
* @date 2023/1/7 19:48
*/
public class IOCTest {
@Test
public void test01(){
ApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
String[] beanDefinitionNames = annotationConfigApplicationContext.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
}
结果
对于@ComponentScan
注解包含includeFilters
和excludeFilters
,都属于是数组。用于过滤哪些需要包含、哪些需要排除
ComponentScan.Filter[] includeFilters() default {};
ComponentScan.Filter[] excludeFilters() default {};
@Retention(RetentionPolicy.RUNTIME)
@Target({})
public @interface Filter {
FilterType type() default FilterType.ANNOTATION;
@AliasFor("classes")
Class<?>[] value() default {};
@AliasFor("value")
Class<?>[] classes() default {};
String[] pattern() default {};
}
其中ComponentScan.Filter[]
是一个Filter
数组,而Filter
默认的过滤规则为FilterType.ANNOTATION
,按注解;而FilterType
有多种过滤规则。
package org.springframework.context.annotation;
public enum FilterType {
ANNOTATION,
ASSIGNABLE_TYPE,
ASPECTJ,
REGEX,
CUSTOM;
private FilterType() {
}
}
FilterType.ANNOTATION:按照注解
FilterType.ASSIGNABLE_TYPE:按照给定的类型
FilterType.ASPECTJ:使用ASPECTJ表达式(不常用)
FilterType.REGEX:使用正则表达式
FilterType.CUSTOM:使用自定义规则
excludeFilters
指定扫描的时候按照什么规则排除那些组件
更新新的过滤规则,在src/main/java/com/atguigu/config/MainConfig.java的@ComponentScan更新配置
// 告诉Spring这是一个配置类
@Configuration
@ComponentScan(value = "com.atguigu", excludeFilters = {
// 排除规则:排除类型为注解,类型为Controller.class和Service.class,即不扫描带@Controller和@Service的类
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class})
})
public class MainConfig {
// 给容器中注册一个Bean; 类型为返回值的类型,id默认是使用方法名作为id
@Bean("ho")
public Person person(){
return new Person("lisi", 24);
}
}
结果
可以发现bookService和bookController不在容器中
includeFIlters
指定扫描的时候只需要包含哪些组件
但是Spring默认是扫描所有的组件,需要更改这个配置才能使用includeFilters。
在最原始的时候是需要在xml文件中指定修改use-default-filters="false"
<context:component-scan base-package="com.atguigu" use-default-filters="false"></context:component-scan>
而使用注解的话,在ComponentScan中有一个boolean useDefaultFilters() default true;
@Configuration
@ComponentScan(value = "com.atguigu", includeFilters = {
// 排除规则:排除类型为注解,类型为Controller.class和Service.class,即不扫描带@Controller和@Service的类
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class}),
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {BookService.class})
}, useDefaultFilters = false)
public class MainConfig {
// 给容器中注册一个Bean; 类型为返回值的类型,id默认是使用方法名作为id
@Bean("ho")
public Person person(){
return new Person("lisi", 24);
}
}
结果
组件注册-自定义TypeFilter指定过滤规则
步骤一:新建配置类src/main/java/com/atguigu/config/MyTypeFilter.java
public class MyTypeFilter implements TypeFilter {
/**
* match
*
* @param metadataReader:读取到的当前正在扫描的类信息
* @param metadataReaderFactory:可以获取到其他任何类信息的
*
* @return boolean
*/
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
// 获取当前类注解的信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
// 获取当前正在扫描的类的类信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
// 获取当前类资源(类的路径)
Resource resource = metadataReader.getResource();
String className = classMetadata.getClassName();
System.out.println("目前正在扫描的包名为:"+className);
if(className.contains("er")){
// 匹配成功就会被包含在容器中
return true;
}
return false;
}
}
步骤二:更新匹配规则
@Configuration
@ComponentScan(value = "com.atguigu", includeFilters = {
// 排除规则:排除类型为注解,类型为Controller.class和Service.class,即不扫描带@Controller和@Service的类
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class}),
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {BookService.class}),
// 启用自定义扫描,扫描规则为MyTypeFilter.class
@ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})
}, useDefaultFilters = false)
public class MainConfig {
}
结果
目前正在扫描的包名为:com.atguigu.test.IOCTest
目前正在扫描的包名为:com.atguigu.bean.MainTest
目前正在扫描的包名为:com.atguigu.bean.Person
目前正在扫描的包名为:com.atguigu.config.MyTypeFilter
目前正在扫描的包名为:com.atguigu.dao.BookDao
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
person
myTypeFilter
bookController
bookService
ho
组件注册-@Scope
步骤1:新建新的配置类src/main/java/com/atguigu/config/MainConfig2.java
@Configuration
public class MainConfig2 {
@Bean("person")
public Person person(){
return new Person("zhangsan", 24);
}
}
步骤2:新建测试类
@Test
public void test02(){
ApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
String[] beanDefinitionNames = annotationConfigApplicationContext.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
Object person = annotationConfigApplicationContext.getBean("person");
Object person1 = annotationConfigApplicationContext.getBean("person");
System.out.println(person == person1);
}
结果
可以注意到,在工厂中获取多次,实际上获取的person也是同一个(单实例)
要改变这种情况,需要引入另一个注解@Scope
,该注解有一个属性String scopeName() default "";
里面使用ConfigurableBeanFactory
而ConfigurableBeanFactory
定义了两种模式String SCOPE_SINGLETON = "singleton";
(单例模式,默认)和String SCOPE_PROTOTYPE = "prototype";
(多例模式)
因此可以通过@Scope修改为多例模式实际上相当于beans.xml中 <bean id = "person" class="com.atguigu.bean.Person" scope="prototype"> <property name="age" value="18"></property> <property name="name" value="zhansan"></property> </bean>
@Configuration
src/main/java/com/atguigu/config/MainConfig2.java
public class MainConfig2 {
@Scope("prototype")
@Bean("person")
public Person person(){
return new Person("zhangsan", 24);
}
}
此时的结果改为:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig2
person
false
注意:
singleton:单实例(默认值):ioc容器启动会调用方法创建对象放到ioc容器中,以后每次获取就是直接从容器(map.get)中拿。
prototype:多实例情况下,ioc容器启动并不会去调用方法创建对象放在ioc容器中。每次获取的时候才会调用方法创建对象。
request:同一个请求创建一个实例
session:同一个session创建一个实例
组件注册-@Lazy-bean
单实例bean:默认在容器启动的时候创建对象(放在单例池中),以后每次调用都不会创建;
懒加载@Lazy
:容器创建不创建对象。第一个使用(获取)Bean创建对象,并初始化;
加入@Lazy
前
ioc容器创建完成...
person
加入@Lazy
后
src/main/java/com/atguigu/config/MainConfig2.java
@Configuration
public class MainConfig2 {
@Scope("prototype")
@Bean("person")
@Lazy
public Person person(){
return new Person("zhangsan", 24);
}
}
结果:
ioc容器创建完成...
组件注册-@Conditional-按条件注册bean
@Conditional
:SpringBoot
底层大量使用该注解,按照一定的条件进行判断,满足条件给容器中注册bean。不像原来的@Bean
,加上就注入到Ioc容器中。@Conditional
是按条件注册。
src/main/java/com/atguigu/config/MainConfig2.java
@Configuration
public class MainConfig2 {
@Scope("prototype")
@Lazy
@Bean("person")
public Person person(){
return new Person("zhangsan", 24);
}
@Bean("bill")
public Person person01(){
return new Person("Bill Gates", 62);
}
@Bean("linus")
public Person person02(){
return new Person("linux", 48); }
}
src/test/java/com/atguigu/test/IOCTest.java
public class IOCTest {
ApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
@Test
public void test03(){
System.out.println("ioc容器创建完成...");
String[] beanNamesForType = annotationConfigApplicationContext.getBeanNamesForType(Person.class);
for (String s : beanNamesForType) {
System.out.println(s);
}
// 所有person定义的Map
Map<String, Person> beansOfType = annotationConfigApplicationContext.getBeansOfType(Person.class);
System.out.println(beansOfType);
}
}
//容器中新建了3个
结果:
ioc容器创建完成...
person
bill
linus
{person=Person{name='zhangsan', age=24}, bill=Person{name='Bill Gates', age=62}, linus=Person{name='linux', age=48}}
目前的需求发生了改变,如果操作系统是Windows则创建Bill,若是Linux则创建linus
因此需要用到按条件创建Bean----->@Conditional
查看Conditional,可看到该注解即可标在类上,也可标在方法上。需要传入一个Condition(数组)
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
Class<? extends Condition>[] value();
}
查看Condition发现这是一个接口,需要写实现类。有一个matches的方法用于判断T/F
// 有两个参数,第一个参数ConditionContext是判断条件能使用的上下文(环境),第二个参数AnnotatedTypeMetadata是注释信息
@FunctionalInterface
public interface Condition {
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
实现
1.由于是Condition作为判断,因此需要实现该接口,并实现方法
src/main/java/com/atguigu/condition/LinuxCondition.java
public class LinuxCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//1.能获取到ioc使用的beanfactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//2.获取类加载器
ClassLoader classLoader = context.getClassLoader();
//3.获取环境信息
Environment environment = context.getEnvironment();
//4,获取bean定义的注册类
BeanDefinitionRegistry registry = context.getRegistry();
String property = environment.getProperty("os.name");
if (property.contains("linux")) {
return true;
}
return false;
}
}
src/main/java/com/atguigu/condition/WindowsCondition.java
public class WindowsCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//1.能获取到ioc使用的beanfactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//2.获取类加载器
ClassLoader classLoader = context.getClassLoader();
//3.获取环境信息
Environment environment = context.getEnvironment();
//4,获取bean定义的注册类
BeanDefinitionRegistry registry = context.getRegistry();
String property = environment.getProperty("os.name");
if (property.contains("Windows")) {
return true;
}
return false;
}
}
2.修改对应方法
src/main/java/com/atguigu/config/MainConfig2.java
@Conditional({WindowsCondition.class})
@Bean("bill")
public Person person01(){return new Person("Bill Gates", 62);}
@Conditional({LinuxCondition.class})
@Bean("linus")
public Person person02(){return new Person("linux", 48); }
3.结果
Windows 10
ioc容器创建完成...
person
bill
扩展:也可以通过registry查看是否含有某个bean,没有就进行注册
boolean person = registry.containsBeanDefinition("person");
也可以将@Conditional标在类上,只有满足Condition的条件,这个类中的所有bea注册才能生效
@Conditional({LinuxCondition.class})
@Configuration
public class MainConfig2 {
...
}
结果:
Windows 10
ioc容器创建完成...
{}
组件注册-@Import-给容器中快速导入一个组件
回顾:给容器中注册组件:
1)包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)【具有局限性,只能扫描自定义的,其他引入的包扫描不到】
2)@Bean【导入的第三方包里面的组件】@Conditional({WindowsCondition.class}) @Bean("bill") public Person person01(){ return new Person("Bill Gates", 62); }
3)@Import【相比于第二种需要创建一个类,能直接通过无参构造器快速给容器导入一个组件】
——1) @Import(要导入到容器中的组件),容器中就会自动注册这个组件,id默认是全类名
——2) ImportSelector:返回需要导入的组件的全类名数组;
——3)ImportBeanDefinitionRegistrar:手动注册bean到容器中
4)使用Spring提供的FactoryBean(工厂Bean)
——1)默认获取到的是工厂bean调用getObject创建的对象
——2)要获取工厂Bean本身,我们需要给id前面加一个&(&colorFactoryBean)
例子:
1)新建一个组件src/main/java/com/atguigu/bean/Color.java
public class Color {
}
2)进行测试,很明显没有注册到容器中
public class IOCTest {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
@Test
public void testImport(){
printBeans(annotationConfigApplicationContext);
}
// 抽取公共方法输出容器里面所有组件
private void printBeans(AnnotationConfigApplicationContext context){
String[] beanDefinitionNames = context.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
}
使用@Import
导入Color
src/main/java/com/atguigu/config/MainConfig2.java
@Configuration
@Import(Color.class)
public class MainConfig2 {
...
}
结果:注意,@Import默认的id是组件的全类名
...
org.springframework.context.event.internalEventListenerFactory
mainConfig2
com.atguigu.bean.Color
person
bill
查看@Import可以看到是一个数组,即可以导入多个
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
/**
* {@link Configuration @Configuration}, {@link ImportSelector},
* {@link ImportBeanDefinitionRegistrar}, or regular component classes to import.
*/
Class<?>[] value();
}
另外新建一个Red.java
@Configuration
@Import({Color.class, Red.class})
public class MainConfig2 {
}
结果:
mainConfig2
com.atguigu.bean.Color
com.atguigu.bean.Red
person
bill
组件注册-@Import-使用ImportSelector
查看ImportSelector源码,可知是一个接口,规定一个方法selectImport,是要导入的全类名数组
public interface ImportSelector {
// AnnotationMetadata:当前标注@Import注解的类的所有注解信息
String[] selectImports(AnnotationMetadata importingClassMetadata);
}
新建src/main/java/com/atguigu/condition/MyImportSelector.java
新建src/main/java/com/atguigu/bean/Red.java
新建src/main/java/com/atguigu/bean/Yellow.java
// 自定义逻辑返回需要导入的组件
public class MyImportSelector implements ImportSelector {
@Override
// AnnotationMetadata:当前标注@Import注解的类的所有注解信息,比如下面的 MainConfig2 可获取到@Configuration和@Import信息
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
// 不能返回null,不然会导致空指针异常
// return new String[0];
return new String[]{"com.atguigu.bean.Blue", "com.atguigu.bean.Yellow"};
}
}
修改对应代码
@Configuration
@Import({Color.class, Red.class, MyImportSelector.class})
public class MainConfig2 {
}
结果:
mainConfig2
com.atguigu.bean.Color
com.atguigu.bean.Red
com.atguigu.bean.Blue
com.atguigu.bean.Yellow
person
bill
组件注册-@Import-使用ImportBeanDefinitionRegistrar
手动注册Bean
查看ImportBeanDefinitionRegistrar源码,可知也是一个接口,有一个方法selectImports,给容器中自己添加一些组件
//
public interface ImportBeanDefinitionRegistrar {
// importingClassMetadata:当前类的注解信息
// registry:Bean定义的注册类
/**
* registerBeanDefinitions
*
* @param importingClassMetadata 当前类的注解信息
* @param registry BeanDefinition的注册类
* 把所有需要添加到容器中的bean,BeanDefinitionRegistry有一个registerBeanDefinition方法
* 调用BeanDefinitionRegistry.registerBeanDefinition方法手工注册进来
*
*/
default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,
BeanNameGenerator importBeanNameGenerator) {
registerBeanDefinitions(importingClassMetadata, registry);
}
default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
}
}
新建类src/main/java/com/atguigu/condition/MyImportBeanDefinitionRegistrar.java
新建类com/atguigu/bean/RainBow.java
1)定义MyImportBeanDefinitionRegistrar
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
* registerBeanDefinitions
*
* @param importingClassMetadata 当前类的注解信息
* @param registry BeanDefinition的注册类
* 把所有需要添加到容器中的bean,BeanDefinitionRegistry有一个registerBeanDefinition方法
* 调用BeanDefinitionRegistry.registerBeanDefinition方法手工注册进来
*
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 查询容器中
boolean red = registry.containsBeanDefinition("com.atguigu.bean.Red");
boolean blue = registry.containsBeanDefinition("com.atguigu.bean.Blue");
if (red && blue) {
// 指定Bean的定义信息(Bean的类型,Bean的作用域等)
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(RainBow.class);
// 注册一个Bean,指定bean名
registry.registerBeanDefinition("rainBow", rootBeanDefinition);
}
}
}
结果:
mainConfig2
com.atguigu.bean.Color
com.atguigu.bean.Red
com.atguigu.bean.Blue
com.atguigu.bean.Yellow
person
bill
rainBow
查看registry.registerBeanDefinition源码
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
对于BeanDefinition,查看源码可知是一个接口
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
...
}
调用其中RootBeanDefinition实现类
@SuppressWarnings("serial")
public class RootBeanDefinition extends AbstractBeanDefinition {
...
}
组件注册-使用FactoryBean注册组件
首先查看FactoryBean源码,可看出这个是一个接口,容器会调用getObject方法,返回的对象,把这个对象放在容器中,而getObjectType返回对象的类型,isSingleton判断是否单例
public interface FactoryBean<T> {
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
@Nullable
T getObject() throws Exception;
@Nullable
Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
}
步骤1)新建src/main/java/com/atguigu/bean/ColorFactoryBean.java
public class ColorFactoryBean implements FactoryBean<Color> {
// 返回Color对象,这个对象会返回到容器中
@Override
public Color getObject() throws Exception {
System.out.println("ColorFactoryBean...");
return new Color();
}
@Override
public Class<?> getObjectType() {
return Color.class;
}
/**
* isSingleton 控制是否单例
*
*
* @return boolean
* true:这个容器是单实例,在容器中只会保存一份
* false:多实例,每次获取都会创建一个新的,调用getObject方法
*/
@Override
public boolean isSingleton() {
return true;
}
}
步骤2)在src/main/java/com/atguigu/config/MainConfig2.java注册
@Bean
public ColorFactoryBean colorFactoryBean(){
return new ColorFactoryBean();
}
步骤3)修改com.atguigu.test.IOCTest#testImport
@Test
public void testImport(){
printBeans(annotationConfigApplicationContext);
// 工厂bean获取的是调用getObject创建的对象
Object colorFactoryBean = annotationConfigApplicationContext.getBean("colorFactoryBean");
System.out.println("bean的类型:" + colorFactoryBean.getClass());
}
结果:
mainConfig2
com.atguigu.bean.Color
com.atguigu.bean.Red
com.atguigu.bean.Blue
com.atguigu.bean.Yellow
person
bill
colorFactoryBean
rainBow
ColorFactoryBean...
bean的类型:class com.atguigu.bean.Color
根据结果可知,虽然加载的名字是colorFactoryBean,但实际上这个colorFactoryBean的类型是Color
创建两个bean查看是否一样
@Test
public void testImport(){
printBeans(annotationConfigApplicationContext);
// 工厂bean获取的是调用getObject创建的对象
Object colorFactoryBean1 = annotationConfigApplicationContext.getBean("colorFactoryBean");
Object colorFactoryBean2 = annotationConfigApplicationContext.getBean("colorFactoryBean");
System.out.println("bean的类型:" + colorFactoryBean1.getClass());
System.out.println(colorFactoryBean1 == colorFactoryBean2);
}
结果:(可看到是同一个bean对象)
ColorFactoryBean...
bean的类型:class com.atguigu.bean.Color
true
将isSingletion()修改为return false
@Override
public boolean isSingleton() {
return true;
}
结果:(可看出不是同一个对象了)
ColorFactoryBean...
ColorFactoryBean...
bean的类型:class com.atguigu.bean.Color
false
需求:想直接输出FacotryBean
在getBean加上&即可
Object colorFactoryBean3 = annotationConfigApplicationContext.getBean("&colorFactoryBean");
System.out.println("bean4的类型:" + colorFactoryBean3.getClass());
结果:
bean4的类型:class com.atguigu.bean.ColorFactoryBean
查看源码
org/springframework/beans/factory/BeanFactory.java
public interface BeanFactory {
String FACTORY_BEAN_PREFIX = "&";
}
生命周期-@Bean指定初始化和销毁方法
bean的生命周期:
- bean创建–>初始化–>销毁的过程
容器管理bean的生命周期;
我们可以自定义初始化和销毁方法;容器在bean进行到生命周期爱的时候来调用我们自定义的初始化和销毁方法
构建(对象创建)
- 单实例:在容器启动时创建对象
- 多实例:在每次获取的时候创建对象(@Scope(“prototype”))
BeanPostProcessor.postProcessBeforeInitialization
初始化:
- 对象创建完成,并赋值好,调用初始化方法。。。
BeanPostProcessor.postProcessAfterInitialization
销毁:
- 单实例:容器关闭的时候进行销毁
- 多实例:容器不会管理整个bean;容器不会调用销毁方法
遍历得到容器中所有的BeanPostProcessor,然后挨个执行beanPostProcessor。
一旦返回null,跳出for循环,不会执行后面的beanPostProcessorsBeforeInitialization// 给bean进行属性赋值 populateBean(beanName, mbd, instanceWrapper){ applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); invokeInitMethods(beanName, wrappedBean, mbd);执行自定义初始化 applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); }
1)指定初始化和销毁方法
- 通过@Bean指定init-method=“xxx” destroy-method=“xxx”
2)通过让Bean实现InitializingBean(定义初始化逻辑),DisposableBean(定义销毁逻辑)
3)可以使用JSR250;
- @PostConstruct:在bean创建完成并且属性赋值完成;来执行初始化方法
- @PreDestro:在容器销毁bean之前通知我们进行清理工作
4)BeanPostProcessor【interface】:bean的后置处理器;
- 在bean初始化前后进行一些处理工作;
- postProcessBeforeInitialization:在初始化之前工作
- postProcessAfterInitialization:在初始化之后工作
使用xml方法
<bean id = "person" class="com.atguigu.bean.Person" scope="prototype" init-method="xxx" destroy-method="xxx">
<property name="age" value="18"></property>
<property name="name" value="zhansan"></property>
</bean>
使用注解
com/atguigu/bean/Car.java
public class Car {
public Car() { System.out.println("car constructor..."); }
public void init() { System.out.println("car...init..."); }
public void destroy() { System.out.println("car...destroy..."); }
}
新建com/atguigu/config/MainConfigOfLifeCycle.java并注册Car
@Configuration
public class MainConfigOfLifeCycle {
@Bean
public Car car() {
return new Car();
}
}
新建测试类com/atguigu/test/IOCTest_LifeCycle.java
public class IOCTest_LifeCycle {
@Test
public void test01() {
// 1.创建ioc容器
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
System.out.println("容器创建完成...");
// 关闭容器
context.close();
}
}
结果:
car constructor...
car...init...
容器创建完成...
car...destroy...
生命周期-InitializingBean和DisposableBean
查看接口InitializingBean
public interface InitializingBean {
// 作用时机,BeanFactory创建好并且把bean所有的属性都设置好
void afterPropertiesSet() throws Exception;
}
查看接口DisposableBean
public interface DisposableBean {
void destroy() throws Exception;
}
创建src/main/java/com/atguigu/bean/Cat.java
@Component
public class Cat implements InitializingBean, DisposableBean {
public Cat() {
System.out.println("cat constructor...");
}
@Override
public void destroy() throws Exception {
System.out.println("cat...destroy...");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("cat...afterPropertiesSet...");
}
}
@ComponentScan("com.atguigu.bean")
@Configuration
public class MainConfigOfLifeCycle {
@Bean(initMethod = "init", destroyMethod = "destroy")
public Car car() {
return new Car();
}
}
测试结果:
cat constructor...
cat...afterPropertiesSet...
car constructor...
car...init...
容器创建完成...
car...destroy...
cat...destroy...
生命周期-@PostConstruct&@PreDestroy
查看注解PostConstruct源码
@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PostConstruct {
}
创建src/main/java/com/atguigu/bean/Dog.java
@Component
public class Dog {
public Dog() {
System.out.println("dog constructor...");
}
// 对象创建并赋值之后调用
@PostConstruct
public void init() {
System.out.println("dog...@PostConstruct...");
}
// 容器移除对象之前
@PreDestroy
public void destory() {
System.out.println("dog...@PreDestroy...");
}
}
测试:
cat constructor...
cat...afterPropertiesSet...
dog constructor...
dog...@PostConstruct...
car constructor...
car...init...
容器创建完成...
car...destroy...
dog...@PreDestroy...
cat...destroy...
生命周期-BeanPostProcessor-后置处理器
BeanPostProcessor
是在创建Bean
的时候,先扫描所有BeanPostProcessor
的postProcessBeforeInitialization
,符合条件的调用。然后再创建对应的Bean对象。然后再扫描所有BeanPostProcessor
的postProcessAfterInitialization
,符合条件的调用。
查看BeanPostProcessor源码
public interface BeanPostProcessor {
// bean是刚创建的实例名字,beanName是这个实例在容器中的名字
// 返回值是要返回将要使用的bean,可以返回传进来的bean,也可以对bean进行包装然后返回出去
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
新建src/main/java/com/atguigu/bean/MyBeanPostProcessor.java
/**
* @version 1.0
* @description: 后置处理器:初始化前后进行处理工作
* 将后置处理器加入到容器中
* @date 2023/1/11 14:39
*/
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization..." + beanName + "=>" + bean);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization..." + beanName + "=>" + bean);
return bean;
}
}
可以观察到每个对象即使没有调用,但都执行了
postProcessBeforeInitialization
和postProcessAfterInitialization
。则是因为MyBeanPostProcessor
的postProcessBeforeInitialization
和postProcessAfterInitialization
没有设置条件。每个Bean创建的时候都扫描到这个MyBeanPostProcessor
然后执行。
结果:
cat constructor...
postProcessBeforeInitialization...cat=>com.atguigu.bean.Cat@6c7a164b
cat...afterPropertiesSet...
postProcessAfterInitialization...cat=>com.atguigu.bean.Cat@6c7a164b
dog constructor...
postProcessBeforeInitialization...dog=>com.atguigu.bean.Dog@536dbea0
dog...@PostConstruct...
postProcessAfterInitialization...dog=>com.atguigu.bean.Dog@536dbea0
car constructor...
postProcessBeforeInitialization...car=>com.atguigu.bean.Car@30b6ffe0
car...init...
postProcessAfterInitialization...car=>com.atguigu.bean.Car@30b6ffe0
容器创建完成...
生命周期-BeanPostProcessor原理
实际上,BeanPostProcesso是初始化,Bean对象注入到Ioc容器时调用的。
在postProcessBeforeInitialization
和postProcessAfterInitialization
打上断点
查看方法调用栈
可看到调用AnnotationConfigApplicationContext
的构造器,
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
// 无参构造,主要用于创建AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner
this();
// 扫描对应的.class文件,调用AnnotatedBeanDefinitionReader进行注入
register(annotatedClasses);
// 对Bean进行创建等操作
refresh();
}
其中的register(annotatedClasses):扫描对应的.class文件,调用AnnotatedBeanDefinitionReader进行注入
public void register(Class<?>... annotatedClasses) {
Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
this.reader.register(annotatedClasses);
}
最后调用了refresh()
方法
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
...
}
主要是调用了
finishBeanFactoryInitialization(beanFactory);
(初始化所有剩下的单实例对象)
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// Initialize conversion service for this context.
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
// Register a default embedded value resolver if no bean post-processor
// (such as a PropertyPlaceholderConfigurer bean) registered any before:
// at this point, primarily for resolution in annotation attribute values.
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(new StringValueResolver() {
@Override
public String resolveStringValue(String strVal) {
return getEnvironment().resolvePlaceholders(strVal);
}
});
}
// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// Stop using the temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(null);
// Allow for caching all bean definition metadata, not expecting further changes.
beanFactory.freezeConfiguration();
// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();
}
这里主要看最后一步
beanFactory.preInstantiateSingletons();
(初始化所有单例bean)
@Override
public void preInstantiateSingletons() throws BeansException {
...
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
@Override
public Boolean run() {
return ((SmartFactoryBean<?>) factory).isEagerInit();
}
}, getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
else {
getBean(beanName);
}
}
}
}
这里主要看getBean(beanName)【尝试获取Bean】
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
然后调用doGetBean---》再调用getSingleton
@Override
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
再看getSingleton,这里又调用了singletonFactory.getObject();获取单实例--》一直尝试获取
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
查看调用栈可知,由于【获取失败】,因此调用了createBean。而createBean调用了doCreateBean创建对象
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
...
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
调用doCreateBean有个initializeBean(beanName, exposedObject, mbd);
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
...
try {
// 为bean的属性进行赋值【即先为bean赋值再调用initializeBean】
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
// initializeBean(beanName, exposedObject, mbd)相当于后置处器的调用
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
...
}
initializeBean(beanName, exposedObject, mbd)相当于【后置处理器】的调用,前面还有一个populateBean(beanName, mbd, instanceWrapper);
为bean的属性进行赋值【即先为bean赋值再调用initializeBean】
而initializeBean(beanName, exposedObject, mbd)函数则是:
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
...
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 执行初始化方法 PostConstruct等
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
// 执行初始化后方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
...
}
由于还没销毁,直接查看applyBeanPostProcessorsBeforeInitialization,通过源码可以看出
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessBeforeInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}
生命周期-BeanPostProcessor在Spring底层的使用
该接口我们也叫后置处理器,作用是在Bean对象在实例化和依赖注入完毕后,在显示调用初始化方法的前后添加我们自己的逻辑。注意是Bean实例化完毕后及依赖注入完成后触发的。
查看
BeanPostProcessor
接口。org/springframework/beans/factory/config/BeanPostProcessor.java
查看其实现类
找到
ApplicationContext
,作用是可以帮我们组件注入到Ioc容器。
例子:
com/atguigu/bean/Dog.java
Dog实现ApplicationContextAware接口。即实现setApplicationContext方法,此时会传入一个ApplicationContext
@Component
public class Dog implements ApplicationContextAware {
// 新建ApplicationContext 用于接收
private ApplicationContext applicationContext;
public Dog() {
System.out.println("dog constructor...");
}
// 对象创建并赋值之后调用
@PostConstruct
public void init() {
System.out.println("dog...@PostConstruct...");
}
// 容器移除对象之前
@PreDestroy
public void destory() {
System.out.println("dog...@PreDestroy...");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
这个功能是由ApplicationContextAwareProcessor
实现
查看org.springframework.context.support.ApplicationContextAwareProcessor#postProcessBeforeInitialization方法
@Override
@Nullable
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// 如果没有实现则直接返回bean
if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware ||
bean instanceof ApplicationStartupAware)) {
return bean;
}
AccessControlContext acc = null;
if (System.getSecurityManager() != null) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
}
if (acc != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareInterfaces(bean);
return null;
}, acc);
}
else {
invokeAwareInterfaces(bean);
}
return bean;
}
这里有一个 bean instanceof ApplicationContextAware 用于判断有没有实现这个接口。如果有就调用invokeAwareInterfaces(bean),在里面注入值。(监听者模式?)
查看invokeAwareInterfaces方法,他会判断有没有实现ApplicationContextAware,如果是则把当前bean转化为ApplicationContextAware,再调用setApplicationContext,把Ioc容器注入进去。
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationStartupAware) {
((ApplicationStartupAware) bean).setApplicationStartup(this.applicationContext.getApplicationStartup());
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
例子2:Spring提供校验Validation(类似于JSR303)
实现
BeanPostProcessor
接口,这里的postProcessBeforeInitialization
和postProcessAfterInitialization
设置了条件
// 在JavaBean创建完注入属性时,可以进行校验。通过判断afterInitialization,在初始化前后调用doValidate进行校验
public class BeanValidationPostProcessor implements BeanPostProcessor, InitializingBean {
@Nullable
private Validator validator;
private boolean afterInitialization = false;
...
// 初始化之前
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (!this.afterInitialization) {
doValidate(bean);
}
return bean;
}
// 初始化之后
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (this.afterInitialization) {
doValidate(bean);
}
return bean;
}
...
}
例子3:@PostConstruct和@PreDestroy
// @PostConstruct和@PreDestroy是怎样起作用的?
@Component
public class Dog implements ApplicationContextAware {
private ApplicationContext applicationContext;
public Dog() {
System.out.println("dog constructor...");
}
// 对象创建并赋值之后调用
@PostConstruct
public void init() {
System.out.println("dog...@PostConstruct...");
}
// 容器移除对象之前
@PreDestroy
public void destory() {
System.out.println("dog...@PreDestroy...");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
打入断点进行调试
查看调用栈可以看出调用了InitDestroyAnnotationBeanPostProcessor
// 传递 javax.annotation.PostConstruct
public void setInitAnnotationType(Class<? extends Annotation> initAnnotationType) {
this.initAnnotationType = initAnnotationType;
}
// 传递 javax.annotation.PreDestroy
public void setDestroyAnnotationType(Class<? extends Annotation> destroyAnnotationType) {
this.destroyAnnotationType = destroyAnnotationType;
}
// 实现PostConstruct
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
try {
metadata.invokeInitMethods(bean, beanName);
}
catch (InvocationTargetException ex) {
throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
}
return bean;
}
注意看LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
可以找到生命周期注解
例子4:@Autowired
在创建完对象后对属性进行赋值
注意这里的AutowiredAnnotationBeanPostProcessor
比较特殊,不是直接实现BeanPostProcessor
使用的是AutowiredAnnotationBeanPostProcessor
public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor,
MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {
...
}