在Spring之基于注解方式实例化BeanDefinition(1)_chen_yao_kerr的博客-CSDN博客中,我们在末尾处分享了一个甜点,就是关于实现了BeanDefinitionRegistryPostProcessor也可以实例化bean的操作,首先需要去了解一下那篇博客的甜点案例,直接搜索“BeanDefinitionRegistryPostProcessor”就能找到,接下来解释才会听的懂。
在我们Spring实例化BeanDefinition以后,并且在Spring实例化Bean之前,我们中间还有很多的功能性方法,这些方法中有一个名字叫 invokeBeanFactoryPostProcessors的方法,它就是提前预处理一些PostProcessor以及实现或继承了这些PostProcessor的类。
debug进去以后:
继续进入该方法,我们知道它是拿到了所有BeanDefinitionRegistryPostProcessor类型的类,然后进行一些具体逻辑的判断。比如: 它是否也实现了PriorityOrdered接口、Ordered接口等一些列的接口判断,并且进行各种各样的排序工作,功能很多。
而我们关注的就是BeanDefinitionRegistryPostProcessor接口,继续往下debug,我们发现他会针对BeanDefinitionRegistryPostProcessor接口调用getBean方法的调用。在上一篇Spring之实例化Bean(2)_chen_yao_kerr的博客-CSDN博客中,我们解释了getBean方法就是实例化Bean的方法。也就是说,在我们进行常规的Spring 实例化Bean操作之前,我们会针对实现了BeanDefinitionRegistryPostProcessor接口的类进行提前实例化,然后又调用了invokeBeanDefinitionRegistryPostProcessors方法:
进入invokeBeanDefinitionRegistryPostProcessors方法中:
而我们的实现类中正好也重写了此方法,因此,它必然会进入我们的实现类中:
package com.xiangxue.jack.postProcessor;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.stereotype.Component;
@Component
public class MyBeanPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
//生成bean
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(Dao2.class);
//给Dao2属性值赋值,这样实例化完成以后就会有值了.MutablePropertyValues有很多方法,
//也就意味着我们即使配置的类有错误,只要实现这个接口,我们依旧可以在类实例化之前,通过
//对beanDefinition进行修改,从而达到修改类的目的
MutablePropertyValues pValues = beanDefinition.getPropertyValues();
pValues.addPropertyValue("name", "yyds");
pValues.addPropertyValue("id", "测试001");
//我们给beanDefinition起了个 名字叫 dao2, 然后注册到spring容器中
registry.registerBeanDefinition("dao2", beanDefinition);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
进入我们的实现类以后,我们会把我们需要实例化BeanDefinition的java类,通过自己写的代码的方式也给实例化成BeanDefinition对象。也就是说,我们的这个java类,即使没有在spring.xml中配置具体的<bean>; 也没有注解,无法通过扫描的方式获取到这个java类的符合实例化BeanDefinition的class文件,我们依旧可以强行的让它实例化成BeanDefinition对象,然后实例化成Bean对象。
在Spring之实例化Bean(2)_chen_yao_kerr的博客-CSDN博客中,我们已经简单的介绍了实例化的主流程操作了,它就是拿到BeanDefinition对象进行实例化bean操作的。因此,咱们的实例化BeanDefinition操作完全符合实例化Bean的流程。
此方法不仅可以实现我们常用的实例化bean操作,而且还可以对spring想要实例化bean的对象进行属性的修改,甚至可以删除beanDefinition对象,让一些对象无法被spring实例化,想想就开心,可以干很多的坏事。
下面再分享一个甜点:InstantiationAwareBeanPostProcessor
刚刚我们说到了干坏事,而InstantiationAwareBeanPostProcessor接口可以让你一次性彻底把坏事做绝了。下面代码就是干坏事的代码:
package com.xiangxue.jack.postProcessor;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.stereotype.Component;
@Component
public class MyInstantiationAwareBeanPostProcessors implements InstantiationAwareBeanPostProcessor {
public boolean postProcessAfterInstantiation(Object bean, String beanName) {
//默认值是true,表示支持DI注册
//此时,我们设置位FALSE,那么spring的DI操作将彻底失效
return false;
}
}
现在,我们需要一些测试的Demo:
case1: 测试Dao是否可以被实例化
package com.xiangxue.jack.bean;
import org.springframework.stereotype.Repository;
import javax.annotation.PostConstruct;
@Repository
public class Dao {
private String name;
private String id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@PostConstruct //相当于init-method
void init () {
id = "001";
name = "yy";
}
@Override
public String toString() {
return "name :" + name + " id :" + id;
}
}
case2: 测试dao是否可以被注入
package com.xiangxue.jack.bean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class MyTestBean2 {
@Autowired
private Dao dao;
public void system () {
System.out.println(dao.toString());
}
}
开始我们的测试:
首先测试dao是否可以被初始化:结果是可以正常实例化的
接下来dao对象是否可以被正常注入:结果是否定的,不能注入
试想一下,Spring依赖注入都无法实现,那还要Spring干什么呢?而且这个错误,很难被发现,可谓是干坏事的鼻祖。
原理简单解析:
在上一篇Spring之实例化Bean(2)_chen_yao_kerr的博客-CSDN博客中,我们有一个方法没有讲解,那就是populateBean方法,它是依赖注入的核心方法,目的就是判断当前实例化的bean是否需要支持依赖注入的功能,里面有这么一段代码:
它的目的就是判断当前实例化完成的bean对象,是否需要支持依赖注入功能,默认是支持的。而我们重写了这个接口的默认值,直接设置成了FALSE,这就导致这个接口默认就不支持DI 依赖注入, 那还扯什么呢,直接把Spring就给干废了。当前,对于一些简单的类,不涉及到任何的注入信息,那还是可以正常运行的。