手写spring第八章-定义标记类型Aware接口,实现感知容器对象

前言

我们在之前的文章中实现了spring框架中大部分的功能,到本章为止我们的框架开始逐渐强大。但是这么强大的框架功能都是属于他自己的,我们如何可以如果要获取框架的某一部分能力该怎么做呢?

需求分析

日常开发中,我们可以配置xml完成依赖注入,但是这个bean在开发中我们需要做调整,总不能再通过配置修改bean吧?所以,我们有没有办法在项目运行过程中操作容器对bean容器进行相关的操作呢?

实现思路

解决方案概述

通过阅读spring的源码,我们发现spring框架对这种需求的解决方案很有技巧性,既然需要框架的能力,那么我们就定义一个接口Aware,假如用户需要beanFactory的能力,那么我们就定义一个BeanFactoryAware接口继承Aware,暴露一个setBeanFactory方法。假如用户需要ClassLoader的能力,那么我们就定义一个BeanClassLoaderAware接口继承Aware,暴露一个setBeanClassLoaderAware方法。
然后在实现bean初始化过场中,我们在代码中判断,如果这个bean是是否属于Aware,若属于我们就去判断他继承了那些Aware,例如实现了BeanFactoryAware,那么我就值bean初始化的时候调用这个bean的setBeanFactory将bean容器交由这个bean进行自己所需要的处理。

类图

类图如下所示,可以看出spring在对bean初始化的时候
可以看出spring在bean初始化的时候有对bean进行相应判断,属于那种Aware就set那种Aware的能力,需要注意一下一个特殊情况,ApplicationContext是spring自己的bean,并不能被我们所控制,所以我们必须在ApplicationContext的实现refresh让他通过ApplicationContextAwareProcessor把自己传给需要它的对象。
在这里插入图片描述

相关代码

Aware

package cn.shark.springframework.beans.factory;

/**
 * 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 {
    
    
}

BeanClassLoaderAware

package cn.shark.springframework.beans.factory;

public interface BeanClassLoaderAware {
    
    

    void setBeanClassLoader(ClassLoader classLoader);
}

BeanNameAware

package cn.shark.springframework.beans.factory;

public interface BeanNameAware extends Aware {
    
    

    void setBeanName(String name);

}

BeanFactoryAware

package cn.shark.springframework.beans.factory;


import cn.shark.springframework.beans.BeansException;

public interface BeanFactoryAware extends Aware {
    
    

    void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}

ApplicationContextAware

package cn.shark.springframework.beans.factory;

import cn.shark.springframework.beans.BeansException;
import cn.shark.springframework.context.ApplicationContext;

public interface ApplicationContextAware extends Aware {
    
    
    void setApplicationContext(ApplicationContext applicationContext) throws BeansException;

}

AbstractAutowireCapableBeanFactory

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

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

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

/**
 * AutowireCapableBeanFactory 前后置处理器操作
 * AbstractBeanFactory  前后置处理器操作
 */
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(beanName, beanDefinition, args);

            applyPropertyValues(beanName, bean, beanDefinition);

            bean = initializeBean(beanName, bean, beanDefinition);
        } catch (Exception e) {
    
    
            throw new BeansException("Instantiation of bean failed", e);
        }

        registerDisposableBeanIfNecessary(beanName, bean, beanDefinition);
        addSingleton(beanName, bean);
        return bean;
    }

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

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


        Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);

        try {
    
    
            invokeInitMethods(beanName, wrappedBean, beanDefinition);
        } catch (Exception e) {
    
    
            throw new BeansException("Invocation of init method of bean[" + beanName + "] failed", e);
        }

        wrappedBean = applyBeanPostProcessorsAfterInitialization(bean, beanName);

        return wrappedBean;
    }

    private void invokeInitMethods(String beanName, Object bean, BeanDefinition beanDefinition) throws Exception {
    
    
        if (bean instanceof InitializingBean) {
    
    
            ((InitializingBean) bean).afterPropertiesSet();
        }

        String initMethodName = beanDefinition.getInitMethodName();
        if (StrUtil.isNotEmpty(initMethodName)) {
    
    
            Method initMethod = beanDefinition.getBeanClass().getMethod(initMethodName);
            if (null == initMethod) {
    
    
                throw new BeansException("Could not find an init method named '" + initMethodName + "' on bean with name '" + beanName + "'");
            }
            initMethod.invoke(bean);
        }

    }

    protected void registerDisposableBeanIfNecessary(String beanName, Object bean, BeanDefinition beanDefinition) {
    
    
        if (bean instanceof DisposableBean || StrUtil.isNotEmpty(beanDefinition.getDestroyMethodName())) {
    
    
            registerDisposableBean(beanName, new DisposableBeanAdapter(bean, beanName, beanDefinition));
        }
    }


    protected Object createBeanInstance(String beanName, BeanDefinition beanDefinition, Object[] args) {
    
    
        Constructor constructorToUse = null;
        Class<?> beanClass = beanDefinition.getBeanClass();
        Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();
        for (Constructor<?> ctor : declaredConstructors) {
    
    
            if (null != args && ctor.getParameterTypes().length == args.length) {
    
    
                constructorToUse = ctor;
                break;
            }
        }

        return getInstantiationStrategy().instantiate(beanName, beanDefinition, constructorToUse, args);
    }


    protected void applyPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition) {
    
    
        try {
    
    
            for (PropertyValue pv : beanDefinition.getPropertyValues().getPropertyValues()) {
    
    
                String name = pv.getName();
                Object value = pv.getValue();
                if (value instanceof BeanReference) {
    
    
                    BeanReference beanReference = (BeanReference) value;
                    value = getBean(beanReference.getBeanName());
                }
                BeanUtil.setFieldValue(bean, name, value);
            }
        } catch (Exception e) {
    
    
            throw new BeansException("Error setting property values:" + beanName);
        }
    }


    public InstantiationStrategy getInstantiationStrategy() {
    
    
        return instantiationStrategy;
    }

    public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy) {
    
    
        this.instantiationStrategy = instantiationStrategy;
    }

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

