Spring_让Spring 依赖注入彻底废掉
迪丽瓦拉
2024-05-30 01:09:58
0

在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 {@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {//生成beanGenericBeanDefinition 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);}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}
}

进入我们的实现类以后,我们会把我们需要实例化BeanDefinition的java类,通过自己写的代码的方式也给实例化成BeanDefinition对象。也就是说,我们的这个java类,即使没有在spring.xml中配置具体的; 也没有注解,无法通过扫描的方式获取到这个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-methodvoid init () {id = "001";name = "yy";}@Overridepublic 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 {@Autowiredprivate 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就给干废了。当前,对于一些简单的类,不涉及到任何的注入信息,那还是可以正常运行的。

相关内容