BeanFactoryPostProcessor扩展类的API调用分析

BeanFactoryPostProcessor

它是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);

ignoreDependencyType

这个方法是什么意思,怎么使用?

其实是:

不管那个哪个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);

ignoreDependencyInterface

这个方法。。。,看起来和上面那个差不多意思,其实不然

看代码

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的用处。

 

registerResolvableDependency

/**
	 * 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会因为多个实例而出现的错误。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值