AbstractApplicationContext

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.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();

//   添加 ApplicationContextAwareProcessor,让继承自 ApplicationContextAware 的 Bean 对象都能感知所属的 ApplicationContext
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

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

    @Override
    public void registerShutdownHook() {
    
    
        Runtime.getRuntime().addShutdownHook(new Thread(this::close));
    }

    @Override
    public void close() {
    
    
        getBeanFactory().destroySingletons();
    }
}

测试

配置

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

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

    <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<>();

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

}

userService

package cn.shark.springframework.bean;

import cn.shark.springframework.beans.BeansException;
import cn.shark.springframework.beans.factory.*;
import cn.shark.springframework.context.ApplicationContext;

/**
 * 测试bean
 *
 * @author Zsy
 * @date 2021-08-30 21:41
 */
public class UserService implements InitializingBean, DisposableBean, BeanFactoryAware, BeanClassLoaderAware, BeanNameAware, ApplicationContextAware {
    
    

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

    private ApplicationContext applicationContext;

    private BeanFactory beanFactory;

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

    @Override
    public void destroy() throws Exception {
    
    
        System.out.println("执行:UserService.destroy");
    }

    /**
     * bean处理了属性填充后调用
     *
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception {
    
    
        System.out.println("执行:UserService.afterPropertiesSet");
    }

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

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

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

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

    public ApplicationContext getApplicationContext() {
    
    
        return applicationContext;
    }

    public BeanFactory getBeanFactory() {
    
    
        return beanFactory;
    }
}

测试代码

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

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

        System.out.println(userService.getApplicationContext());

        UserDao userDao = (UserDao) userService.getBeanFactory().getBean("userDao");
        String name = userDao.queryUserName("10001");
        System.out.println("name:"+name);

    }

输出结果

执行:init-method
setBeanClassLoader
setBeanName
执行:UserService.afterPropertiesSet
巨大情,改为:测试公司,改为:福建省
cn.shark.springframework.context.support.ClassPathXmlApplicationContext@7cf10a6f
name:巨大情
执行:UserService.destroy
执行:destroy-method

参考文献

《Spring 手撸专栏》第 9 章:虎行有雨,定义标记类型Aware接口,实现感知容器对象

猜你喜欢

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