手寫Spring,定義標記類型Aware接口,實現感知容器對象

做者:小傅哥
博客:https://bugstack.cnhtml

沉澱、分享、成長,讓本身和他人都能有所收穫!😄

1、前言

同事寫的代碼,我竟絲毫看不懂!java

大佬的代碼,就像 「賴蛤蟆泡青蛙,張的醜玩的花」:一個類實現了多個接口、繼承的類又繼承了其餘類、接口還能夠和接口繼承、實現接口的抽象類再由類實現抽象類方法、類A繼承的類B實現了類A實現的接口C,等等。程序員

看上去複雜又難懂的代碼,卻又能一次次知足需求的高效迭代和順利擴展,而像螺絲釘同樣搬磚的你,只是在大佬寫的代碼裏,完成某個接口下的一小塊功能,甚至寫完了也不知道怎麼就被調用運行了,整個過程像看 Spring 源碼同樣神奇,跳來跳去的摸不着頭緒!spring

其實這主要是由於你的代碼是否運用了設計模式,固然設計模式也沒那麼神奇,就像大家兩家都是120平米的房子,他家有三室兩廳一廚一衛,南北通透,全陽採光。但你家就不同了,你家是鍋碗瓢盆、衛浴馬桶、沙發茶几還有那1.8的雙人牀,在120平米的房子裏敞開了放,沒有動靜隔離,也沒有乾溼分離,純自由發揮。因此你的代碼看上去就亂的很!設計模式

2、目標

目前已實現的 Spring 框架,在 Bean 操做上能提供出的能力,包括:Bean 對象的定義和註冊,以及在操做 Bean 對象過程當中執行的,BeanFactoryPostProcessor、BeanPostProcessor、InitializingBean、DisposableBean,以及在 XML 新增的一些配置處理,讓咱們能夠 Bean 對象有更強的操做性。微信

那麼,若是咱們想得到 Spring 框架提供的 BeanFactory、ApplicationContext、BeanClassLoader等這些能力作一些擴展框架的使用時該怎麼操做呢。因此咱們本章節但願在 Spring 框架中提供一種能感知容器操做的接口,若是誰實現了這樣的一個接口,就能夠獲取接口入參中的各種能力。多線程

3、設計

若是說我但願拿到 Spring 框架中一些提供的資源,那麼首先須要考慮以一個什麼方式去獲取,以後你定義出來的獲取方式,在 Spring 框架中該怎麼去承接,實現了這兩項內容,就能夠擴展出你須要的一些屬於 Spring 框架自己的能力了。架構

在關於 Bean 對象實例化階段咱們操做過一些額外定義、屬性、初始化和銷燬的操做,其實咱們若是像獲取 Spring 一些如 BeanFactory、ApplicationContext 時,也能夠經過此類方式進行實現。那麼咱們須要定義一個標記性的接口,這個接口不須要有方法,它只起到標記做用就能夠,而具體的功能由繼承此接口的其餘功能性接口定義具體方法,最終這個接口就能夠經過 instanceof 進行判斷和調用了。總體設計結構以下圖:app

  • 定義接口 Aware,在 Spring 框架中它是一種感知標記性接口,具體的子類定義和實現能感知容器中的相關對象。也就是經過這個橋樑,向具體的實現類中提供容器服務
  • 繼承 Aware 的接口包括:BeanFactoryAware、BeanClassLoaderAware、BeanNameAware和ApplicationContextAware,固然在 Spring 源碼中還有一些其餘關於註解的,不過目前咱們仍是用不到。
  • 在具體的接口實現過程當中你能夠看到,一部分(BeanFactoryAware、BeanClassLoaderAware、BeanNameAware)在 factory 的 support 文件夾下,另外 ApplicationContextAware 是在 context 的 support 中,這是由於不一樣的內容獲取須要在不一樣的包下提供。因此,在 AbstractApplicationContext 的具體實現中會用到向 beanFactory 添加 BeanPostProcessor 內容的 ApplicationContextAwareProcessor 操做,最後由 AbstractAutowireCapableBeanFactory 建立 createBean 時處理相應的調用操做。關於 applyBeanPostProcessorsBeforeInitialization 已經在前面章節中實現過,若是忘記能夠往前翻翻

