乐趣区

关于java:30个类手写Spring核心原理之依赖注入功能3

本文节选自《Spring 5 外围原理》

在之前的源码剖析中咱们曾经理解到,依赖注入(DI)的入口是 getBean() 办法,后面的 IoC 手写局部根本流程已通。先在 GPApplicationContext 中定义好 IoC 容器,而后将 GPBeanWrapper 对象保留到 Map 中。在 GPApplicationContext 中设计两个 Map:factoryBeanObjectCache 保留单例对象的缓存,factoryBeanInstanceCache 保留 GPBeanWrapper 的缓存,变量命名也和原生 Spring 统一,这两个对象的设计其实就是注册式单例模式的经典利用。


public class GPApplicationContext extends GPDefaultListableBeanFactory implements GPBeanFactory {private String [] configLocations;

    private GPBeanDefinitionReader reader;

    // 用来保障注册式单例的容器
    private Map<String,Object> factoryBeanObjectCache = new HashMap<String, Object>();

    // 用来存储所有的被代理过的对象
    private Map<String,GPBeanWrapper> factoryBeanInstanceCache = new ConcurrentHashMap<String, GPBeanWrapper>();
        
    ...

}

1 从 getBean() 办法开始

上面咱们从欠缺 getBean() 办法开始:


    @Override
    public Object getBean(String beanName) {GPBeanDefinition beanDefinition = super.beanDefinitionMap.get(beanName);

        try{

            // 生成告诉事件
            GPBeanPostProcessor beanPostProcessor = new GPBeanPostProcessor();

            Object instance = instantiateBean(beanDefinition);
            if(null == instance){return  null;}

            // 在实例初始化以前调用一次
            beanPostProcessor.postProcessBeforeInitialization(instance,beanName);

            GPBeanWrapper beanWrapper = new GPBeanWrapper(instance);

            this.factoryBeanInstanceCache.put(beanName,beanWrapper);

            // 在实例初始化当前调用一次
            beanPostProcessor.postProcessAfterInitialization(instance,beanName);

            populateBean(beanName,instance);

            // 通过这样调用,相当于给咱们本人留有了可操作的空间
            return this.factoryBeanInstanceCache.get(beanName).getWrappedInstance();}catch (Exception e){//            e.printStackTrace();
            return null;
        }
    }

2 instantiateBean() 办法反射创立实例


    // 传一个 BeanDefinition,就返回一个实例 Bean
    private Object instantiateBean(GPBeanDefinition beanDefinition){
        Object instance = null;
        String className = beanDefinition.getBeanClassName();
        try{

            // 因为依据 Class 能力确定一个类是否有实例
            if(this.factoryBeanObjectCache.containsKey(className)){instance = this.factoryBeanObjectCache.get(className);
            }else{Class<?> clazz = Class.forName(className);
                instance = clazz.newInstance();

                this.factoryBeanObjectCache.put(beanDefinition.getFactoryBeanName(),instance);
            }

            return instance;
        }catch (Exception e){e.printStackTrace();
        }

        return null;
    }
        

3 populateBean() 办法实现依赖注入


    private void populateBean(String beanName,Object instance){Class clazz = instance.getClass();

        if(!(clazz.isAnnotationPresent(GPController.class) ||
                clazz.isAnnotationPresent(GPService.class))){return;}

        Field [] fields = clazz.getDeclaredFields();

        for (Field field : fields) {if (!field.isAnnotationPresent(GPAutowired.class)){continue;}

            GPAutowired autowired = field.getAnnotation(GPAutowired.class);

            String autowiredBeanName = autowired.value().trim();

            if("".equals(autowiredBeanName)){autowiredBeanName = field.getType().getName();}

            field.setAccessible(true);

            try {field.set(instance,this.factoryBeanInstanceCache.get(autowiredBeanName). getWrappedInstance());

            } catch (IllegalAccessException e) {//                e.printStackTrace();
            }

        }

    }
        

4 GPBeanPostProcessor 后置处理器

原生 Spring 中的 BeanPostProcessor 是为对象初始化事件设置的一种回调机制。这个 Mini 版本中只做阐明,不做具体实现,感兴趣的“小伙伴”能够持续深入研究 Spring 源码。


package com.tom.spring.formework.beans.config;

public class GPBeanPostProcessor {

    // 为在 Bean 的初始化之前提供回调入口
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws Exception {return bean;}

    // 为在 Bean 的初始化之后提供回调入口
    public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception {return bean;}
}

至此,DI 局部就手写实现了,也就是说实现了 Spring 的外围局部。“小伙伴们”是不是发现其实还是很简略的?

退出移动版