曹工雜談:爲何不多須要改Spring源碼,由於擴展點太多了,說說Spring的後置處理器

前言

最近發了好幾篇,都是覆蓋框架源碼,可是spring的代碼,我是從沒覆蓋過,畢竟,若是方便擴展,沒誰想去改源碼,而spring就是不須要改源碼的那個,真的是「對擴展開放,對修改關閉」的典範。java

就我說曾經用過的,spring的擴展點,就包括了listenerbeanFactoryPostProcessorbeanPostProcessor,而spring boot的擴展點,除了propertiesymljava config覆蓋自動配置、org.springframework.boot.CommandLineRunner,還包括了META-INF下的spring.factory等。web

眼下就有之前的一個例子:spring

此次,只簡單說說後置處理器,主要是beanFactoryPostProcessorbeanPostProcessorapp

先說說beanFactoryPostProcessor

這兩個比較像,都是後置處理器,可是處理的對象不一樣,前者是針對beanFactory,後者是針對bean實例。框架

beanFactoryPostProcessor的註釋以下:ide

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進行修改。post

bean definition定義

所謂的bean definition呢,就是bean的元數據,好比bean的name、scope、class、是否延遲初始化(is-lazy-init)、依賴的bean等等。ui

負責維護bean definition 的註冊表

bean definition放在哪裏呢,就在org.springframework.beans.factory.support.BeanDefinitionRegistry裏,看名字能夠知道,這是一個註冊表,具體存儲來講,通常會選擇咱們熟悉的hashmap,key是beanDefinition的類名,value就是beanDefinitionthis

固然,這只是個接口,其提供了增刪改查的方法:lua

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;
    }
}

下面是我這邊運行的效果:

總結

相同點

一、操做對象不一樣

前面也說了,beanFactoryPostProcessor對bean的圖紙進行修改,beanPostProcessor則是對生產出來的東西,進行修改或者替換(爲何說替換,由於也可能照着生產出來的產品,搞一個代理,好比aop就是基於此實現。)

二、生效時機不一樣

相同點

相同點呢,就是,這都是spring給咱們提供出來的擴展點,至關方便,不是嗎?

相關文章
相關標籤/搜索