4、實現

1. 工程結構

small-spring-step-08
└── src
    ├── main
    │   └── java
    │       └── cn.bugstack.springframework
    │           ├── beans
    │           │   ├── factory
    │           │   │   ├── factory
    │           │   │   │   ├── AutowireCapableBeanFactory.java
    │           │   │   │   ├── BeanDefinition.java
    │           │   │   │   ├── BeanFactoryPostProcessor.java
    │           │   │   │   ├── BeanPostProcessor.java
    │           │   │   │   ├── BeanReference.java
    │           │   │   │   ├── ConfigurableBeanFactory.java
    │           │   │   │   └── SingletonBeanRegistry.java
    │           │   │   ├── support
    │           │   │   │   ├── AbstractAutowireCapableBeanFactory.java
    │           │   │   │   ├── AbstractBeanDefinitionReader.java
    │           │   │   │   ├── AbstractBeanFactory.java
    │           │   │   │   ├── BeanDefinitionReader.java
    │           │   │   │   ├── BeanDefinitionRegistry.java
    │           │   │   │   ├── CglibSubclassingInstantiationStrategy.java
    │           │   │   │   ├── DefaultListableBeanFactory.java
    │           │   │   │   ├── DefaultSingletonBeanRegistry.java
    │           │   │   │   ├── DisposableBeanAdapter.java
    │           │   │   │   ├── InstantiationStrategy.java
    │           │   │   │   └── SimpleInstantiationStrategy.java  
    │           │   │   ├── support
    │           │   │   │   └── XmlBeanDefinitionReader.java
    │           │   │   ├── Aware.java
    │           │   │   ├── BeanClassLoaderAware.java
    │           │   │   ├── BeanFactory.java
    │           │   │   ├── BeanFactoryAware.java
    │           │   │   ├── BeanNameAware.java
    │           │   │   ├── ConfigurableListableBeanFactory.java
    │           │   │   ├── DisposableBean.java
    │           │   │   ├── HierarchicalBeanFactory.java
    │           │   │   ├── InitializingBean.java
    │           │   │   └── ListableBeanFactory.java
    │           │   ├── BeansException.java
    │           │   ├── PropertyValue.java
    │           │   └── PropertyValues.java 
    │           ├── context
    │           │   ├── support
    │           │   │   ├── AbstractApplicationContext.java 
    │           │   │   ├── AbstractRefreshableApplicationContext.java 
    │           │   │   ├── AbstractXmlApplicationContext.java 
    │           │   │   ├── ApplicationContextAwareProcessor.java 
    │           │   │   └── ClassPathXmlApplicationContext.java 
    │           │   ├── ApplicationContext.java 
    │           │   ├── ApplicationContextAware.java 
    │           │   └── ConfigurableApplicationContext.java
    │           ├── core.io
    │           │   ├── ClassPathResource.java 
    │           │   ├── DefaultResourceLoader.java 
    │           │   ├── FileSystemResource.java 
    │           │   ├── Resource.java 
    │           │   ├── ResourceLoader.java 
    │           │   └── UrlResource.java
    │           └── utils
    │               └── ClassUtils.java
    └── test
        └── java
            └── cn.bugstack.springframework.test
                ├── bean
                │   ├── UserDao.java
                │   └── UserService.java
                └── ApiTest.java

工程源碼公衆號「bugstack蟲洞棧」,回覆:Spring 專欄,獲取完整源碼框架

Spring 感知接口的設計和實現類關係,如圖 9-2

