手写spring第六章-实现应用上下文,完成bean的扩展机制

前言

在上一章我们完成的容器初始化,从而完成bean定义注册和bean对象的初始化。
在日常开发中,我们会遇到这样的问题,加入我们需要修改某个bean对象的成员属性,假如只有需要修改的bean对象还好说,我们可以通过xml配置修改来解决问题,但是若遇到一个依赖关系十分复杂且不止一个bean对象,我们又该怎么办呢?

需求分析

所以我们需要一个实现一个功能可以在容器初始化的时候修改bean定义信息完成所有bean定义的修改操作,或者在实例化bean前后修改bean的相关属性。同时我们还希望这个扩展可以对用户友好,说白了,就是我们需要修改某个bean属性的时候操作尽可能简单。

思路分析

设计解析

如下图所示,我们需要编写一个容器上下文,通过集成现有bean容器,并封装一个refresh方法来实现bean加载、注册、扩展、实例化四个操作。
在这里插入图片描述

类图

架构设计如下图所示,笔者还是延续了之前的设计思想使用接口定义动作,抽象类实现模板方法以及根据单一职责原则实现自己应该有的类,再有子类实现具体实现细节
在这里插入图片描述

项目结构

使用命令即可导入到xx.txt目录

tree /f >xx.txt
├─src
│  ├─main
│  │  ├─java
│  │  │  └─cn
│  │  │      └─shark
│  │  │          └─springframework
│  │  │              ├─beans
│  │  │              │  │  BeansException.java
│  │  │              │  │  PropertyValue.java
│  │  │              │  │  PropertyValues.java
│  │  │              │  │  
│  │  │              │  └─factory
│  │  │              │      │  BeanFactory.java
│  │  │              │      │  ConfigurableListableBeanFactory.java
│  │  │              │      │  HierarchicalBeanFactory.java
│  │  │              │      │  ListableBeanFactory.java
│  │  │              │      │  
│  │  │              │      ├─config
│  │  │              │      │      AutowireCapableBeanFactory.java
│  │  │              │      │      BeanDefinition.java
│  │  │              │      │      BeanFactoryPostProcessor.java
│  │  │              │      │      BeanPostProcessor.java
│  │  │              │      │      BeanReference.java
│  │  │              │      │      ConfigurableBeanFactory.java
│  │  │              │      │      SingletonBeanRegistry.java
│  │  │              │      │      
│  │  │              │      ├─core
│  │  │              │      │  └─io
│  │  │              │      │          ClassPathResource.java
│  │  │              │      │          DefaultResourceLoader.java
│  │  │              │      │          FileSystemResource.java
│  │  │              │      │          Resource.java
│  │  │              │      │          ResourceLoader.java
│  │  │              │      │          UrlResource.java
│  │  │              │      │          
│  │  │              │      ├─support
│  │  │              │      │      AbstractAutowireCapableBeanFactory.java
│  │  │              │      │      AbstractBeanDefinitionReader.java
│  │  │              │      │      AbstractBeanFactory.java
│  │  │              │      │      BeanDefinitionReader.java
│  │  │              │      │      BeanDefinitionRegistry.java
│  │  │              │      │      CglibSubclassingInstantiationStrategy.java
│  │  │              │      │      DefaultListableBeanFactory.java
│  │  │              │      │      DefaultSingletonBeanRegistry.java
│  │  │              │      │      InstantiationStrategy.java
│  │  │              │      │      SimpleInstantiationStrategy.java
│  │  │              │      │      
│  │  │              │      ├─util
│  │  │              │      │      ClassUtils.java
│  │  │              │      │      
│  │  │              │      └─xml
│  │  │              │              XmlBeanDefinitionReader.java
│  │  │              │              
│  │  │              └─context
│  │  │                  │  ApplicationContext.java
│  │  │                  │  ConfigurableApplicationContext.java
│  │  │                  │  
│  │  │                  └─support
│  │  │                          AbstractApplicationContext.java
│  │  │                          AbstractRefreshableApplicationContext.java
│  │  │                          AbstractXmlApplicationContext.java
│  │  │                          ClassPathXmlApplicationContext.java
│  │  │                          
│  │  └─resources
│  └─test
│      ├─java
│      │  └─cn
│      │      └─shark
│      │          └─springframework
│      │              │  ApiTest.java
│      │              │  
│      │              ├─bean
│      │              │      UserDao.java
│      │              │      UserService.java
│      │              │      
│      │              └─common
│      │                      MyBeanFactoryPostProcessor.java
│      │                      MyBeanPostProcessor.java
│      │                      
│      └─resources
│              important.properties
│              spring.xml

相关代码

BeanFactoryPostProcessor(bean工厂扩展)

package cn.shark.springframework.beans.factory.config;

import cn.shark.springframework.beans.BeansException;
import cn.shark.springframework.beans.factory.ConfigurableListableBeanFactory;

