手写Spring:第9章-Aware感知容器对象

文章目录

  • 一、目标:Aware感知容器对象
  • 二、设计:Aware感知容器对象
  • 三、实现:Aware感知容器对象
    • [3.1 工程结构](#3.1 工程结构)
    • [3.2 Spring感知接口类图](#3.2 Spring感知接口类图)
    • [3.3 定义标记接口和容器感知类](#3.3 定义标记接口和容器感知类)
      • [3.3.1 定义标记接口](#3.3.1 定义标记接口)
      • [3.3.2 对象工厂感知接口](#3.3.2 对象工厂感知接口)
      • [3.3.3 类加载感知接口](#3.3.3 类加载感知接口)
      • [3.3.4 对象名称感知接口](#3.3.4 对象名称感知接口)
      • [3.3.5 应用上下文感知接口](#3.3.5 应用上下文感知接口)
    • [3.4 包装应用上下文处理器](#3.4 包装应用上下文处理器)
      • [3.4.1 包装应用上下文处理器](#3.4.1 包装应用上下文处理器)
      • [3.4.2 注册 BeanPostProcessor](#3.4.2 注册 BeanPostProcessor)
    • [3.5 感知调用操作](#3.5 感知调用操作)
      • [3.5.1 抽象对象工厂](#3.5.1 抽象对象工厂)
      • [3.5.2 感知调用操作](#3.5.2 感知调用操作)
  • 四、测试:Awrae感知容器对象
    • [4.1 修改UserDao用户对象](#4.1 修改UserDao用户对象)
    • [4.2 单元测试](#4.2 单元测试)
  • 五、总结:Aware感知容器对象

一、目标:Aware感知容器对象

💡 如何在获得 Spring 的功能时做些扩展框架的使用该怎么操作?

  • 目前实现的 Spring 框架中,在 Bean 操作上提供的能力,包括:
    • Bean 对象的定义和注册。
    • 操作 Bean 对象过程中执行的 BeanFactoryPostProcessorBeanFactoryPostProcessorInitializingBeanDisposableBean
  • XML 新增的一些配置处理,让我们可以对 Bean 对象有更强的操作性。
  • 那么,如果我们想获得 Spring 框架提供的 BeanFactoryApplicationContextBeanClassLoader 等这些功能做一些扩展框架的使用时该怎么操作呢?
    • 所以我们希望在 Spring 框架中提供一种能感知容器操作的接口,如果谁实现类这样的接口,就可以获取接口入参中的各类能力。

二、设计:Aware感知容器对象

💡 希望拿到 Spring 框架中一些提供的资源,那么首先需要考虑以一个什么方式去获取,之后定义出来的获取方式,在 Spring 该怎么去承接?

实现了这两项内容,就可以扩展出你需要的一些属于 Spring 框架本身的能力了。

  • Bean 对象实例化阶段我们操作过一些额外定义、属性、初始化和销毁的操作,其实如果像获取 Spring 一些如 BeanFactoryApplicationContext 时,也可以通过此类方式进行实现。
    • 需要定义一个标记性的接口,这个接口不需要有方法,它只起到标记作用。
    • 而具体的功能由继承此接口的其他功能性接口定义具体方法,最终这个接口就可以通过 instanceof 进行判断和调用。
  • 定义接口 Aware,在 Spring 框架中它是一种感知标记性接口,具体的子类定义和实现能感知容器中的相关对象。
    • 也就是通过这个桥梁,向具体的实现类中提供容器服务
  • 继承 Aware 的接口包括:BeanFactoryAwareBeanClassLoaderAwareBeanNameAwareApplicationContextAware
  • 在具体的接口实现过程中看到,
    • 一部分(BeanFactoryAwareBeanClassLoaderAwareBeanNameAware)在 factorysupport 文件夹下。
    • 另外(ApplicationContextAware)是在 contextsupport 中。
  • 这是因为不同的内容获取需要在不同的包下提供。所以:
    • AbstractApplicationContext 的具体实现中会用到向 beanFactory 添加 BeanPostProcessor 内容的 ApplicationContextAwareProcessor 操作。
    • 最后由 AbstractAutowireCapableBeanFactory 创建 createBean 时处理相应的调用操作。

三、实现:Aware感知容器对象

3.1 工程结构

java 复制代码
spring-step-08
|-src
	|-main
	|	|-java
	|		|-com.lino.springframework
	|			|-beans
	|			|	|-factory
	|			|	|	|-config
	|			|	|	|	|-AutowireCapableBeanFactory.java
	|			|	|	|	|-BeanDefinition.java
	|			|	|	|	|-BeanFactoryPostProcessor.java
	|			|	|	|	|-BeanPostProcessor.java
	|			|	|	|	|-BeanReference.java
	|			|	|	|	|-ConfigurableBeanFactory.java
	|			|	|	|	|-SingletonBeanRegistry.java
	|			|	|	|-support
	|			|	|	|	|-AbstractAutowireCapableBeanFactory.java
	|			|	|	|	|-AbstractBeabDefinitionReader.java
	|			|	|	|	|-AbstractBeabFactory.java
	|			|	|	|	|-BeabDefinitionReader.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
	|			|	|	|-HierarcgicalBeanFactory.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
	|			|-util
	|			|	|-ClassUtils.java
	|-test
		|-java
			|-com.lino.springframework.test
                |-bean
                |	|-UserDao.java
                |	|-UserService.java
                |-ApiTest.java
		|-resources
			|-spring.xml

3.2 Spring感知接口类图

  • 整个类关系就是关于 Aware 感知的定义和对容器感知的实现。
  • Aware 有四个继承的接口,其他这些接口的继承都是为了继承一个标记,有了标记的存在更方便类的操作和具体判断实现。
  • 另外由于 ApplicationContext 并不是在 AbstractAutowireCapableBeanFactorycreateBean 方法下的内容。
    • 所以需要像容器中注册 addBeanPostProcessor,再由 createBean 统一调用 applyBeanPostProcessorBeforeInitialization 时进行操作。

3.3 定义标记接口和容器感知类

3.3.1 定义标记接口

Aware.java

java 复制代码
package com.lino.springframework.beans.factory;

/**
 * @description: 标记类接口,实现该接口可以被Spring容器感知
 */
public interface Aware {
}
  • Spring 中有特别多类似这样的标记接口的设计方式,它们的存在就像是一种标签一样,可以方便统一摘取出属于此类接口的实现类,通常会有 instanceof 一起判断使用。

3.3.2 对象工厂感知接口

BeanFactoryAware.java

java 复制代码
package com.lino.springframework.beans.factory;

import com.lino.springframework.beans.BeansException;

/**
 * @description: 实现此接口,即能感知到所属的 BeanFactory
 */
public interface BeanFactoryAware extends Aware {

    /**
     * 设置对象工厂
     *
     * @param beanFactory 对象工厂
     * @throws BeansException 异常
     */
    void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}
  • 实现此接口,即能感知到所属的 BeanFactory

3.3.3 类加载感知接口

BeanClassLoaderAware.java

java 复制代码
package com.lino.springframework.beans.factory;

/**
 * @description: 实现此接口,即能感知到所属的 ClassLoader
 */
public interface BeanClassLoaderAware extends Aware {

    /**
     * 设置类加载器
     *
     * @param classLoader 类加载器
     */
    void setBeanClassLoader(ClassLoader classLoader);
}
  • 实现此接口,即能感知到所属的 ClassLoader

3.3.4 对象名称感知接口

BeanNameAware.java

java 复制代码
package com.lino.springframework.beans.factory;

/**
 * @description: 实现此接口,即能感知到所属的 BeanName
 */
public interface BeanNameAware {

    /**
     * 设置对象名称
     *
     * @param name 对象名称
     */
    void setBeanName(String name);
}
  • 实现此接口,即能感知到所属的 BeanName

3.3.5 应用上下文感知接口

ApplicationContextAware.java

java 复制代码
package com.lino.springframework.context;

import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.Aware;

/**
 * @description: 实现此接口,即能感知到所属的 ApplicationContext
 */
public interface ApplicationContextAware extends Aware {

    /**
     * 设置应用上下文
     *
     * @param applicationContext 应用上下文
     * @throws BeansException 异常
     */
    void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
  • 实现此接口,即能感知到所属的 ApplicationContext

3.4 包装应用上下文处理器

3.4.1 包装应用上下文处理器

ApplicationContextAwareProcessor.java

java 复制代码
package com.lino.springframework.context.support;

import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.config.BeanPostProcessor;
import com.lino.springframework.context.ApplicationContext;
import com.lino.springframework.context.ApplicationContextAware;

/**
 * @description: 通过 BeanPostProcessor 实现类感知应用上下文对象
 */
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 方法调用。

3.4.2 注册 BeanPostProcessor

AbstractApplicationContext.java

java 复制代码
package com.lino.springframework.context.support;

import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.ConfigurableListableBeanFactory;
import com.lino.springframework.beans.factory.config.BeanFactoryPostProcessor;
import com.lino.springframework.beans.factory.config.BeanPostProcessor;
import com.lino.springframework.context.ConfigurableApplicationContext;
import com.lino.springframework.core.io.DefaultResourceLoader;
import java.util.Map;

/**
 * @description: 抽象应用上下文
 */
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 实例化之前,执行 BeanFactoryPostProcess
        invokeBeanFactoryPostProcessor(beanFactory);

        // 5.BeanPostProcessor 需要提前与其他 Bean 对象实例化之前执行注册操作
        registerBeanPostProcessor(beanFactory);

        // 6.提前实例化单例 Bean 对象
        beanFactory.preInstantiateSingletons();
    }

    ...
}
  • refresh() 方法就是整个 Spring 容器的操作过程,这次新增加了 addBeanPostProcessor 操作。
  • 添加 ApplicationContextAwareProcessor,让继承自 ApplicationContextAwareBean 对象都能感知所属的 ApplicationContext

3.5 感知调用操作

3.5.1 抽象对象工厂

AbstractBeanFactory.java

java 复制代码
package com.lino.springframework.beans.factory.support;

import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.config.BeanDefinition;
import com.lino.springframework.beans.factory.config.BeanPostProcessor;
import com.lino.springframework.beans.factory.config.ConfigurableBeanFactory;
import com.lino.springframework.util.ClassUtils;
import java.util.ArrayList;
import java.util.List;

/**
 * @description: 抽象的 Bean 工厂基类,定义模板方法
 */
public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry implements ConfigurableBeanFactory {

    private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();

    private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();

    ...

    public ClassLoader getBeanClassLoader() {
        return this.beanClassLoader;
    }
}
  • 添加 ClassLoader 对像,并提供一个获取对象类加载器的方法。getBeanClassLoader()

3.5.2 感知调用操作

AbstractAutowireCapableBeanFactory.java

java 复制代码
package com.lino.springframework.beans.factory.support;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValue;
import com.lino.springframework.beans.PropertyValues;
import com.lino.springframework.beans.factory.*;
import com.lino.springframework.beans.factory.config.AutowireCapableBeanFactory;
import com.lino.springframework.beans.factory.config.BeanDefinition;
import com.lino.springframework.beans.factory.config.BeanPostProcessor;
import com.lino.springframework.beans.factory.config.BeanReference;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 * @description: 实现默认bean创建的抽象bean工厂超类
 * @author: lingjian
 * @createDate: 2022/11/22 14:39
 */
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {

    private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();

    ...

    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(wrappedBean, beanName);
        return wrappedBean;
    }

    ...
}
  • 首先在 initializeBean 中,通过判断 bean instanceof Aware,调用三个接口方法。这样就能通知到已经实现了此接口的类。
    • ((BeanFactoryAware) bean).setBeanFactory(this)
    • ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader())
    • ((BeanNameAware) bean).setBeanName(beanName)
  • 另外还向 BeanPostProcessor 中添加了 ApplicationContextAwareProcessor,此时在这个方法中也会被调用到具体的类实现,得到一个 ApplicationContext 属性。

四、测试:Awrae感知容器对象

4.1 修改UserDao用户对象

UserService.java

java 复制代码
package com.lino.springframework.test.bean;

import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.*;
import com.lino.springframework.context.ApplicationContext;
import com.lino.springframework.context.ApplicationContextAware;

/**
 * @description: 模拟用户 Bean 对象
 */
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 setBeanClassLoader(ClassLoader classLoader) {
        System.out.println("ClassLoader: " + classLoader);
    }

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

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

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

    /**
     * 查询用户信息
     */
    public String queryUserInfo() {
        return userDao.queryUserName(uId) + "," + company + "," + location;
    }

    public String getuId() {
        return uId;
    }

    public void setuId(String uId) {
        this.uId = uId;
    }

    public String getCompany() {
        return company;
    }

    public void setCompany(String company) {
        this.company = company;
    }

    public String getLocation() {
        return location;
    }

    public void setLocation(String location) {
        this.location = location;
    }

    public UserDao getUserDao() {
        return userDao;
    }

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    public BeanFactory getBeanFactory() {
        return beanFactory;
    }
}
  • 新增加 BeanNameAware, BeanClassLoaderAware, ApplicationContextAware, BeanFactoryAware 四个感知的实现类,并在类中的实现相应的接口方法。

4.2 单元测试

ApiTest.java

java 复制代码
@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 实现的调用,其他不需要调用的也打印了相应的日志信息,可以在测试结果中看到。

测试结果

java 复制代码
执行:init-method
ClassLoader: sun.misc.Launcher$AppClassLoader@18b4aac2
Bean Name is: userService
测试结果:张三,阿里,杭州
ApplicationContextAware: com.lino.springframework.context.support.ClassPathXmlApplicationContext@56cbfb61
BeanFactoryAware: com.lino.springframework.beans.factory.support.DefaultListableBeanFactory@1134affc
执行:destroy-method
  • 从测试结果来看,新增加的感知接口对应的具体实现(BeanNameAware, BeanClassLoaderAware, ApplicationContextAware, BeanFactoryAware),已经可以正常输出结果。

五、总结:Aware感知容器对象

  • 本节关于 Aware 的感知接口的四个继承接口 BeanNameAware, BeanClassLoaderAware, ApplicationContextAware, BeanFactoryAware 的实现,又扩展了 Spring 的功能。
  • 目前关于 Spring 框架的实现中,功能已经越来越趋向于完整,尤其对于 Bean 对象的生命周期。
相关推荐
Chen-Edward5 分钟前
有了Spring为什么还有要Spring Boot?
java·spring boot·spring
magic3341656324 分钟前
Springboot整合MinIO文件服务(windows版本)
windows·spring boot·后端·minio·文件对象存储
云创智城-yuncitys24 分钟前
SpringCloud 架构在智慧交通路侧停车系统中的实践:从技术落地到城市级服务升级
spring·spring cloud·架构·智慧城市·停车系统·充电系统源码
开心-开心急了34 分钟前
Flask入门教程——李辉 第一、二章关键知识梳理(更新一次)
后端·python·flask
掘金码甲哥1 小时前
调试grpc的哼哈二将,你值得拥有
后端
陈小桔1 小时前
idea中重新加载所有maven项目失败,但maven compile成功
java·maven
小学鸡!1 小时前
Spring Boot实现日志链路追踪
java·spring boot·后端
xiaogg36781 小时前
阿里云k8s1.33部署yaml和dockerfile配置文件
java·linux·kubernetes
逆光的July1 小时前
Hikari连接池
java
微风粼粼2 小时前
eclipse 导入javaweb项目,以及配置教程(傻瓜式教学)
java·ide·eclipse