圖 9-2

  • 以上整個類關係就是關於 Aware 感知的定義和對容器感知的實現。
  • Aware 有四個繼承的接口,其餘這些接口的繼承都是爲了繼承一個標記,有了標記的存在更方便類的操做和具體判斷實現。
  • 另外因爲 ApplicationContext 並非在 AbstractAutowireCapableBeanFactory 中 createBean 方法下的內容,因此須要像容器中註冊 addBeanPostProcessor ,再由 createBean 統一調用 applyBeanPostProcessorsBeforeInitialization 時進行操做。

2. 定義標記接口

cn.bugstack.springframework.beans.factory.Aware

/**
 * Marker superinterface indicating that a bean is eligible to be
 * notified by the Spring container of a particular framework object
 * through a callback-style method.  Actual method signature is
 * determined by individual subinterfaces, but should typically
 * consist of just one void-returning method that accepts a single
 * argument.
 *
 * 標記類接口,實現該接口能夠被Spring容器感知
 *
 */
public interface Aware {
}
  • 在 Spring 中有特別多相似這樣的標記接口的設計方式,它們的存在就像是一種標籤同樣,能夠方便統一摘取出屬於此類接口的實現類,一般會有 instanceof 一塊兒判斷使用。

3. 容器感知類

3.1 BeanFactoryAware

cn.bugstack.springframework.beans.factory.BeanFactoryAware

public interface BeanFactoryAware extends Aware {

   void setBeanFactory(BeanFactory beanFactory) throws BeansException;

}
  • Interface to be implemented by beans that wish to be aware of their owning {@link BeanFactory}.
  • 實現此接口,既能感知到所屬的 BeanFactory

3.2 BeanClassLoaderAware

cn.bugstack.springframework.beans.factory.BeanClassLoaderAware

public interface BeanClassLoaderAware extends Aware{

    void setBeanClassLoader(ClassLoader classLoader);

}
  • Callback that allows a bean to be aware of the bean{@link ClassLoader class loader}; that is, the class loader used by the present bean factory to load bean classes.
  • 實現此接口,既能感知到所屬的 ClassLoader

3.3 BeanNameAware

cn.bugstack.springframework.beans.factory.BeanNameAware

public interface BeanNameAware extends Aware {

    void setBeanName(String name);

}
  • Interface to be implemented by beans that want to be aware of their bean name in a bean factory.
  • 實現此接口,既能感知到所屬的 BeanName

3.4 ApplicationContextAware

cn.bugstack.springframework.context.ApplicationContextAware

public interface ApplicationContextAware extends Aware {

    void setApplicationContext(ApplicationContext applicationContext) throws BeansException;

}
  • Interface to be implemented by any object that wishes to be notifiedof the {@link ApplicationContext} that it runs in.
  • 實現此接口,既能感知到所屬的 ApplicationContext

4. 包裝處理器(ApplicationContextAwareProcessor)

cn.bugstack.springframework.context.support.ApplicationContextAwareProcessor

public class ApplicationContextAwareProcessor implements BeanPostProcessor {

    private final ApplicationContext applicationContext;

