文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

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

2024-12-02 13:10

关注

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

  1. public class GPApplicationContext extends GPDefaultListableBeanFactory implements GPBeanFactory { 
  2.  
  3.     private String [] configLocations; 
  4.  
  5.     private GPBeanDefinitionReader reader; 
  6.  
  7.     //用来保证注册式单例的容器 
  8.     private Map factoryBeanObjectCache = new HashMap(); 
  9.  
  10.     //用来存储所有的被代理过的对象 
  11.     private Map factoryBeanInstanceCache = new ConcurrentHashMap(); 
  12.  
  13.     ... 
  14.  

1 从getBean()方法开始

下面我们从完善getBean()方法开始:

  1.     @Override 
  2.     public Object getBean(String beanName) { 
  3.  
  4.         GPBeanDefinition beanDefinition = super.beanDefinitionMap.get(beanName); 
  5.  
  6.         try{ 
  7.  
  8.             //生成通知事件 
  9.             GPBeanPostProcessor beanPostProcessor = new GPBeanPostProcessor(); 
  10.  
  11.             Object instance = instantiateBean(beanDefinition); 
  12.             if(null == instance){ return  null;} 
  13.  
  14.             //在实例初始化以前调用一次 
  15.             beanPostProcessor.postProcessBeforeInitialization(instance,beanName); 
  16.  
  17.             GPBeanWrapper beanWrapper = new GPBeanWrapper(instance); 
  18.  
  19.             this.factoryBeanInstanceCache.put(beanName,beanWrapper); 
  20.  
  21.             //在实例初始化以后调用一次 
  22.             beanPostProcessor.postProcessAfterInitialization(instance,beanName); 
  23.  
  24.             populateBean(beanName,instance); 
  25.  
  26.             //通过这样调用,相当于给我们自己留有了可操作的空间 
  27.             return this.factoryBeanInstanceCache.get(beanName).getWrappedInstance(); 
  28.         }catch (Exception e){ 
  29. //            e.printStackTrace(); 
  30.             return null
  31.         } 
  32.     } 

2 instantiateBean()方法反射创建实例

  1. //传一个BeanDefinition,就返回一个实例Bean 
  2. private Object instantiateBean(GPBeanDefinition beanDefinition){ 
  3.     Object instance = null
  4.     String className = beanDefinition.getBeanClassName(); 
  5.     try{ 
  6.  
  7.         //因为根据Class才能确定一个类是否有实例 
  8.         if(this.factoryBeanObjectCache.containsKey(className)){ 
  9.             instance = this.factoryBeanObjectCache.get(className); 
  10.         }else
  11.             Class clazz = Class.forName(className); 
  12.             instance = clazz.newInstance(); 
  13.  
  14.             this.factoryBeanObjectCache.put(beanDefinition.getFactoryBeanName(),instance); 
  15.         } 
  16.  
  17.         return instance; 
  18.     }catch (Exception e){ 
  19.         e.printStackTrace(); 
  20.     } 
  21.  
  22.     return null

3 populateBean()方法完成依赖注入

  1.     private void populateBean(String beanName,Object instance){ 
  2.  
  3.         Class clazz = instance.getClass(); 
  4.  
  5.         if(!(clazz.isAnnotationPresent(GPController.class) || 
  6.                 clazz.isAnnotationPresent(GPService.class))){ 
  7.             return
  8.         } 
  9.  
  10.         Field [] fields = clazz.getDeclaredFields(); 
  11.  
  12.         for (Field field : fields) { 
  13.             if (!field.isAnnotationPresent(GPAutowired.class)){ continue; } 
  14.  
  15.             GPAutowired autowired = field.getAnnotation(GPAutowired.class); 
  16.  
  17.             String autowiredBeanName = autowired.value().trim(); 
  18.  
  19.             if("".equals(autowiredBeanName)){ 
  20.                 autowiredBeanName = field.getType().getName(); 
  21.             } 
  22.  
  23.             field.setAccessible(true); 
  24.  
  25.             try { 
  26.  
  27.                 field.set(instance,this.factoryBeanInstanceCache.get(autowiredBeanName). getWrappedInstance()); 
  28.  
  29.             } catch (IllegalAccessException e) { 
  30. //                e.printStackTrace(); 
  31.             } 
  32.  
  33.         } 
  34.  
  35.     } 

4 GPBeanPostProcessor后置处理器

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

  1. package com.tom.spring.formework.beans.config; 
  2.  
  3. public class GPBeanPostProcessor { 
  4.  
  5.     //为在Bean的初始化之前提供回调入口 
  6.     public Object postProcessBeforeInitialization(Object bean, String beanName) throws Exception { 
  7.         return bean; 
  8.     } 
  9.  
  10.     //为在Bean的初始化之后提供回调入口 
  11.     public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception { 
  12.         return bean; 
  13.     } 

至此,DI部分就手写完成了,也就是说完成了Spring的核心部分。“小伙伴们”是不是发现其实还是很简单的?

 

来源:Tom弹架构内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