前言
最近發了好幾篇,都是覆蓋框架源碼,但是spring的代碼,我是從沒覆蓋過,畢竟,如果方便擴展,沒誰想去改源碼,而spring就是不需要改源碼的那個,真的是“對擴展開放,對修改關閉”的典范。
就我說曾經用過的,spring的擴展點,就包括了listener
、beanFactoryPostProcessor
、beanPostProcessor
,而spring boot的擴展點,除了properties
、yml
、java config
覆蓋自動配置、org.springframework.boot.CommandLineRunner
,還包括了META-INF
下的spring.factory
等。
眼下就有以前的一個例子:
這次,只簡單說說后置處理器,主要是beanFactoryPostProcessor
、beanPostProcessor
。
先說說beanFactoryPostProcessor
這兩個比較像,都是后置處理器,但是處理的對象不同,前者是針對beanFactory,后者是針對bean實例。
beanFactoryPostProcessor
的注釋如下:
Allows for custom modification of an application context's bean definitions, adapting the bean property values of the context's underlying bean factory.
Application contexts can auto-detect BeanFactoryPostProcessor beans in their bean definitions and apply them before any other beans get created.
Useful for custom config files targeted at system administrators that override bean properties configured in the application context.
See PropertyResourceConfigurer and its concrete implementations for out-of-the-box solutions that address such configuration needs.
A BeanFactoryPostProcessor may interact with and modify bean definitions, but never bean instances. Doing so may cause premature bean instantiation, violating the container and causing unintended side-effects. If bean instance interaction is required, consider implementing BeanPostProcessor instead.
簡單來說,允許對bean definition
進行修改。
bean definition定義
所謂的bean definition
呢,就是bean的元數據,比如bean的name、scope、class、是否延遲初始化(is-lazy-init)、依賴的bean等等。
負責維護bean definition 的注冊表
bean definition
放在哪里呢,就在org.springframework.beans.factory.support.BeanDefinitionRegistry
里,看名字可以知道,這是一個注冊表,具體存儲來說,一般會選擇我們熟悉的hashmap
,key是beanDefinition
的類名,value就是beanDefinition
。
當然,這只是個接口,其提供了增刪改查的方法:
public interface BeanDefinitionRegistry extends AliasRegistry {
//注冊bean Definition
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException;
//刪除bean Definition
void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
//獲取beanDefinition
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
//判斷是否包含指定的bean Definition
boolean containsBeanDefinition(String beanName);
//獲取所有的beanDefinition的名稱
String[] getBeanDefinitionNames();
//獲取beanDefinition的數量
int getBeanDefinitionCount();
}
那我們再看看這個接口的實現:
這里面可以看出來,ApplicationContext
就是這個接口的實現,這里可以稍微看下registerBean
的實現:
org.springframework.context.support.GenericApplicationContext#registerBeanDefinition
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
//代理給beanFactory
this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
}
這里的beanFactory類型為:org.springframework.beans.factory.support.DefaultListableBeanFactory
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition){
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
//...省略無關代碼
//往hashmap里存放beanName--》beanDefinition
this.beanDefinitionMap.put(beanName, beanDefinition);
}
//...省略無關代碼
}
beanFactoryPostProcessor`的實現類
經過上面的介紹,想來大家比較了解beanFactoryPostProcessor
了,我們看看這個接口的實現類呢:
拿以上實現類來說,
org.springframework.boot.web.servlet.ServletComponentRegisteringPostProcessor
:
這個是處理ServletComponentScan
注解,將@WebServlet
,@WebFilter
等注解的servlet組件,注冊到applicationContext
。
默認情況下,spring boot web應用,會有如下這個實現類:
org.springframework.context.annotation.ConfigurationClassPostProcessor
主要就是用於處理@Configuration
注解的java類。
org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanFactory
/**
* Prepare the Configuration classes for servicing bean requests at runtime
* by replacing them with CGLIB-enhanced subclasses.
*/
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
int factoryId = System.identityHashCode(beanFactory);
this.factoriesPostProcessed.add(factoryId);
if (!this.registriesPostProcessed.contains(factoryId)) {
// BeanDefinitionRegistryPostProcessor hook apparently not supported...
// Simply call processConfigurationClasses lazily at this point then.
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
}
//對configuration注解的類進行cglib代理,保證@bean注解的方法,即使多次調用,也只會有一個實例
enhanceConfigurationClasses(beanFactory);
//新增一個bean后置處理器
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
自定義beanFactoryPostProcessor,並使之生效
很簡單,像下面這樣,定義一個類,實現BeanFactoryPostProcessor
,並保證被掃描到即可。
@Component
@Slf4j
public class CustomBeanDefinitionPostProcessor implements BeanFactoryPostProcessor{
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinition definition = beanFactory.getBeanDefinition("customBeanDefinitionPostProcessor");
log.info("definition:{}",definition);
}
}
啟動時,輸出如下:
11-12 15:49:48.627 [restartedMain] INFO c.c.cad.config.CustomBeanDefinitionPostProcessor
- definition:Generic bean: class [com.ceiec.cad.config.CustomBeanDefinitionPostProcessor]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in file [F:\working_code\****\CustomBeanDefinitionPostProcessor.class] [CustomBeanDefinitionPostProcessor.java:20]
再說說beanPostProcessor
接口定義
Factory hook that allows for custom modification of new bean instances, e.g. checking for marker interfaces or wrapping them with proxies.
ApplicationContexts can autodetect BeanPostProcessor beans in their bean definitions and apply them to any beans subsequently created. Plain bean factories allow for programmatic registration of post-processors, applying to all beans created through this factory.
Typically, post-processors that populate beans via marker interfaces or the like will implement postProcessBeforeInitialization(java.lang.Object, java.lang.String), while post-processors that wrap beans with proxies will normally implement postProcessAfterInitialization(java.lang.Object, java.lang.String).
//對bean的實例進行修改,或者用一個代理來包裝它們,這個和上面的重要差別就出來了,一個是在bean還沒實例化之前,處理beanFactory里的bean definition;一個是處理實例化后的bean。
public interface BeanPostProcessor {
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
接口的實現類
以上有大家熟悉的,比如 ApplicationContextAwareProcessor
:
org.springframework.context.support.ApplicationContextAwareProcessor#invokeAwareInterfaces
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof Aware) {
//....省略無關
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
}
aop代理的實現
另一個廣泛應用的,就是aop用到的org.springframework.aop.framework.AbstractAdvisingBeanPostProcessor
AbstractAdvisingBeanPostProcessor#postProcessAfterInitialization
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (this.advisor == null || bean instanceof AopInfrastructureBean) {
// Ignore AOP infrastructure such as scoped proxies.
return bean;
}
if (bean instanceof Advised) {
Advised advised = (Advised) bean;
if (!advised.isFrozen() && isEligible(AopUtils.getTargetClass(bean))) {
// Add our local Advisor to the existing proxy's Advisor chain...
if (this.beforeExistingAdvisors) {
advised.addAdvisor(0, this.advisor);
}
else {
advised.addAdvisor(this.advisor);
}
return bean;
}
}
if (isEligible(bean, beanName)) {
ProxyFactory proxyFactory = prepareProxyFactory(bean, beanName);
//是否對目標類進行代理(cglib),如果不是的話,則獲取bean的接口,進行接口代理,即jdk代理
if (!proxyFactory.isProxyTargetClass()) {
evaluateProxyInterfaces(bean.getClass(), proxyFactory);
}
proxyFactory.addAdvisor(this.advisor);
customizeProxyFactory(proxyFactory);
return proxyFactory.getProxy(getProxyClassLoader());
}
// No proxy needed.
return bean;
}
protected ProxyFactory prepareProxyFactory(Object bean, String beanName) {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
proxyFactory.setTarget(bean);
return proxyFactory;
}
自定義beanPostProcessor,並生效
很簡單,直接在你的代碼里,像下面這樣寫一個類,實現BeanPostProcessor
,並保證被掃描到即可。
@Component
@Slf4j
public class CustomBeanPostProcessor implements BeanPostProcessor{
@Nullable
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof RabbitTemplate) {
log.info("hahah RabbitTemplate");
}
return bean;
}
}
下面是我這邊運行的效果:
總結
相同點
1、操作對象不同
前面也說了,beanFactoryPostProcessor對bean的圖紙進行修改,beanPostProcessor則是對生產出來的東西,進行修改或者替換(為什么說替換,因為也可能照着生產出來的產品,搞一個代理,比如aop就是基於此實現。)
2、生效時機不同
相同點
相同點呢,就是,這都是spring給我們提供出來的擴展點,相當方便,不是嗎?