    public ApplicationContextAwareProcessor(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof ApplicationContextAware){
            ((ApplicationContextAware) bean).setApplicationContext(applicationContext);
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

}
  • 因爲 ApplicationContext 的獲取並不能直接在建立 Bean 時候就能夠拿到,因此須要在 refresh 操做時,把 ApplicationContext 寫入到一個包裝的 BeanPostProcessor 中去,再由 AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization 方法調用。

5. 註冊 BeanPostProcessor

cn.bugstack.springframework.context.support.AbstractApplicationContext

public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {

    @Override
    public void refresh() throws BeansException {
        // 1. 建立 BeanFactory,並加載 BeanDefinition
        refreshBeanFactory();

        // 2. 獲取 BeanFactory
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();

        // 3. 添加 ApplicationContextAwareProcessor,讓繼承自 ApplicationContextAware 的 Bean 對象都能感知所屬的 ApplicationContext
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

        // 4. 在 Bean 實例化以前,執行 BeanFactoryPostProcessor (Invoke factory processors registered as beans in the context.)
        invokeBeanFactoryPostProcessors(beanFactory);

        // 5. BeanPostProcessor 須要提早於其餘 Bean 對象實例化以前執行註冊操做
        registerBeanPostProcessors(beanFactory);

        // 6. 提早實例化單例Bean對象
        beanFactory.preInstantiateSingletons();
    }
    
     // ...   
}
  • refresh() 方法就是整個 Spring 容器的操做過程,與上一章節對比,本次新增長了關於 addBeanPostProcessor 的操做。
  • 添加 ApplicationContextAwareProcessor,讓繼承自 ApplicationContextAware 的 Bean 對象都能感知所屬的 ApplicationContext。

6. 感知調用操做

cn.bugstack.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {

    private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();

    @Override
    protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) throws BeansException {
        Object bean = null;
        try {
            bean = createBeanInstance(beanDefinition, beanName, args);
            // 給 Bean 填充屬性
            applyPropertyValues(beanName, bean, beanDefinition);
            // 執行 Bean 的初始化方法和 BeanPostProcessor 的前置和後置處理方法
            bean = initializeBean(beanName, bean, beanDefinition);
        } catch (Exception e) {
            throw new BeansException("Instantiation of bean failed", e);
        }

        // 註冊實現了 DisposableBean 接口的 Bean 對象
        registerDisposableBeanIfNecessary(beanName, bean, beanDefinition);

        addSingleton(beanName, bean);
        return bean;
    }

    private Object initializeBean(String beanName, Object bean, BeanDefinition beanDefinition) {

        // invokeAwareMethods
        if (bean instanceof Aware) {
            if (bean instanceof BeanFactoryAware) {
                ((BeanFactoryAware) bean).setBeanFactory(this);
            }
            if (bean instanceof BeanClassLoaderAware){
                ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
            }
            if (bean instanceof BeanNameAware) {
                ((BeanNameAware) bean).setBeanName(beanName);
            }
        }

        // 1. 執行 BeanPostProcessor Before 處理
        Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);

        // 執行 Bean 對象的初始化方法
        try {
            invokeInitMethods(beanName, wrappedBean, beanDefinition);
        } catch (Exception e) {
            throw new BeansException("Invocation of init method of bean[" + beanName + "] failed", e);
        }

        // 2. 執行 BeanPostProcessor After 處理
        wrappedBean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
        return wrappedBean;
    }



    @Override
    public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {
        Object result = existingBean;
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
            Object current = processor.postProcessBeforeInitialization(result, beanName);
            if (null == current) return result;
            result = current;
        }
        return result;
    }

    @Override
    public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException {
        Object result = existingBean;
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
            Object current = processor.postProcessAfterInitialization(result, beanName);
            if (null == current) return result;
            result = current;
        }
        return result;
    }

}
  • 這裏咱們去掉了一些類的內容,只保留關於本次 Aware 感知接口的操做。
  • 首先在 initializeBean 中,經過判斷 bean instanceof Aware,調用了三個接口方法,BeanFactoryAware.setBeanFactory(this)BeanClassLoaderAware.setBeanClassLoader(getBeanClassLoader())BeanNameAware.setBeanName(beanName),這樣就能通知到已經實現了此接口的類。
  • 另外咱們還向 BeanPostProcessor 中添加了 ApplicationContextAwareProcessor,此時在這個方法中也會被調用到具體的類實現,獲得一個 ApplicationContex 屬性。

5、測試

1. 事先準備

cn.bugstack.springframework.test.bean.UserDao

public class UserDao {

    private static Map<String, String> hashMap = new HashMap<>();

    public void initDataMethod(){
        System.out.println("執行:init-method");
        hashMap.put("10001", "小傅哥");
        hashMap.put("10002", "八杯水");
        hashMap.put("10003", "阿毛");
    }

    public void destroyDataMethod(){
        System.out.println("執行:destroy-method");
        hashMap.clear();
    }

    public String queryUserName(String uId) {
        return hashMap.get(uId);
    }

}