public interface BeanFactoryPostProcessor {
    
    

    /**
     * 在所有的 BeanDefinition 加载完成后,实例化 Bean 对象之前,提供修改 BeanDefinition 属性的机制
     *
     * @param beanFactory
     * @throws BeansException
     */
    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

BeanPostProcessor(bean扩展)

package cn.shark.springframework.beans.factory.config;

import cn.shark.springframework.beans.BeansException;

public interface BeanPostProcessor {
    
    

    /**
     * 在 Bean 对象执行初始化方法之前,执行此方法
     *
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    Object postProcessBeforeInitialization(Object bean,String beanName) throws BeansException;


    Object postProcessAfterInitialization(Object bean,String beanName) throws BeansException;
}

ApplicationContext (上下文行为定义,继承ListableBeanFactory,从而可以根据类类型获取前后置处理器)

该类看没有实现任何东西,但是很好的实现了各个类与spring容器的完美解耦,并且拿到了ListableBeanFactory具备的行为,这样就可以让其子类可根据需要实现根据类类型获取bean的函数。

package cn.shark.springframework.context;

import cn.shark.springframework.beans.factory.ListableBeanFactory;

public interface ApplicationContext extends ListableBeanFactory {
    
    
}

ConfigurableApplicationContext(上下文行为定义)

该类继承父类的所有功能,并规范之后所有子类都必须执行的动作,而具体实现交由后者实现。

package cn.shark.springframework.context;

import cn.shark.springframework.beans.BeansException;

public interface ConfigurableApplicationContext extends ApplicationContext {
    
    

    /**
     * 刷新容器
     *
     * @throws BeansException
     */
    void refresh() throws BeansException;

}

AbstractApplicationContext(上下文行为规范,使用模板方法定义执行顺序)

使用模板方法完成其父类(ConfigurableApplicationContext )实现模板,由于bean工厂具体情况未知,所有讲bean工厂刷新和获取作为抽象方法给后者实现

package cn.shark.springframework.context.support;

import cn.shark.springframework.beans.BeansException;
import cn.shark.springframework.beans.factory.ConfigurableListableBeanFactory;
import cn.shark.springframework.beans.factory.config.BeanFactoryPostProcessor;
import cn.shark.springframework.beans.factory.config.BeanPostProcessor;
import cn.shark.springframework.beans.factory.config.ConfigurableBeanFactory;
import cn.shark.springframework.beans.factory.core.io.DefaultResourceLoader;
import cn.shark.springframework.context.ConfigurableApplicationContext;

import java.util.Map;

public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
    
    

    /**
     * 刷新容器
     *
     * @throws BeansException
     */
    @Override
    public void refresh() throws BeansException {
    
    

        // 1. 创建 BeanFactory,并加载 BeanDefinition
        refreshBeanFactory();

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

        // 3. 在 Bean 实例化之前,执行 BeanFactoryPostProcessor (Invoke factory processors registered as beans in the context.)
        invokeBeanFactoryPostProcessors(beanFactory);

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

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

    }

    protected abstract void refreshBeanFactory() throws BeansException;

    protected abstract ConfigurableListableBeanFactory getBeanFactory();

    private void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    
    
        Map<String, BeanFactoryPostProcessor> beanFactoryPostProcessorMap = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
        for (BeanFactoryPostProcessor beanFactoryPostProcessor : beanFactoryPostProcessorMap.values()) {
    
    
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
        }
    }

    private void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    
    
        Map<String, BeanPostProcessor> beanPostProcessorMap = beanFactory.getBeansOfType(BeanPostProcessor.class);
        for (BeanPostProcessor beanPostProcessor : beanPostProcessorMap.values()) {
    
    
            beanFactory.addBeanPostProcessor(beanPostProcessor);
        }
    }

    /**
     * 按照类型返回bean实例
     *
     * @param type
     * @return
     * @throws BeansException
     */
    @Override
    public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
    
    
        return getBeanFactory().getBeansOfType(type);
    }

    /**
     * 返回注册表中所有的bean名称
     *
     * @return
     */
    @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... agrs) throws BeansException {
    
    
        return getBeanFactory().getBean(name,agrs);
    }

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

AbstractRefreshableApplicationContext(上下文刷新行为抽象,单一职责最好的体现)

package cn.shark.springframework.context.support;

import cn.shark.springframework.beans.BeansException;
import cn.shark.springframework.beans.factory.ConfigurableListableBeanFactory;
import cn.shark.springframework.beans.factory.support.DefaultListableBeanFactory;

public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext  {
    
    

    private DefaultListableBeanFactory beanFactory;

    @Override
    protected void refreshBeanFactory() throws BeansException {
    
    
        DefaultListableBeanFactory beanFactory = createBeanFactory();
        loadBeanDefinitions(beanFactory);;
        this.beanFactory=beanFactory;
    }

    private DefaultListableBeanFactory createBeanFactory(){
    
    
        return new DefaultListableBeanFactory();
    }

    protected  abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException;

    @Override
    protected ConfigurableListableBeanFactory getBeanFactory() {
    
    
        return beanFactory;
    }
}

