新聞中心
[[407936]]
本文轉(zhuǎn)載自微信公眾號「bugstack蟲洞棧」,作者小傅哥 。轉(zhuǎn)載本文請聯(lián)系bugstack蟲洞棧公眾號。

目前創(chuàng)新互聯(lián)已為成百上千家的企業(yè)提供了網(wǎng)站建設(shè)、域名、虛擬空間、網(wǎng)站托管運(yùn)營、企業(yè)網(wǎng)站設(shè)計、婺源網(wǎng)站維護(hù)等服務(wù),公司將堅持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。
目錄
- 一、前言
- 二、目標(biāo)
- 三、設(shè)計
- 四、實現(xiàn)
- 1. 工程結(jié)構(gòu)
- 2. 定義標(biāo)記接口
- 3. 容器感知類
- 4. 包裝處理器(ApplicationContextAwareProcessor)
- 5. 注冊 BeanPostProcessor
- 6. 感知調(diào)用操作
- 五、測試
- 1. 事先準(zhǔn)備
- 2. 配置文件
- 3. 單元測試
- 六、總結(jié)
一、前言
同事寫的代碼,我竟絲毫看不懂!
大佬的代碼,就像“賴蛤蟆泡青蛙,張的丑玩的花”:一個類實現(xiàn)了多個接口、繼承的類又繼承了其他類、接口還可以和接口繼承、實現(xiàn)接口的抽象類再由類實現(xiàn)抽象類方法、類A繼承的類B實現(xiàn)了類A實現(xiàn)的接口C,等等。
看上去復(fù)雜又難懂的代碼,卻又能一次次滿足需求的高效迭代和順利擴(kuò)展,而像螺絲釘一樣搬磚的你,只是在大佬寫的代碼里,完成某個接口下的一小塊功能,甚至寫完了也不知道怎么就被調(diào)用運(yùn)行了,整個過程像看 Spring 源碼一樣神奇,跳來跳去的摸不著頭緒!
其實這主要是因為你的代碼是否運(yùn)用了設(shè)計模式,當(dāng)然設(shè)計模式也沒那么神奇,就像你們兩家都是120平米的房子,他家有三室兩廳一廚一衛(wèi),南北通透,全陽采光。但你家就不一樣了,你家是鍋碗瓢盆、衛(wèi)浴馬桶、沙發(fā)茶幾還有那1.8的雙人床,在120平米的房子里敞開了放,沒有動靜隔離,也沒有干濕分離,純自由發(fā)揮。所以你的代碼看上去就亂的很!
二、目標(biāo)
目前已實現(xiàn)的 Spring 框架,在 Bean 操作上能提供出的能力,包括:Bean 對象的定義和注冊,以及在操作 Bean 對象過程中執(zhí)行的,BeanFactoryPostProcessor、BeanPostProcessor、InitializingBean、DisposableBean,以及在 XML 新增的一些配置處理,讓我們可以 Bean 對象有更強(qiáng)的操作性。
那么,如果我們想獲得 Spring 框架提供的 BeanFactory、ApplicationContext、BeanClassLoader等這些能力做一些擴(kuò)展框架的使用時該怎么操作呢。所以我們本章節(jié)希望在 Spring 框架中提供一種能感知容器操作的接口,如果誰實現(xiàn)了這樣的一個接口,就可以獲取接口入?yún)⒅械母黝惸芰Α?/p>
三、設(shè)計
如果說我希望拿到 Spring 框架中一些提供的資源,那么首先需要考慮以一個什么方式去獲取,之后你定義出來的獲取方式,在 Spring 框架中該怎么去承接,實現(xiàn)了這兩項內(nèi)容,就可以擴(kuò)展出你需要的一些屬于 Spring 框架本身的能力了。
在關(guān)于 Bean 對象實例化階段我們操作過一些額外定義、屬性、初始化和銷毀的操作,其實我們?nèi)绻瘾@取 Spring 一些如 BeanFactory、ApplicationContext 時,也可以通過此類方式進(jìn)行實現(xiàn)。那么我們需要定義一個標(biāo)記性的接口,這個接口不需要有方法,它只起到標(biāo)記作用就可以,而具體的功能由繼承此接口的其他功能性接口定義具體方法,最終這個接口就可以通過 instanceof 進(jìn)行判斷和調(diào)用了。整體設(shè)計結(jié)構(gòu)如下圖:
- 定義接口 Aware,在 Spring 框架中它是一種感知標(biāo)記性接口,具體的子類定義和實現(xiàn)能感知容器中的相關(guān)對象。也就是通過這個橋梁,向具體的實現(xiàn)類中提供容器服務(wù)
- 繼承 Aware 的接口包括:BeanFactoryAware、BeanClassLoaderAware、BeanNameAware和ApplicationContextAware,當(dāng)然在 Spring 源碼中還有一些其他關(guān)于注解的,不過目前我們還是用不到。
- 在具體的接口實現(xiàn)過程中你可以看到,一部分(BeanFactoryAware、BeanClassLoaderAware、BeanNameAware)在 factory 的 support 文件夾下,另外 ApplicationContextAware 是在 context 的 support 中,這是因為不同的內(nèi)容獲取需要在不同的包下提供。所以,在 AbstractApplicationContext 的具體實現(xiàn)中會用到向 beanFactory 添加 BeanPostProcessor 內(nèi)容的 ApplicationContextAwareProcessor 操作,最后由 AbstractAutowireCapableBeanFactory 創(chuàng)建 createBean 時處理相應(yīng)的調(diào)用操作。關(guān)于 applyBeanPostProcessorsBeforeInitialization 已經(jīng)在前面章節(jié)中實現(xiàn)過,如果忘記可以往前翻翻
四、實現(xiàn)
1. 工程結(jié)構(gòu)
- 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
Spring 感知接口的設(shè)計和實現(xiàn)類關(guān)系,如圖 9-2
圖 9-2
- 以上整個類關(guān)系就是關(guān)于 Aware 感知的定義和對容器感知的實現(xiàn)。
- Aware 有四個繼承的接口,其他這些接口的繼承都是為了繼承一個標(biāo)記,有了標(biāo)記的存在更方便類的操作和具體判斷實現(xiàn)。
- 另外由于 ApplicationContext 并不是在 AbstractAutowireCapableBeanFactory 中 createBean 方法下的內(nèi)容,所以需要像容器中注冊 addBeanPostProcessor ,再由 createBean 統(tǒng)一調(diào)用 applyBeanPostProcessorsBeforeInitialization 時進(jìn)行操作。
2. 定義標(biāo)記接口
- /**
- * 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.
- *
- * 標(biāo)記類接口,實現(xiàn)該接口可以被Spring容器感知
- *
- */
- public interface Aware {
- }
在 Spring 中有特別多類似這樣的標(biāo)記接口的設(shè)計方式,它們的存在就像是一種標(biāo)簽一樣,可以方便統(tǒng)一摘取出屬于此類接口的實現(xiàn)類,通常會有 instanceof 一起判斷使用。
3. 容器感知類
3.1 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}.
- 實現(xiàn)此接口,既能感知到所屬的 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.
- 實現(xiàn)此接口,既能感知到所屬的 ClassLoader
3.3 BeanNameAware
cn.bugstack.springframework.beans.factory.BeanNameAware
- public interface BeanClassLoaderAware extends Aware{
- void setBeanClassLoader(ClassLoader classLoader);
- }
- Interface to be implemented by beans that want to be aware of their bean name in a bean factory.
- 實現(xiàn)此接口,既能感知到所屬的 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.
- 實現(xiàn)此接口,既能感知到所屬的 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 的獲取并不能直接在創(chuàng)建 Bean 時候就可以拿到,所以需要在 refresh 操作時,把 ApplicationContext 寫入到一個包裝的 BeanPostProcessor 中去,再由 AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization 方法調(diào)用。
5. 注冊 BeanPostProcessor
cn.bugstack.springframework.context.support.AbstractApplicationContext
- public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
- @Override
- public void refresh() throws BeansException {
- // 1. 創(chuàng)建 BeanFactory,并加載 BeanDefinition
- refreshBeanFactory();
- // 2. 獲取 BeanFactory
- ConfigurableListableBeanFactory beanFactory = getBeanFactory();
- // 3. 添加 ApplicationContextAwareProcessor,讓繼承自 ApplicationContextAware 的 Bean 對象都能感知所屬的 ApplicationContext
- beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
- // 4. 在 Bean 實例化之前,執(zhí)行 BeanFactoryPostProcessor (Invoke factory processors registered as beans in the context.)
- invokeBeanFactoryPostProcessors(beanFactory);
- // 5. BeanPostProcessor 需要提前于其他 Bean 對象實例化之前執(zhí)行注冊操作
- registerBeanPostProcessors(beanFactory);
- // 6. 提前實例化單例Bean對象
- beanFactory.preInstantiateSingletons();
- }
- // ...
- }
- refresh() 方法就是整個 Spring 容器的操作過程,與上一章節(jié)對比,本次新增加了關(guān)于 addBeanPostProcessor 的操作。
- 添加 ApplicationContextAwareProcessor,讓繼承自 ApplicationContextAware 的 Bean 對象都能感知所屬的 ApplicationContext。
6. 感知調(diào)用操作
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);
- // 執(zhí)行 Bean 的初始化方法和 BeanPostProcessor 的前置和后置處理方法
- bean = initializeBean(beanName, bean, beanDefinition);
- } catch (Exception e) {
- throw new BeansException("Instantiation of bean failed", e);
- }
- // 注冊實現(xiàn)了 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. 執(zhí)行 BeanPostProcessor Before 處理
- Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);
- // 執(zhí)行 Bean 對象的初始化方法
- try {
- invokeInitMethods(beanName, wrappedBean, beanDefinition);
- } catch (Exception e) {
- throw new BeansException("Invocation of init method of bean[" + beanName + "] failed", e);
- }
- // 2. 執(zhí)行 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;
- }
- }
- 這里我們?nèi)サ袅艘恍╊惖膬?nèi)容,只保留關(guān)于本次 Aware 感知接口的操作。
- 首先在 initializeBean 中,通過判斷 bean instanceof Aware,調(diào)用了三個接口方法,BeanFactoryAware.setBeanFactory(this)、BeanClassLoaderAware.setBeanClassLoader(getBeanClassLoader())、BeanNameAware.setBeanName(beanName),這樣就能通知到已經(jīng)實現(xiàn)了此接口的類。
- 另外我們還向 BeanPostProcessor 中添加了 ApplicationContextAwareProcessor,此時在這個方法中也會被調(diào)用到具體的類實現(xiàn),得到一個 ApplicationContex 屬性。
五、測試
1. 事先準(zhǔn)備
cn.bugstack.springframework.test.bean.UserDao
- public class UserDao {
- private static Map
hashMap = new HashMap<>(); - public void initDataMethod(){
- System.out.println("執(zhí)行:init-method");
- hashMap.put("10001", "小傅哥");
- hashMap.put("10002", "八杯水");
- hashMap.put("10003", "阿毛");
- }
- public void destroyDataMethod(){
- System.out.println("執(zhí)行: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 本次并沒有什么改變,還是提供了關(guān)于初始化的方法,并在 Spring.xml 中提供 init-method、destroy-method 配置信息。
UserService 新增加,BeanNameAware, BeanClassLoaderAware, ApplicationContextAware, BeanFactoryAware,四個感知的實現(xiàn)類,并在類中實現(xiàn)相應(yīng)的接口方法。
2. 配置文件
基礎(chǔ)配置,無BeanFactoryPostProcessor、BeanPostProcessor,實現(xiàn)類
本章節(jié)中并沒有額外新增加配置信息,與上一章節(jié)內(nèi)容相同。
3. 單元測試
- @Test
- public void test_xml() {
- // 1.初始化 BeanFactory
- ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");
- applicationContext.registerShutdownHook();
- // 2. 獲取Bean對象調(diào)用方法
- UserService userService = applicationContext.getBean("userService", UserService.class);
- String result = userService.queryUserInfo();
- System.out.println("測試結(jié)果:" + result);
- System.out.println("ApplicationContextAware:"+userService.getApplicationContext());
- System.out.println("BeanFactoryAware:"+userService.getBeanFactory());
- }
- 測試方法中主要是添加了一寫關(guān)于新增 Aware 實現(xiàn)的調(diào)用,其他不需要調(diào)用的也打印了相應(yīng)的日志信息,可以在測試結(jié)果中看到。
測試結(jié)果
- 執(zhí)行:init-method
- ClassLoader:sun.misc.Launcher$AppClassLoader@14dad5dc
- Bean Name is:userService
- 測試結(jié)果:小傅哥,騰訊,深圳
- ApplicationContextAware:cn.bugstack.springframework.context.support.ClassPathXmlApplicationContext@5ba23b66
- BeanFactoryAware:cn.bugstack.springframework.beans.factory.support.DefaultListableBeanFactory@2ff4f00f
- 執(zhí)行:destroy-method
- Process finished with exit code 0
從測試結(jié)果可以看到,本章節(jié)新增加的感知接口對應(yīng)的具體實現(xiàn)(BeanNameAware, BeanClassLoaderAware, ApplicationContextAware, BeanFactoryAware),已經(jīng)可以如期輸出結(jié)果了。
六、總結(jié)
目前關(guān)于 Spring 框架的實現(xiàn)中,某些功能點已經(jīng)越來趨向于完整,尤其是 Bean 對象的生命周期,已經(jīng)有了很多的體現(xiàn)。整體總結(jié)如下圖:
本章節(jié)關(guān)于 Aware 的感知接口的四個繼承接口 BeanNameAware, BeanClassLoaderAware, ApplicationContextAware, BeanFactoryAware 的實現(xiàn),又?jǐn)U展了 Spring 的功能。如果你有做過關(guān)于 Spring 中間件的開發(fā)那么一定會大量用到這些類,現(xiàn)在你不只是用過,而且還知道他們都是什么時候觸達(dá)的,在以后想排查類的實例化順序也可以有一個清晰的思路了。
每一章節(jié)內(nèi)容的實現(xiàn)都是在以設(shè)計模式為核心的結(jié)構(gòu)上填充各項模塊的功能,單純的操作編寫代碼并不會有太多收獲,一定是要理解為什么這么設(shè)計,這么設(shè)計的好處是什么,怎么就那么多接口和抽象類的應(yīng)用,這些才是 Spring 框架學(xué)習(xí)的核心所在。
文章標(biāo)題:虎行有雨,定義標(biāo)記類型Aware接口,實現(xiàn)感知容器對象
本文鏈接:http://www.fisionsoft.com.cn/article/djjdhoo.html


咨詢
建站咨詢
