当前位置: 首页 > news >正文

Spring-手写模拟Spring底层原理

概述

模拟大致的底层原理,为学习Spring源码做铺垫。

实现的功能:扫描路径、依赖注入、aware回调、初始化前、初始化、初始化后、切面

未实现的功能:构造器推断、循环依赖

重点:BeanDefinition、BeanPostProcessor

学习Spring源码的重点:设计模式、编码规范、设计思想、扩展点

启动类:

public class Yeah
{public static void main(String[] args){GaxApplicationContext gaxApplicationContext = new GaxApplicationContext(AppConfig.class);UserInterface userService = (UserInterface) gaxApplicationContext.getBean("userService");userService.test();}
}

关键方法:

public class GaxApplicationContext
{private Class configClass;private static final String SINGLETON = "singleton";private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();private Map<String, Object> singletonObjects = new HashMap<>();// Spring源码用的是LinkedListprivate List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();public GaxApplicationContext(Class configClass){this.configClass = configClass;// 扫描指定路径,找到所有@Component注解的类,封装成beanDefinition保存再Map中scan(configClass);// 思考个问题:beanDefinitionMap.keySet()和beanDefinitionMap.entrySet()两种遍历的区别?选用哪个好?for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()){String beanName = entry.getKey();BeanDefinition beanDefinition = entry.getValue();if (SINGLETON.equals(beanDefinition.getScope())){Object bean = createBean(beanName, beanDefinition);singletonObjects.put(beanName, bean);}}}private Object createBean(String beanName, BeanDefinition beanDefinition){Class clazz = beanDefinition.getType();Object instance = null;try{// 直接使用默认的无参构造器,多个构造器的场景未实现instance = clazz.getConstructor().newInstance();// 属性填充,依赖注入for (Field field : clazz.getDeclaredFields()){if (field.isAnnotationPresent(Autowired.class)){field.setAccessible(true);field.set(instance, getBean(field.getName()));}}// aware回调if (instance instanceof BeanNameAware){((BeanNameAware)instance).setBeanName(beanName);}// 初始化前for (BeanPostProcessor beanPostProcessor : beanPostProcessorList){instance = beanPostProcessor.postProcessBeforeInitialization(instance, beanName);}// 初始化if (instance instanceof InitializingBean){((InitializingBean)instance).afterPropertiesSet();}// 初始化后for (BeanPostProcessor beanPostProcessor : beanPostProcessorList){instance = beanPostProcessor.postProcessAfterInitialization(instance, beanName);}}catch (InstantiationException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e){e.printStackTrace();}return instance;}public Object getBean(String beanName){if (!beanDefinitionMap.containsKey(beanName)){throw new NullPointerException();}BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);if (SINGLETON.equals(beanDefinition.getScope())){Object singletonBean = singletonObjects.get(beanName);if (null == singletonBean){singletonBean = createBean(beanName, beanDefinition);singletonObjects.put(beanName, singletonBean);}return singletonBean;}else{// 原型BeanObject prototypeBean = createBean(beanName, beanDefinition);return prototypeBean;}}private void scan(Class configClass){if (configClass.isAnnotationPresent(ComponentScan.class)){ComponentScan componentScanAnnotation = (ComponentScan)configClass.getAnnotation(ComponentScan.class);String path = componentScanAnnotation.value();// path = com/gax/servicepath = path.replace(".", "/");ClassLoader classLoader = GaxApplicationContext.class.getClassLoader();URL resource = classLoader.getResource(path);assert resource != null;File file = new File(resource.getFile());if (file.isDirectory()){for (File f : Objects.requireNonNull(file.listFiles())){String absolutePath = f.getAbsolutePath();absolutePath = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));// 类加载器入参需要的格式:com.gax.service.XXXabsolutePath = absolutePath.replace("\\", ".");try{Class<?> clazz = classLoader.loadClass(absolutePath);if (clazz.isAnnotationPresent(Component.class)){if (BeanPostProcessor.class.isAssignableFrom(clazz)){BeanPostProcessor instance = (BeanPostProcessor)clazz.getConstructor().newInstance();beanPostProcessorList.add(instance);}Component componentAnnotation = clazz.getAnnotation(Component.class);String beanName = componentAnnotation.value();if ("".equals(beanName)){// 默认beanNamebeanName = Introspector.decapitalize(clazz.getSimpleName());}BeanDefinition beanDefinition = new BeanDefinition();beanDefinition.setType(clazz);if (clazz.isAnnotationPresent(Scope.class)){Scope scopeAnnotation = clazz.getAnnotation(Scope.class);String value = scopeAnnotation.value();beanDefinition.setScope(value);}else{// 默认单例BeanbeanDefinition.setScope(SINGLETON);}beanDefinitionMap.put(beanName, beanDefinition);}}catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException| InstantiationException | IllegalAccessException e){e.printStackTrace();}}}}}
}

gitee地址:

git clone https://gitee.com/seek6174/spring-seek.git

http://www.lryc.cn/news/207557.html

相关文章:

  • Scala【集合常用方法和函数操作(下)】
  • JS加密/解密之那些不为人知的基础逻辑运算符
  • flinksql kafka到mysql累计指标练习
  • pdf转jpg的方法【ps和工具方法】
  • 【已解决】Qt发送信号后,槽函数没有响应
  • Kafka入门05——基础知识
  • WordPress(7)配置邮箱发送功能
  • 简化路径(C++解法)
  • CS224W1.1——图机器学习介绍
  • docker搭建waline评论系统
  • sql server 生成连续日期和数字
  • 太极v14.0.4 免ROOT用Xposed
  • python DevOps
  • Git(四)底层命令:git对象、树对象、提交对象
  • LVS-DR模式+keepalived+nginx+tomcat实现动静分离、负载均衡、高可用实验
  • canvas 状态管理
  • vue中如何给后端过来的数组中每一个对象加一个新的属性和新的对象(不影响后端的原始数据)
  • SpringAOP源码解析之TargetSource(四)
  • Centos7 安装nvidia显卡驱动
  • 22 行为型模式-状态模式
  • Jetpack:018-Jetpack中的导航一
  • Linux常见问题解决操作(yum被占用、lsb无此命令、Linux开机进入命令界面等)
  • 层次式架构的设计理论与实践
  • 【shell】read -t -n1
  • 【嵌入式项目应用】__cJSON在单片机的使用
  • 【智能家居】
  • Android stdio 无法新建或打开AIDL文件(解决方法)
  • 如何进行渗透测试以提高软件安全性?
  • YOLOv5 添加 OTA,并使用 coco、CrowdHuman数据集进行训练。
  • SpringBoot 日志