(造轮子)手写Spring框架-Bean的Aware接口&bean作用域,增加prototype的支持&FactoryBean

113 阅读2分钟

Bean的Aware接口&bean作用域,增加prototype的支持&FactoryBean

代码地址:WangChao-ly/chao-spring at aware-interface (github.com)

建议订阅博主专栏,从下到上系统手写spring源码,体会其中过程!

  1. Bean的Aware接口 Aware接口总的来说是可以让用户得到自己所属的BeanFactory和Application
  • Aware接口
/**
 * 标记类接口,实现该接口能感知容器类接口
 * @author WangChao
 * @version 1.0
 * @date 2023/6/28 9:48
 */
public interface Aware {
}
  • BeanFactoryAware:该接口是用来获取Bean对应的BeanFactory,用来标识注入的bean是不是需要获取它的BeanFactory。
public interface BeanFactoryAware extends Aware{
    /**
     * 设置所属BeanFactory
     * @param beanFactory
     */
    void setBeanFactory(BeanFactory beanFactory);
}
  • initializeBean方法中,判断bean是不是BeanFactoryAware类型,如果是,则将当前的BeanFactory注入进去。
protected Object initializeBean(String beanName,Object bean,BeanDefinition beanDefinition){
    //设置BeanFactory
    if(bean instanceof BeanFactoryAware){
        ((BeanFactoryAware) bean).setBeanFactory(this);
    }
    //执行BeanPostProcessor的前置处理
    Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean,beanName);
    try{
        invokeInitMethods(beanName,wrappedBean,beanDefinition);
    }catch (Throwable ex) {
        throw new BeansException("Invocation of init method of bean[" + beanName + "] failed", ex);
    }
    //执行BeanPostProcessor的后置处理
    wrappedBean = applyBeanPostProcessorsAfterInitialization(bean,beanName);
    return wrappedBean;
}
  • ApplicationContext同理,不同的是,它是用的一个BeanPostProcessor切面,切面中检测到是否为继承了ApplicationContextAware类,如果是,则在bean中设置其ApplicationContext信息。
  • 测试代码
  1. bean作用域,增加prototype的支持
  • 在BeanDefinition中扩展几个属性,包括scope和是否单例等
    private String scope = SCOPE_SINGLETON;
    /**
     * 提供判断方法
     */
    private boolean singleton = true;
    private boolean prototype = false;

    /**
     * 设置是否单例
     * @param scope
     */
    public void setScope(String scope){
        this.scope = scope;
        this.singleton = SCOPE_SINGLETON.equals(scope);
        this.prototype = SCOPE_PROTOTYPE.equals(scope);
    }

    public boolean isSingleton(){
        return this.singleton;
    }

    public boolean isPrototype(){
        return this.prototype;
    }
  • 在xml读取时候,读取对应的scope信息,看用户设置是不是单例,从而设置对应的BeanDefinitin信息
    //设置是否单例
    if(StrUtil.isNotEmpty(beanScope)){
        beanDefinition.setScope(beanScope);
    }
  • 在创建Bean时,如果不是单例,不需要将bean加入容器中,同时也不需要注册有销毁功能的bean
    //注册有销毁方法的bean
    registerDisposableBeanIfNecessary(beanName,bean,beanDefinition);

    //不是单例不需要加入容器中
    if(beanDefinition.isSingleton()){
        addSingleton(beanName,bean);
    }
    
    /**
     * 注册有销毁方法的bean,即bean继承自DisposableBean或有自定义的销毁方法
     * @param beanName
     * @param bean
     * @param beanDefinition
     */
    protected void registerDisposableBeanIfNecessary(String beanName,Object bean,BeanDefinition beanDefinition){
        //只有singleton类型bean会执行销毁方法
        if(beanDefinition.isSingleton()){
            if(bean instanceof DisposableBean || StrUtil.isNotEmpty(beanDefinition.getDestroyMethodName())){
                registerDisposableBean(beanName,new DisposableBeanAdapter(bean,beanName,beanDefinition));
            }
        }
    }
  • 测试
    • spring.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-4.0.xsd">
    
        <bean id="car" class="org.springframework.test.ioc.bean.Car" scope="prototype">
            <property name="brand" value="porsche"/>
        </bean>
    </beans>
    
    • 测试代码
      public class PrototypeBeanTest {
          @Test
          public void testPrototype() throws Exception {
              ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:prototype-bean.xml");
    
              Car car1 = applicationContext.getBean("car", Car.class);
              Car car2 = applicationContext.getBean("car", Car.class);
              Assert.isFalse(car1==car2);
          }
      }
    
  1. FactoryBean FactoryBean接口主要用于标识一个bean是不是FactoryBean对象,如果是,则获取该对象的时候,会从一个Map缓存中获取,如果缓存不存在,则从FactoyBean的getObject方法中得到一个对象,主要代码如下:
    private final Map<String, Object> factoryBeanObjectCache = new HashMap<>();

    @Override
    public Object getBean(String beanName) throws BeansException {
        //如果已经存在该bean,则直接调用方法返回
        Object sharedInstance  = getSingleton(beanName);
        if(sharedInstance!=null){
            //如果是FactoryBean,从FactoryBean#getObject中创建bean
            return getObjectForBeanInstance(sharedInstance,beanName);
        }
        BeanDefinition beanDefinition = getBeanDefinition(beanName);
        Object bean = createBean(beanName, beanDefinition);
        return getObjectForBeanInstance(bean,beanName);
    }

    protected Object getObjectForBeanInstance(Object beanInstance,String beanName){
        Object object = beanInstance;
        if(beanInstance instanceof FactoryBean){
            FactoryBean factoryBean = (FactoryBean)beanInstance;
            try{
                if(factoryBean.isSingleton()){
                    //singleton作用域bean,从缓存中获取
                    object = this.factoryBeanObjectCache.get(beanName);
                    if(object==null){
                        object = factoryBean.getObject();
                        this.factoryBeanObjectCache.put(beanName,object);
                    }
                }else{
                    //prototype作用域bean,新创建bean
                    object = factoryBean.getObject();
                }
            }catch (Exception ex) {
                throw new BeansException("FactoryBean threw exception on object[" + beanName + "] creation", ex);
            }
        }
        return object;
    }
  • FactroyBean实例如下,往泛型中存入Car对象,然后提供getObject方法:
public class CarFactoryBean implements FactoryBean<Car> {
    private String brand;

    @Override
    public Car getObject() throws Exception {
        Car car = new Car();
        car.setBrand(brand);
        return car;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    public void setBrand(String brand){
        this.brand = brand;
    }
}

总结:以上是Spring中常用的三种东西实现方法,具体代码看开头代码链接。