它是bean工厂的处理器,主要是提供给程序员扩展的;在spring容器运行期间可以让程序员对BeanFactory组件进行设置;
这个咱们肯定都知道,BeanFactoryPostProcessor是Spring给程序员的个扩展点,而这个扩展点,是怎么扩展呢?可以看看这个接口
@FunctionalInterface
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
可以看到这个接口只有一个方法,而扩展点就是重写了这个方法,而重写这个方法用来干嘛呢,重点就在方法的参数上,这个ConfigurableListableBeanFactory里面,点进去看看,可以看到里面有几个方法,这个博客就是分析这几个方法。
/**
* 忽略给定的依赖类型进行自动装配:例如,字符串。默认为无。
* @param type the dependency type to ignore
*/
void ignoreDependencyType(Class> type);
这个方法是什么意思,怎么使用?
其实是:
不管那个哪个bean当中依赖了B这类,那么spring容器在启动的过程当中都不会自动装配B,但是这仅仅局限与这个依赖项为自动装配;
看代码
@Component
public class A {
B b;
public void setB(B b) {
this.b = b;
}
public void printInfo(){
System.out.println(b);;
}
}
@Component
public class B {
}
public class TestBeanFactoryPostProcessor {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(Config.class);
applicationContext.getBean(A.class).printInfo();
}
}
结果
null
Process finished with exit code 0
上面这段代码就是在A类里面,依赖了B对象,然后再main里面通过spring容器调用A对象里面的printInfo()方法返回null,说明b对象没有依赖注入进来,是因为A类的自动注入模式为默认的(不自动注入),所以b为null,接下来给b加上@Autowired 那么再次运行b肯定不等于null
com.spring.extension.beanFactoryPostProcessor.bean.B@776aec5c
Process finished with exit code 0
加了@Autowired就返回B对象,说明依赖注入成功
接下来就来试试ignoreDependencyType,
public class TestIgnoreDependencyType implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
//获取A的BeanDefinition
AnnotatedGenericBeanDefinition a =
(AnnotatedGenericBeanDefinition) beanFactory.getBeanDefinition("a");
//设置所有自动注入的属性如果类型为B则忽略
beanFactory.ignoreDependencyType(B.class);
}
}
继承这个接口,重写方法,通过调用ignoreDependencyType设置如果是自动注入的对象是B则忽略。BeanFactoryPostProcessor是bean工厂,能够获得进入到IOC容器里的BeanDefinition,这些之后应该会写博客吧,先不说。所以设置了后,当我们再启动main,应该不会得到b对象吧?
com.spring.extension.beanFactoryPostProcessor.bean.B@776aec5c
Process finished with exit code 0
然而不是,依旧得到了B对象,为啥呢?难道这个API是假的吗?
其实不是,而是这个咱们加了@Autowired这个注解,可以看ignoreDependencyType方法上面写的注解,它是要忽略自动注入的属性,而@Autowired它其实不是自动注入,它是手动注入,所以这个API没有生效,那么将A里面的B改为自动注入试试。
public class TestIgnoreDependencyType implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
//获取A的BeanDefinition
ScannedGenericBeanDefinition a =
(ScannedGenericBeanDefinition) beanFactory.getBeanDefinition("a");
//修改A这个bean的注入模型为自动注入bytype
a.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
//设置所有自动注入的属性如果类型为B则忽略
beanFactory.ignoreDependencyType(B.class);
}
}
加了自动注入,不调用这个API就可以得到B,
调用这个API不加@Autowired返回的就是null
void ignoreDependencyInterface(Class> ifc);
这个方法。。。,看起来和上面那个差不多意思,其实不然
看代码
public interface C {
}
@Component
public class D implements C{
}
@Component
public class A {
C d;
public void setD(D d) {
this.d = d;
}
public void printInfo(){
System.out.println(d);;
}
}
@Component
public class TestIgnoreDependencyInterface implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
ScannedGenericBeanDefinition a =
(ScannedGenericBeanDefinition) beanFactory.getBeanDefinition("a");
a.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_NAME);
//设置忽略X接口--什么意思呢?
beanFactory.ignoreDependencyInterface(C.class);
}
}
讲道理,这个是自动注入,也调用了这个接口,应该就会忽略掉吧,可是呢
com.spring.extension.beanFactoryPostProcessor.bean.D@7bedc48a
Process finished with exit code 0
它返回出了D的bean对象,为啥呢?看代码
@Component
public class W implements X{
Y y;
@Override
public void setY(Y y) {
this.y = y;
}
public void printInfo(){
System.out.println(y);;
}
}
public interface X {
public void setY(Y y);
}
@Component
public class Y {
}
@Component
public class TestIgnoreDependencyInterface implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
ScannedGenericBeanDefinition w =
(ScannedGenericBeanDefinition) beanFactory.getBeanDefinition("w");
w.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_NAME);
//设置忽略X接口--什么意思呢?
//beanFactory.ignoreDependencyInterface(W.class);
}
}
public class TestBeanFactoryPostProcessor {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(Config.class);
applicationContext.getBean(W.class).printInfo();
}
}
这里是把这个API注释了
com.spring.extension.beanFactoryPostProcessor.bean.Y@77f1baf5
Process finished with exit code 0
可以看到Y是注入到W里面了,而取消注释会发现输出null
所以这个API的作用的实现方式有点特殊
如果你的类A实现了接口B,那么在类A完成自动自动注入的时候会去调用setter方法,但是如果你的setter方法在接口B中定义了则忽略;比如上文中的W实现了X的setY,而X刚好自己也要setY,和X接口的当中的setY重复了或者说相同了,那么这个setY就失效了,不会对Y进行自动注入了;当然不是所有这种情况都会失效你必须指定beanFactory.ignoreDependencyInterface(X.class);
spring为什么要这么设计呢?可以看看spring源码里面,在哪调用了这个API
可以看看refresh里面的prepareBeanFactory方法
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
里面多次用到了这个API,而这些xxxxxAware类,可以看到都是接口,而且里面都有一个setxxx方法,可想而知,咋们这也是一个扩展类,如果咋们搞个类实现这个xxxxAware接口,重写setxxxx方法,那么这个类就无法自动注入属性进去,这样是防止啥呢,可以随便点进去一个xxxxAware接口,点最熟悉的ApplicationContextAware接口吧
public interface ApplicationContextAware extends Aware {
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
可以看到传进去的是咋们spring的上下文,如果这时候想注入属性,那么难道注入ApplicationContext对象进去吗?这可是spring的“上下文”,注入了个空进去了,那还叫spring上下文吗,所以spring为了防止ApplicationContext对象的注入,做了这么一件事情。
这就是这个API的用处。
/**
* Register a special dependency type with corresponding autowired value.
*/
void registerResolvableDependency(Class> dependencyType, @Nullable Object autowiredValue);
给指定类型的依赖注入项一个特定的值,看代码
@Component
public class A {
@Autowired
C c;
public void setC(C c) {
this.c = c;
}
public void printInfo(){
System.out.println(c);;
}
}
@Component
public interface C {
}
@Component
public class D implements C{
}
@Component
public class E implements C {
}
@Component
public class TestRegisterResolvableDependency implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
//表示只要遇到需要注入C类型的依赖,就new一个D给他
beanFactory.registerResolvableDependency(C.class,new D());
}
}
public class TestBeanFactoryPostProcessor {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(Config.class);
applicationContext.getBean(A.class).printInfo();
}
}
返回
com.spring.extension.beanFactoryPostProcessor.bean.D@3ecd23d9
Process finished with exit code 0
这个很容易懂吧,如果不加这个API,会报错,因为spring会因为多个实例而出现的错误。