AbstractXmlApplicationContext (上下文加载bean抽象,实现自己的职责:加载xml文件并注册bean定义)

package cn.shark.springframework.context.support;

import cn.shark.springframework.beans.BeansException;
import cn.shark.springframework.beans.factory.support.DefaultListableBeanFactory;
import cn.shark.springframework.beans.factory.xml.XmlBeanDefinitionReader;

public abstract class AbstractXmlApplicationContext extends AbstractRefreshableApplicationContext {
    
    

    @Override
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException {
    
    
        XmlBeanDefinitionReader beanDefinitionReader=new XmlBeanDefinitionReader(beanFactory,this);
        String[] configLocations = getConfigLocations();
        if (null!=configLocations){
    
    
            beanDefinitionReader.loadBeanDefinitions(configLocations);
        }
    }

    protected abstract String[] getConfigLocations();
}

具体实现

package cn.shark.springframework.context.support;



public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
    
    

    private String[] configLocations;

    public ClassPathXmlApplicationContext() {
    
    
    }

    public ClassPathXmlApplicationContext(String configLocations) {
    
    
        this(new String[]{
    
    configLocations});
    }


    public ClassPathXmlApplicationContext(String[] configLocations) {
    
    
        this.configLocations = configLocations;
        refresh();
    }

    @Override
    protected String[] getConfigLocations() {
    
    
        return configLocations;
    }



}

测试

配置文件

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

    <bean id="userDao" class="cn.shark.springframework.bean.UserDao"/>

    <bean id="userService" class="cn.shark.springframework.bean.UserService">
        <property name="uId" value="10001"/>
        <property name="company" value="腾讯"/>
        <property name="location" value="深圳"/>
        <property name="userDao" ref="userDao"/>
    </bean>

    <bean class="cn.shark.springframework.common.MyBeanFactoryPostProcessor"/>
    <bean class="cn.shark.springframework.common.MyBeanPostProcessor"/>

</beans>

测试代码

UserDao

package cn.shark.springframework.bean;

import java.util.HashMap;
import java.util.Map;

public class UserDao {
    
    

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

    static {
    
    
        hashMap.put("10001", "巨大情");
        hashMap.put("10002", "巨二情");
        hashMap.put("10003", "巨三情");
    }

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

}

UserService

package cn.shark.springframework.bean;

/**
 * 测试bean
 *
 * @author Zsy
 * @date 2021-08-30 21:41
 */
public class UserService {
    
    

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

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

MyBeanFactoryPostProcessor

package cn.shark.springframework.common;

import cn.shark.springframework.beans.BeansException;
import cn.shark.springframework.beans.PropertyValue;
import cn.shark.springframework.beans.PropertyValues;
import cn.shark.springframework.beans.factory.ConfigurableListableBeanFactory;
import cn.shark.springframework.beans.factory.config.BeanDefinition;
import cn.shark.springframework.beans.factory.config.BeanFactoryPostProcessor;

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    
    

    /**
     * 在所有的 BeanDefinition 加载完成后,实例化 Bean 对象之前,提供修改 BeanDefinition 属性的机制
     *
     * @param beanFactory
     * @throws BeansException
     */
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    
    
        BeanDefinition beanDefinition = beanFactory.getBeanDefinition("userService");

        PropertyValues propertyValues=beanDefinition.getPropertyValues();

        propertyValues.addPropertyValue(new PropertyValue("company","改为:测试公司"));
    }
}

MyBeanPostProcessor

package cn.shark.springframework.common;

import cn.shark.springframework.bean.UserService;
import cn.shark.springframework.beans.BeansException;
import cn.shark.springframework.beans.factory.config.BeanPostProcessor;

public class MyBeanPostProcessor implements BeanPostProcessor {
    
    
    /**
     * 在 Bean 对象执行初始化方法之前,执行此方法
     *
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    
    
        if ("userService".equals(beanName)){
    
    
            UserService userService= (UserService) bean;
            userService.setLocation("改为:福建省");
        }
        return bean;
    }

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

测试代码

 @Test
    public void test_Processor(){
    
    
        ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("classpath:spring.xml");


        UserService userService = applicationContext.getBean("userService", UserService.class);
        String result = userService.queryUserInfo();
        System.out.println(result);

    }

结果

巨大情,改为:测试公司,改为:福建省

参考文献

《Spring 手撸专栏》第 7 章:所向披靡,实现应用上下文,自动识别、资源加载、扩展机制

UML基础(附绘制教程)

猜你喜欢

转载自blog.csdn.net/shark_chili3007/article/details/120471356