IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Spring手撸源码系列-实现Aware感知容器对象 -> 正文阅读

[Java知识库]Spring手撸源码系列-实现Aware感知容器对象

tia 此次实现会比较简单,围绕着Aware感知事件的处理,所谓Aware感知通俗说明就是将applicationContext、beanFactory、beanName、beanClassLoader等等的IOC的容器对象传给用户,使用户能够获取该对象并进行使用的操作。

那么就要考虑如何传给用户,怎么合理设计,让用户得到容器对象

1.工程目录

等待上传中

2.xml类图

2.1.Aware接口

定义了Aware接口,这个接口就是标记的,如果任何继承此接口则代表是感知接口,统一判断对象是不是Aware条件也可使用

2.2 BeanFactoryAware

定义了BeanFactoryAware接口,此接口继承Aware,并定义方法为setBeanFactory(BeanFactory beanFactory);,此方法可用户实现

2.3 BeanNameAware

定义了BeanNameAware接口,此接口继承Aware,并定义方法为setBeanName(String beanName);,此方法可用户实现

2.4 BeanClassLoaderAware

定义了BeanClassLoaderAware接口,此接口继承Aware,并定义方法为setBeanClassLoader(ClassLoader classLoader);,此方法可用户实现。

2.5 ApplicationContextAware

定义了ApplicationContextAware接口,此接口继承Aware,并定义方法为setApplicationContext(ApplicationContext? applicationContext);,此方法可用户实现。

2.6?ApplicationContextAwareProcessor

定义一个ApplicationContextAwareProcessor类,实现BeanPostProcessor接口,这样的好处是原本咱们上节已经有了bean对象实例化后可以处理后置bean的情况,那么可以通过此进行使用。

2.7?AbstractApplicationContext

添加到beanPostProcessor集合里,并且调用ApplicationContextAwareProcessor包装类的构造方法将当前applicationContext对象放入到包装类里留着bean初始化之后调用自定义方法

2.8?AbstractAutowireCapableBeanFactory

将之前的初始化方法里添加判断是否是Aware的操作,调用具体的用户自定义的方法

3.代码实现

? ?Aware:添加Aware标志接口

// 定义标记接口,实现该接口可以被spring感知
// 就像是一种标签一样,可以统一方便摘取出属于此类接口的实现类,通常会有instanceof一起判断使用
public interface Aware {
}

?添加BeanFactoryAware接口定义BeanFactory的感知

// 特点:此接口类继承Aware接口类
// 实现此接口,就能感知到所属的beanFactory
public interface BeanFactoryAware extends Aware{
    void setBeanFactory(BeanFactory beanFactory);
}

添加BeanNameAware接口定义BeanName的感知

// 实现此接口,就能感知到所属的beanName
public interface BeanNameAware extends Aware {
    void setBeanName(String name);
}

添加BeanClassLoaderAware接口定义beanClassLoader的感知

// 实现此接口,既能感知到所属的ClassLoader
public interface BeanClassLoaderAware  extends Aware {
    void setBeanClassLoader(ClassLoader classLoader);
}

在xontext包下添加ApplicationContextAware,用来对ApplicationContext感知

// 实现此接口,就能感知到所属的ApplicationContext
public interface ApplicationContextAware extends Aware {
    void setApplicationContext(ApplicationContext applicationContext);
}

添加ApplicationContextAwareProcessor包装类,这个主要是在ApplicationContext得到的时候使用注册添加集合数据里,通过构造方法获取ApplicationContext ,在初始化之后将此实例传给用户的操作。

// ApplicationContextAware包装处理类,主要原因是ApplicationContext所创建对象时机和beanFactoryAware等不在一块,
// 通过此类的postProcessBeforeInitialization在初始化后调用此方法来交给用户自定义赋值setApplicationContext方法得到
// ApplicationContext对象
public class ApplicationContextAwareProcessor implements BeanPostProcessor {

    private final ApplicationContext applicationContext;

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

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

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

AbstractApplicationContext的修改添加了一个这段代码? “beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));”就ok了