cn.bugstack.springframework.test.bean.UserService

public class UserService implements BeanNameAware, BeanClassLoaderAware, ApplicationContextAware, BeanFactoryAware {

    private ApplicationContext applicationContext;
    private BeanFactory beanFactory;

    private String uId;
    private String company;
    private String location;
    private UserDao userDao;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("Bean Name is:" + name);
    }

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        System.out.println("ClassLoader:" + classLoader);
    }

    // ...get/set
}
  • UserDao 本次並無什麼改變,仍是提供了關於初始化的方法,並在 Spring.xml 中提供 init-method、destroy-method 配置信息。
  • UserService 新增長,BeanNameAware, BeanClassLoaderAware, ApplicationContextAware, BeanFactoryAware,四個感知的實現類,並在類中實現相應的接口方法。

2. 配置文件

基礎配置,無BeanFactoryPostProcessor、BeanPostProcessor,實現類

<?xml version="1.0" encoding="UTF-8"?>
<beans>

    <bean id="userDao" class="cn.bugstack.springframework.test.bean.UserDao" init-method="initDataMethod" destroy-method="destroyDataMethod"/>

    <bean id="userService" class="cn.bugstack.springframework.test.bean.UserService">
        <property name="uId" value="10001"/>
        <property name="company" value="騰訊"/>
        <property name="location" value="深圳"/>
        <property name="userDao" ref="userDao"/>
    </bean>

</beans>
  • 本章節中並無額外新增長配置信息,與上一章節內容相同。

3. 單元測試

@Test
public void test_xml() {
    // 1.初始化 BeanFactory
    ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");
    applicationContext.registerShutdownHook();      

    // 2. 獲取Bean對象調用方法
    UserService userService = applicationContext.getBean("userService", UserService.class);
    String result = userService.queryUserInfo();
    System.out.println("測試結果:" + result);
    System.out.println("ApplicationContextAware:"+userService.getApplicationContext());
    System.out.println("BeanFactoryAware:"+userService.getBeanFactory());
}
  • 測試方法中主要是添加了一寫關於新增 Aware 實現的調用,其餘不須要調用的也打印了相應的日誌信息,能夠在測試結果中看到。

測試結果

執行:init-method
ClassLoader:sun.misc.Launcher$AppClassLoader@14dad5dc
Bean Name is:userService
測試結果:小傅哥,騰訊,深圳
ApplicationContextAware:cn.bugstack.springframework.context.support.ClassPathXmlApplicationContext@5ba23b66
BeanFactoryAware:cn.bugstack.springframework.beans.factory.support.DefaultListableBeanFactory@2ff4f00f
執行:destroy-method



Process finished with exit code 0
  • 從測試結果能夠看到,本章節新增長的感知接口對應的具體實現(BeanNameAware, BeanClassLoaderAware, ApplicationContextAware, BeanFactoryAware),已經能夠如期輸出結果了。

6、總結

  • 目前關於 Spring 框架的實現中,某些功能點已經越來趨向於完整,尤爲是 Bean 對象的生命週期,已經有了不少的體現。總體總結如圖 9-3

    圖 9-3

  • 本章節關於 Aware 的感知接口的四個繼承接口 BeanNameAware, BeanClassLoaderAware, ApplicationContextAware, BeanFactoryAware 的實現,又擴展了 Spring 的功能。若是你有作過關於 Spring 中間件的開發那麼必定會大量用到這些類,如今你不僅是用過,並且還知道他們都是何時觸達的,在之後想排查類的實例化順序也能夠有一個清晰的思路了。
  • 每一章節內容的實現都是在以設計模式爲核心的結構上填充各項模塊的功能,單純的操做編寫代碼並不會有太多收穫,必定是要理解爲何這麼設計,這麼設計的好處是什麼,怎麼就那麼多接口和抽象類的應用,這些纔是 Spring 框架學習的核心所在。

7、系列推薦

相關文章
相關標籤/搜索