继续讨论BeanFactoryPostProcesso
beanFactoryPostProcessor有什么作用
顾名思义beanFactoryPostProcessor=bean工厂的后置处理器,主要是提供给程序员扩展的(当然了spring内部也对这个接口进行了各种实现,本文只讨论程序员如何扩展它);在spring容器运行期间可以让程序员对BeanFactory组件进行各种全局的设置,这便是这个处理器的作用;关于什么是beanFactory——中文翻译过来叫做bean工厂,其实也就是我们常常说的spring容器;这个处理器主要就是针对spring容器做一些配置;那么他能进行哪些配置呢?先看一下这个接口的定义和他的主要方法
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
其实这个接口(不考虑子类)他只有一个方法;也就是当程序员实现这个接口后,重写这个方法后,spring容器会在启动的时候调用你重写的这个方法,并且把ConfigurableListableBeanFactory
类的对象传给你;实际运行过程中传入的是个子类——DefaultListableBeanFactory
,当我们得到这beanFactory之后就能对这对象进行设置了,那么回到刚刚的问题,主要能进行哪些设置呢?这就要看DefaultListableBeanFactory
当中主要提供哪些API供我们调用了;他的api比较多,笔者并没有打算在一篇文章当中写完;会逐个分析他的一些重要的api
ignoreDependencyType
ignoreDependencyType
——忽略依赖注入的某个类型,存在父类当中ConfigurableListableBeanFactory
先看一下这方法发的定义和javadoc
/**
* Ignore the given dependency type for autowiring:
* for example, String. Default is none.
* @param type the dependency type to ignore
*/
void ignoreDependencyType(Class<?> type);
这个方法只有参数class类型的,比如你调用这个方法传入了一个B.class
则表示整个spring容器当中当遇到需要自动注入B的时候会被忽略,你注意看他的javadoc的说明,特别强调是自动注入的时候;接下来对这个方法来代码测试;
有类A和 类B 代码如下:
package com.spring.extension.beanFactoryPostProcessor.bean;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author 钢牌讲师-子路
* @date 2021/3/2218:41
*/
@Slf4j(topic = "e")
public class A {
B b;
public void setB(B b) {
this.b = b;
}
public void printInfo(){
log.debug("bean-b:{}",b);
}
}
--------------------------------------------------------------------------------------
package com.spring.extension.beanFactoryPostProcessor.bean;
import org.springframework.stereotype.Component;
public class B {
}
在一个A类当中由一个属性B,并且提供了setter方法,当中有一个
printInfo
方法主要来打印b是否有值
测试类代码如下:
@Slf4j(topic = "e")
public class TestBeanFactoryPostProcessor {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext();
Class[] clazz = new Class[]{A.class,B.class};
applicationContext.register(clazz);
applicationContext.refresh();
applicationContext.getBean(A.class).printInfo();
}
}
这里需要说明的是,我是把A.class和B.class直接注册给了spring容器
而没有采用平常那种通过配置类扫描的方式来启动spring容器
这么做的主要原因是因为我机器上的bean太多了,如果采用扫描可能会影响结果
通过这种手动注册方式,可以很方便的控制我的环境,和扫描没有区别
上面的代码比较简单,就是相当于spring容器当中扫描到了A和B两个类,然后调用A的printinfo方法打印看看b是否有值;讲道理这个时候b肯定等于null,因为虽然A当中由b属性,但是并没有通过任何手段去注入B,故而他肯定为null;运行过程和结果:
接下来给属性b加上@Autowired
注解再次允许b肯定不为null这个过于简单笔者变不截图做解释了;
跟着来测试ignoreDependencyType
这个api,新建一个类TestIgnoreDependencyType
让他实现BeanFactoryPostProcessor
这个接口,然后在postProcessBeanFactory
方法里面调用ignoreDependencyType
设置B.class,让所有bean在注入B类型的bean的时候忽略;代码如下:
/**
* @author 钢牌讲师-子路
* @date 2021/3/2218:39
* 主要来测试ignoreDependencyType 这个API
*/
@Slf4j(topic = "e")
public class TestIgnoreDependencyType implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
log.debug("TestIgnoreDependencyType--execute 测试这个方法是否被执行了");
//设置所有自动注入的属性如果类型为B则忽略
beanFactory.ignoreDependencyType(B.class);
}
}
跟着修改测试类,把TestIgnoreDependencyType这个类也加入到容器当中,因为如果你把这个类加入到容器则spring无法发现这个类(再次强调,为了保持环境的干净我没有用扫描,而是用到那个类就手动注册哪个类),修改后的测试类:
@Slf4j(topic = "e")
public class TestBeanFactoryPostProcessor {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext();
//多添加了一个类给spring容器
Class[] clazz = new Class[]{A.class,B.class,TestIgnoreDependencyType.class};
applicationContext.register(clazz);
applicationContext.refresh();
applicationContext.getBean(A.class).printInfo();
}
}
然后允许测试类,讲道理这个时候b要为null才符合spring提供这个方法的意义(忽略B类型的注入);
但是结果还是b不等于null;运行结果如下图:
为什么b还是不为null呢?原因有两
原因1、因为ignoreDependencyType
这个api上的javadoc有明确说明需要上自动注入的情况下才会生效,可能有人会说难道这里的b不是自动注入?确实不是这个我在前面那个毁三观的自动注入博文里面有解释,下面还有评论说@Autowired是自动注入;其实这里就更加能证明@Autowired不是自动注入,最多算半自动注入,所以导致了ignoreDependencyType
这个方法没有生效
我们先解决第一个问题,把A的自动注入模型改成自动注入;怎么改呢?其实这也是我们得到beanFactory
这个对象之后能够做的事情之一——修改beanDefinition
(前面我们提到,所谓的bean工厂处理器,到底能处理什么,修改一个beanDefintion其实也算我们做的处理之一);故而修改TestIgnoreDependencyType
的代码如下
/**
* @author 钢牌讲师-子路
* @date 2021/3/2218:39
* 主要来测试ignoreDependencyType 这个API
*/
@Slf4j(topic = "e")
public class TestIgnoreDependencyType implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
log.debug("TestIgnoreDependencyType--execute 测试这个方法是否被执行了");
//获取A的BeanDefinition
AnnotatedGenericBeanDefinition a =
(AnnotatedGenericBeanDefinition) beanFactory.getBeanDefinition("a");
//修改A这个bean的注入模型为自动注入bytype
a.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
//设置所有自动注入的属性如果类型为B则忽略
beanFactory.ignoreDependencyType(B.class);
}
}
然后再次运行,但是结果依然b不等于null,因为我们前面说过原因有两,目前我们只是解决了第一个原因,所以结果还是不等于null,结果如下图:
原因2、 A的模型虽然被改成了自动注入模型,但是b属性的注入模式还是手动注入,也就是属性看有单独体现注入模型,那么类的注入模型对这个被单独指定过注入模型的属性已经无效了,但是对其他没有被指定注入模型的属性还是生效的,比如A里面还有个属性x,而这个x,没有指定注入模型,则会沿用类的注入模型;所以得把b上面的注解去掉,那么就能生效了,这个时候b就等于null了;
运行结果如下图:
到这里我们已经看到了这个方法的作用了——为容器当中所有自动注入的bean忽略给定的类型依赖项;
当然有的人可能会认为b等于null可能不是因为beanFactory.ignoreDependencyType(B.class);
引起的;所以笔者还是不怕麻烦的再次证明一下,把这行代码删了再来看结果那么b肯定不等于null了(因为A的自动注入模型是自动注入,而你又提供了setter方法,故而b肯定能被注入进来);结果如下图:
好了到现在我们已经把ignoreDependencyType这个api彻底搞懂了;过几天更新其他api;接下来传销一波:传销之前先说一下笔者再写这篇博客的时候看到了一件非常欣慰的事情,是笔者自己的群里的网友聊天
非常感谢这位CSDN的博主对笔者的肯定,其实我以前讲的spring源码并没有达到自己的期望,因为以前在公司里面讲课又各种限制;所以一直没有讲好,甚至很多东西都一带而过;