public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {

    // 使用模板方法
    @Override
    public void refresh() {
        // 1.创建beanFactory
        // 2.将创建完的beanFactory和配置文件路径传输到资源处理器里
        // 3.从资源处理器获取输入流,根据流解析bean以及属性数据并注册到bean容器里
        refreshBeanFactory();

        // 2.获取beanFactory
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();

        // 3.将当前AbstractApplicationContext对象通过构造方法赋值传给包装类
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

        // 4.在bean实例化之前,执行BeanFactoryPostProcessor(Invoke factory processors registered as beans in the context)
        // 4.1 根据BeanFactoryPostProcessor来判断是否是自定义实现子类,是就创建bean,并注册到单例类(创建自定义类Bean(MyBeanFactoryPostProcessor))
        // 4.2 根据得到的BeanFactoryPostProcessor接口来调用postProcessBeanFactory方法(此时beanDefinition里的属性已经修改)
        invokeBeanFactoryPostProcessors(beanFactory);

        // 5.BeanPostProcessor需要提前于其他Bean对象实例化之前执行注册操作
        // 5.1 通过getBeansOfType()找到与BeanPostProcessor相关的类,
        // 5.2 找到以后调用将当前的BeanPostProcessor放入集合里(做标识-后续其他bean实例创建可进行后置处理更改对象bean)
        registerBeanPostProcessors(beanFactory);


        // 6.提前实例化单例bean对象
        // 通过beanDefinationMap里的实例对象将后续bean实例进行实例化,并处理后置修改的对象
        beanFactory.preInstantiateSingletons();


    }

    protected abstract void refreshBeanFactory();

    protected abstract ConfigurableListableBeanFactory getBeanFactory();

    // 在bean实例化之前,执行BeanFactoryPostProcessor,自定义实现进行bean的修改
    private void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        // 获取和BeanFactoryPostProcessor类有关系的的类-这里主要是获取BeanFactoryPostProcessor的子实现接口
        Map<String, BeanFactoryPostProcessor> beanPostProcessorMap = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
        for (BeanFactoryPostProcessor beanFactoryPostProcessor : beanPostProcessorMap.values()) {
            // 调用用户自定义实现的子接口
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
        }
    }

    private void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        // 根据BeanPostProcessor获取其子实现接口
        Map<String, BeanPostProcessor> beanPostProcessorMap = beanFactory.getBeansOfType(BeanPostProcessor.class);
        for (BeanPostProcessor beanPostProcessor : beanPostProcessorMap.values()) {
            // 将beanPostProcessor添加到集合里
            beanFactory.addBeanPostProcessor(beanPostProcessor);
        }
    }

    @Override
    public void registerShutdownHook() {
        System.out.println("进行registerShutdownHook()注册钩子方法!");
        // 在程序正常退出或jvm进行关闭时调用传输进来的线程对象方法,此次调用本类里close()方法。
        Runtime.getRuntime().addShutdownHook(new Thread(this::close));
    }


    @Override
    public void close() {
        System.out.println("程序执行完毕,可以调用close()方法,进行用户自定义销毁工作!");
        getBeanFactory().destroySingletons();
    }

    @Override
    public <T> Map<String, T> getBeansOfType(Class<T> type) {
        return getBeanFactory().getBeansOfType(type);
    }

    @Override
    public String[] getBeanDefinitionNames() {
        return getBeanFactory().getBeanDefinitionNames();
    }

    @Override
    public Object getBean(String name) throws BeansException {
        return getBeanFactory().getBean(name);
    }

    @Override
    public Object getBean(String name, Object... args) {
        return getBeanFactory().getBean(name, args);
    }

    @Override
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
        return getBeanFactory().getBean(name, requiredType);
    }
}

AbstractAutowireCapableBeanFactory这个类我就不把全部的展示出来了,就展示initializeBean方法,这个方法主要是添加了如下几个if判断,如果是这些感知实现调用用户实现方法,将参数传给外界

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

        if (bean instanceof Aware){
            if (bean instanceof BeanFactoryAware){
                // 设置当前BeanFactory
                ((BeanFactoryAware) bean).setBeanFactory(this);
            }
            if (bean instanceof BeanNameAware){
                // 设置容器中bean的名称
                ((BeanNameAware) bean).setBeanName(beanName);
            }
            if (bean instanceof BeanClassLoaderAware){
                ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
            }
        }

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

        // 执行自定义初始化方法invokeInitMethods(beanName, wrappedBean, beanDefinition);
        try {
            invokeInitMethods(beanName, wrappedBean, beanDefinition);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BeansException("Invocation of init method of bean [" + beanName + "] failed", e);
        }
        // 2. 执行 BeanPostProcessor After 处理
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        return wrappedBean;
    }

4.测试准备

还是上一节的配置文件以及UserDao,只有userService发生变化,需要实现aware感知,将值进行赋值操作,并且我将值打印出来,方便大家观看

public class UserService implements BeanFactoryAware, ApplicationContextAware, BeanNameAware, BeanClassLoaderAware {
    private String uId;
    private String company;
    private UserDao userDao;
    private String location;

    private ApplicationContext applicationContext;
    private BeanFactory beanFactory;
    private String beanName;
    private ClassLoader classLoader;


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

    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        this.beanFactory = beanFactory;
        System.out.println("this.beanFactory="+beanFactory);
    }

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
        System.out.println("this.beanName="+name);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
        System.out.println("this.applicationContext="+applicationContext);
    }


    public void queryUserInfo() {
        System.out.println("查询用户信息:" + userDao.queryUserName(uId)
                + ",公司名称:" + company + ",地址:" + location);
    }

    /*@Override
    public void destroy() throws Exception {
        System.out.println("执行接口实现方式的DisposableBean:UserService.destroy");
    }

    @Override
    public void afterPropertiesSet() {
        System.out.println("执行接口实现方式的InitializingBean:UserService.afterPropertiesSet");
    }*/

    public String getuId() {
        return uId;
    }

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

    public UserDao getUserDao() {
        return userDao;
    }

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

    public String getLocation() {
        return location;
    }

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

    public String getCompany() {
        return company;
    }

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

    public ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    public BeanFactory getBeanFactory() {
        return beanFactory;
    }

    public String getBeanName() {
        return beanName;
    }

    public ClassLoader getClassLoader() {
        return classLoader;
    }
}

添加单元测试:

public class ApiTest {
    //
    @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);
        userService.queryUserInfo();
        System.out.println("BeanClassLoaderAware:" + userService.getApplicationContext());
        System.out.println("BeanFactoryAware:" + userService.getBeanFactory());
    }
}

运行以后测试情况如下:说明容器数据已经给到用户了。

?

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-03-22 20:22:50  更:2022-03-22 20:25:26 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 8:00:15-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码