30个类手写Spring核心原理之依赖注入功能(3)

简介: 在之前的源码分析中我们已经了解到,依赖注入(DI)的入口是getBean()方法,前面的IoC手写部分基本流程已通。先在GPApplicationContext中定义好IoC容器,然后将GPBeanWrapper对象保存到Map中。在GPApplicationContext中设计两个Map:factoryBeanObjectCache保存单例对象的缓存,factoryBeanInstanceCache保存GPBeanWrapper的缓存,变量命名也和原生Spring一致,这两个对象的设计其实就是注册式单例模式的经典应用。

本文节选自《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的核心部分。“小伙伴们”是不是发现其实还是很简单的?


本文为“Tom弹架构”原创,转载请注明出处。技术在于分享,我分享我快乐!

如果您有任何建议也可留言评论或私信,您的支持是我坚持创作的动力。

原创不易,坚持很酷,都看到这里了,小伙伴记得点赞、收藏、在看,一键三连加关注!如果你觉得内容太干,可以分享转发给朋友滋润滋润!

相关文章
|
10天前
|
XML Java 程序员
Spring6框架中依赖注入的多种方式(推荐构造器注入)
依赖注入(DI)是一种过程,对象通过构造函数参数、工厂方法的参数或在对象实例构建后设置的属性来定义它们的依赖关系(即与其一起工作的其他对象)。
23 3
|
8天前
|
前端开发 Java 程序员
Spring Boot统一功能处理(拦截器, 统一数据返回格式, 统一异常处理)
Spring Boot统一功能处理(拦截器, 统一数据返回格式, 统一异常处理)
20 1
|
9天前
|
Java Spring 容器
【Spring底层原理】BeanFactory的实现
【Spring底层原理】BeanFactory的实现
17 0
|
12天前
|
Java Spring 容器
Spring底层原理之 BeanFactory 与 ApplicationContext
Spring底层原理之 BeanFactory 与 ApplicationContext
23 3
|
12天前
|
Java Spring 容器
Spring注解开发,bean的作用范围及生命周期、Spring注解开发依赖注入
Spring注解开发,bean的作用范围及生命周期、Spring注解开发依赖注入
24 1
Spring注解开发,bean的作用范围及生命周期、Spring注解开发依赖注入
|
12天前
|
Java Spring 容器
Spring依赖注入方式,自动装配及自动装配特征
Spring依赖注入方式,自动装配及自动装配特征
12 1
|
21天前
|
开发框架 监控 Java
深入探索Spring Boot的监控、管理和测试功能及实战应用
【5月更文挑战第14天】Spring Boot是一个快速开发框架,提供了一系列的功能模块,包括监控、管理和测试等。本文将深入探讨Spring Boot中监控、管理和测试功能的原理与应用,并提供实际应用场景的示例。
21 2
|
21天前
|
监控 安全 Java
Spring cloud原理详解
Spring cloud原理详解
29 0
|
XML Java API
Spring 依赖注入的方式,你了解哪些?
前言 依赖查找和依赖注入是 Spring 实现 IoC 容器提供的两大特性,相对于依赖查找,Spring 更推崇的是使用依赖注入,本篇先对 Spring 中依赖注入的几种方式进行介绍,后续再分享其实现。
205 0
Spring 依赖注入的方式,你了解哪些?
|
Java 测试技术 开发者
Spring 有哪几种依赖注入方式?官方是怎么建议使用的呢?
IDEA 提示 Field injection is not recommended 在使用IDEA 进行Spring 开发的时候,当你在字段上面使用@Autowired注解的时候,你会发现IDEA 会有警告提示:
257 0
Spring 有哪几种依赖注入方式?官方是怎么建议使用的呢?