一.Bean生命周期
其定义为:从对象的创建到销毁的过程。而Spring中的一个Bean从开始到结束经历很多过程,但总体可以分为六个阶段:Bean定义、实例化、属性赋值、初始化、生存期、销毁。
二.创建一个类,注解为@Component
@Component
public class BeanLifeCtrl {
private final static Logger log = LoggerFactory.getLogger(BeanLifeCtrl.class);
public BeanLifeCtrl(){
log.info("执行了构造方法");
}
@Autowired
public void getName(@Value("java_home")String java_home){
log.info("依赖注入:"+java_home);
}
@PostConstruct
public void postConstruct(){
log.info("构造后处理!");
}
@PreDestroy
public void beforeDestroy(){
log.info("销毁前处理");
}
}
然后运行springboot
2023-09-18 09:51:15.480 INFO 17872 --- [ main] com.jjh.BeanLifeApplication : Starting BeanLifeApplication using Java 11.0.14 on LAPTOP-UR1MH949 with PID 17872 (E:\cloud-project\BeanLife\target\classes started by JJH in E:\cloud-project\SpringIoc)
2023-09-18 09:51:15.482 INFO 17872 --- [ main] com.jjh.BeanLifeApplication : No active profile set, falling back to 1 default profile: "default"
2023-09-18 09:51:15.693 INFO 17872 --- [ main] com.jjh.component.BeanLifeCtrl : 执行了构造方法
2023-09-18 09:51:15.695 INFO 17872 --- [ main] com.jjh.component.BeanLifeCtrl : 依赖注入:java_home
2023-09-18 09:51:15.696 INFO 17872 --- [ main] com.jjh.component.BeanLifeCtrl : 构造后处理!
2023-09-18 09:51:15.742 INFO 17872 --- [ main] com.jjh.BeanLifeApplication : Started BeanLifeApplication in 0.444 seconds (JVM running for 1.274)
2023-09-18 09:51:15.745 INFO 17872 --- [ main] com.jjh.component.BeanLifeCtrl : 销毁前处理
三.自定义bean后处理器
这两个接口都实现了BeanPostProcessor接口
@Component
public class MYBeanPostPoccesser implements InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor {
private final static Logger log = LoggerFactory.getLogger(MYBeanPostPoccesser.class);
@Override
public void postProcessBeforeDestruction(Object o, String beanName) throws BeansException {
if("beanLifeCtrl".equals(beanName)){
log.info("在销毁前处理,如@PreDestory");
}
}
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if("beanLifeCtrl".equals(beanName)){
log.info("实例化之前执行,这里的bean会替换初始的bean");
}
return null;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if("beanLifeCtrl".equals(beanName)){
log.info("在实例化之后处理,如果返回false,则跳过依赖注入阶段");
}
return true;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if("beanLifeCtrl".equals(beanName)){
log.info("实例化之后处理,这里的bean会替换初始的bean");
}
return null;
}
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
if("beanLifeCtrl".equals(beanName)){
log.info("在依赖注入阶段执行,如@Autowired,@Resource");
}
return null;
}
}
我们在运行查看结果:
2023-09-18 10:24:03.251 INFO 19208 --- [ main] com.jjh.component.MYBeanPostPoccesser : 实例化之前执行,这里的bean会替换初始的bean
2023-09-18 10:24:03.252 INFO 19208 --- [ main] com.jjh.component.BeanLifeCtrl : 执行了构造方法
2023-09-18 10:24:03.253 INFO 19208 --- [ main] com.jjh.component.MYBeanPostPoccesser : 在实例化之后处理,如果返回false,则跳过依赖注入阶段
2023-09-18 10:24:03.253 INFO 19208 --- [ main] com.jjh.component.MYBeanPostPoccesser : 在依赖注入阶段执行,如@Autowired,@Resource
2023-09-18 10:24:03.255 INFO 19208 --- [ main] com.jjh.component.BeanLifeCtrl : 依赖注入:java_home
2023-09-18 10:24:03.256 INFO 19208 --- [ main] com.jjh.component.BeanLifeCtrl : 构造后处理!
2023-09-18 10:24:03.256 INFO 19208 --- [ main] com.jjh.component.MYBeanPostPoccesser : 实例化之后处理,这里的bean会替换初始的bean
2023-09-18 10:24:03.328 INFO 19208 --- [ main] com.jjh.BeanLifeApplication : Started BeanLifeApplication in 0.475 seconds (JVM running for 1.346)
2023-09-18 10:24:03.332 INFO 19208 --- [ main] com.jjh.component.MYBeanPostPoccesser : 在销毁前处理,如@PreDestory
2023-09-18 10:24:03.332 INFO 19208 --- [ main] com.jjh.component.BeanLifeCtrl : 销毁前处理
进程已结束,退出代码0
可以很清晰的看到执行顺序:
实例化之前处理器->构造方法->实例化之后处理器(判断是否跳过依赖注入)->依赖注入处理器->依赖注入->构造后处理->实例化之后处理器->销毁前处理器->销毁前处理
四.模板设计模式
我们可以把固定不变的流程设计为模板,其中动态变化的方法,我们可以通过接口,给它添加进去,在需要执行的方调用不同的实现方法
1,定义MyBeanPostPoccessor接口
interface MyBeanPostProcessor{
//依赖注入
void inject();
}
2.创建MyBeanFactory类
class MyBeanFactory{
private List<MyBeanPostProcessor> postProcessors = new ArrayList<>();
public Object getBean(){
Object bean = new Object();
System.out.println("构造方法");
System.out.println("依赖注入");
postProcessors.forEach(MyBeanPostProcessor::inject);
System.out.println("初始化");
return bean;
}
public void addProcessor(MyBeanPostProcessor postProcessor){
postProcessors.add(postProcessor);
}
}
我们在依赖注入之后执行需要的方法
3.我们给它添加这个后处理器,实现方法
MyBeanFactory beanFactory = new MyBeanFactory();
beanFactory.addProcessor(() -> System.out.println("@Autowired注解注入"));
beanFactory.addProcessor(()-> System.out.println("@Resource注解注入"));
beanFactory.getBean();
运行代码,查看结果:
构造方法
依赖注入
@Autowired注解注入
@Resource注解注入
初始化
可以看到,我们添加的方法执行了
五.Bean的后处理器
1.准备
我们知道,spring提供了很多注解,对应bean每个阶段的生命周期,那么我们来分析一下后处理器的执行流程
创建Bean1类
@Component
public class Bean1 {
private final static Logger log = LoggerFactory.getLogger(Bean1.class);
private Bean2 bean2;
@Resource
public void setBean2(Bean2 bean2){
this.bean2 = bean2;
log.info("@Resource生效....");
}
public Bean2 getBean2() {
return bean2;
}
public Bean1(){
log.info("执行构造方法....");
}
@Autowired
public void getName(@Value("${java_home}")String home){
log.info("@Autowired值注入:{}",home);
}
@PostConstruct
public void postConstruct(){
log.info("@PostConstruct生效...构造后处理");
}
@PreDestroy
public void preDestroy(){
log.info("@PreDestroy生效...销毁前处理");
}
}
创建Bean2类
@Component
public class Bean2 {
}
使用GenericApplicationContext作为容器,因为它比较干净,没有自己添加后处理器,方便测试
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("bean2", Bean2.class);
context.registerBean("bean1", Bean1.class);
//实例化bean
context.refresh();
//关闭bean
context.close();
运行查看结果:
11:30:40.165 [main] DEBUG org.springframework.context.support.GenericApplicationContext - Refreshing org.springframework.context.support.GenericApplicationContext@28ac3dc3
11:30:40.192 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean2'
11:30:40.204 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean1'
11:30:40.204 [main] INFO com.jjh.component.Bean1 - 执行构造方法....
11:30:40.230 [main] DEBUG org.springframework.context.support.GenericApplicationContext - Closing org.springframework.context.support.GenericApplicationContext@28ac3dc3, started on Mon Sep 18 11:30:40 CST 2023
发现只有构造方法被执行了,注解的方法并没有被执行,下面我们给它添加后处理器
2.添加AutowiredAnnotationBeanPostProcessor后处理器
它可以解析@Autowired,@Value
注意:我们需要在添加它之前设置AutowireCanidateResolver()为ContextAnnotationAutowiredCandidateResolver()解析器,否则无法解析Stirng的值
context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
查看结果;
11:35:13.221 [main] INFO com.jjh.component.Bean1 - 执行构造方法....
11:35:13.280 [main] WARN org.springframework.context.support.GenericApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'bean1': Unsatisfied dependency expressed through method 'getName' parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'java.lang.String' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Value(value="${java_home}")}
发现解析了@Autowired
3.添加CommonAnnotationBeanPostProcessor后处理器
它可以解析@Resource,@PostConstuct,@Predestory
context.registerBean(CommonAnnotationBeanPostProcessor.class);
查看结果:
11:37:17.371 [main] INFO com.jjh.component.Bean1 - 执行构造方法....
11:37:17.424 [main] INFO com.jjh.component.Bean1 - @Resource生效....
11:37:17.426 [main] WARN org.springframework.context.support.GenericApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'bean1': Unsatisfied dependency expressed through method 'getName' parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'java.lang.String' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Value(value="${java_home}")}
发现@Resource生效
4.Springboot中的@ConfigurationProperties注解
spirngboot可以通过该注解读取配置文件里的信息
(1)准备application.yml文件
java:
home: E:\java
version: 1.8
(2)创建Bean3类
@Component
@ConfigurationProperties(prefix = "java")
public class Bean3 {
private String home;
private String version;
public String getHome() {
return home;
}
public void setHome(String home) {
this.home = home;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
@Override
public String toString() {
return "Bean3{" +
"home='" + home + '\'' +
", version='" + version + '\'' +
'}';
}
}
(3)注册这个bean3,并读取观察信息
context.registerBean("bean3", Bean3.class);
//实例化bean
context.refresh();
//关闭bean
System.out.println(context.getBean("bean3"));
查看结果:
15:08:51.880 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean3'
Bean3{home='null', version='null'}
发现并没有解析@ConfigurationProperties
我们添加ConfigurationPropertiesBindingPostProcessor处理器
//解析spirngboot中的@ConfigurationPerporties
ConfigurationPropertiesBindingPostProcessor.register(context.getDefaultListableBeanFactory());
再次运行,查看:
15:16:11.916 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean3'
Bean3{home='E:\Java', version='11.0.14'}
发现成功的解析了该注解
六.AutowiredAnnotationBeanPostProcessor后处理器工作流程
我们知道它可以解析@Autowired和@Value注解,下面让我们看一下它的工作流程:
public class DigInAutowiredProcessorTest {
public static void main(String[] args) throws Throwable {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerSingleton("bean2",new Bean2());
//beanFactory.registerSingleton("bean1",new Bean1());
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
//设置${}解析器
beanFactory.addEmbeddedValueResolver(new StandardEnvironment()::resolvePlaceholders);
AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();
processor.setBeanFactory(beanFactory);
Bean1 bean1 = new Bean1();
processor.postProcessProperties(null,bean1,"bean1");
System.out.println(bean1);
查看一下运行结果:
15:54:03.689 [main] INFO com.jjh.component.Bean1 - 执行构造方法....
15:54:03.777 [main] DEBUG org.springframework.core.env.SystemEnvironmentPropertySource - PropertySource 'systemEnvironment' does not contain property 'java_home', but found equivalent 'JAVA_HOME'
15:54:03.777 [main] DEBUG org.springframework.core.env.PropertySourcesPropertyResolver - Found key 'java_home' in PropertySource 'systemEnvironment' with value of type String
15:54:03.778 [main] INFO com.jjh.component.Bean1 - @Autowired值注入:E:\java
com.jjh.component.Bean1@38d8f54a
最重要的方法是
processor.postProcessProperties(null,bean1,"bean1");
这个方法就是在依赖注入时注入值的,
我们看一下它的源码:
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
InjectionMetadata metadata = this.findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
metadata.inject(bean, beanName, pvs);
return pvs;
} catch (BeanCreationException var6) {
throw var6;
} catch (Throwable var7) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", var7);
}
}
这里的findAutowiringMetadata()方法是查找类的成员变量和方法上是否带上了@Autowired注解,
找到之后返回InjectionMetadata对象,然后调用metada.inject()方法来实现依赖注入,该方法需要三个参数,哪个bean,bean的名称,null
下面我们使用反射的方法来调用一下这个inject()方法:
//利用反射获取方法
Method findAutowiringMetadata = AutowiredAnnotationBeanPostProcessor.class.getDeclaredMethod("findAutowiringMetadata", String.class, Class.class, PropertyValues.class);
//调用该方法
findAutowiringMetadata.setAccessible(true);
//获取到metadata
InjectionMetadata metadata = (InjectionMetadata) findAutowiringMetadata.invoke(processor,"bean1",Bean1.class,null);
//调用inject方法注入依赖
metadata.inject(bean1,"bean1",null);
所有核心流程是:
1.先查找哪个成员变量和方法上注解了@Autowired
2.调用inject()方法对bean进行依赖注入
那么它是如何找到要注入的bean的呢?
我们先来看这三个:
@Autowired
private Bean4 bean4;
@Autowired
public void setBean2(Bean2 bean2){
this.bean2 = bean2;
log.info("@Autowired生效....");
}
@Autowired
public void setName(@Value("${java_home}")String home){
log.info("@Autowired值注入:{}",home);
}
这三个都需要找到要注入的bean,
//在成员变量上注入
Field bean4 = Bean1.class.getDeclaredField("bean4");
DependencyDescriptor descriptor1 = new DependencyDescriptor(bean4,false);
Object o = beanFactory.doResolveDependency(descriptor1, null, null, null);
System.out.println(o);
//在方法上注入
Method setBean2 = Bean1.class.getDeclaredMethod("setBean2", Bean2.class);
DependencyDescriptor descriptor2 =
new DependencyDescriptor(new MethodParameter(setBean2,0),false);
Object o1 = beanFactory.doResolveDependency(descriptor2, null, null, null);
System.out.println(o1);
//@Value注入
Method setHome = Bean1.class.getDeclaredMethod("setName", String.class);
DependencyDescriptor descriptor3 =
new DependencyDescriptor(new MethodParameter(setHome,0),false);
Object o2 = beanFactory.doResolveDependency(descriptor3, null, null, null);
System.out.println(o2);
主要是DependencyDescriptor类,
基本是就是先通过反射拿到被注解了的成员变量和方法,然后变量可以获取这个属性的类型,
方法可以根据他的参数找到类型,从而从容器中获取bean然后注入依赖
然后通过beanFactory.doResolveDependency()方法,来获取这个bean