• 简单Spring源码解析(一) 容器启动


    一、创建spring容器

    首先建立Test类和service类

    在Test类中创建spring容器

    自定义两个注解@ComponmentScan和@Componment注解,提供扫描路径方法

    1. package com.spring;
    2. import java.lang.annotation.ElementType;
    3. import java.lang.annotation.Retention;
    4. import java.lang.annotation.RetentionPolicy;
    5. import java.lang.annotation.Target;
    6. @Target(ElementType.TYPE)
    7. @Retention(RetentionPolicy.RUNTIME)
    8. public @interface Component {
    9. String value() default "";
    10. }

    1. package com.spring;
    2. import java.lang.annotation.ElementType;
    3. import java.lang.annotation.Retention;
    4. import java.lang.annotation.RetentionPolicy;
    5. import java.lang.annotation.Target;
    6. @Target(ElementType.TYPE)
    7. @Retention(RetentionPolicy.RUNTIME)
    8. public @interface ComponentScan {
    9. String value() default "";
    10. }

    创建spring容器类和appconfig工具类

    二、手写模拟Spring扫描底层实现

    创建一个UserService的bean,扫描工具类看是否有通过这个注解得到的类信息。

    1. //spring容器类
    2. public class GaoApplicationContext {
    3. private Class configClass;
    4. public GaoApplicationContext(Class configClass) {
    5. this.configClass = configClass;
    6. //扫描工具类看是否有通过这个注解得到的类信息
    7. //这段代码的意思是从一个类的注解中获取ComponentScan注解,并将其赋值给componentScanAnnotation变量。
    8. //具体来说,configClass是一个类对象,getAnnotation(ComponentScan.class)是通过反射获取configClass类上的ComponentScan注解。
    9. //如果configClass类上存在ComponentScan注解,则返回该注解的实例;否则返回null。
    10. //将返回的注解实例赋值给componentScanAnnotation变量,可以通过该变量来访问注解的属性值。
    11. //通过这段代码,我们可以在运行时动态地获取类上的注解,并进一步处理注解的属性值。
    12. //(ComponentScan)是一种强制类型转换的写法,
    13. //将configClass.getAnnotation(ComponentScan.class)返回的注解实例转换为ComponentScan类型。
    14. //在Java中,通过反射获取注解实例时,返回的是Annotation类型,而不是具体的注解类型。
    15. //因此,如果我们需要访问注解的属性值或者调用注解的方法,就需要将其转换为具体的注解类型。这就是使用(ComponentScan)进行类型转换的作用。
    16. //在这段代码中,configClass.getAnnotation(ComponentScan.class)返回的注解实例被转换为ComponentScan类型,
    17. //并赋值给componentScanAnnotation变量,以便后续访问注解的属性值
    18. if (configClass.isAnnotationPresent(ComponentScan.class)){
    19. ComponentScan componentScanAnnotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
    20. //扫描路径 com.service(并不是扫描service目录下的文件,而是编译后.class文件即target文件夹service下的文件)
    21. String path = componentScanAnnotation.value();
    22. path = path.replace(".","/"); // com/service
    23. //传相对路径到classLoader里面 D:\test\spring\target\classes\com\service
    24. ClassLoader classLoader = GaoApplicationContext.class.getClassLoader();
    25. URL resource = classLoader.getResource(path);
    26. File file = new File(resource.getFile());
    27. System.out.println(file);
    28. //判断resource里面传的是否是一个文件夹
    29. if (file.isDirectory()){
    30. //获得所有文件夹的名称
    31. File[] files = file.listFiles();
    32. //得到想要的.class文件
    33. for (File f : files){
    34. //得到绝对路径的名字
    35. String fileName = f.getAbsolutePath();
    36. //判断是否是,class文件
    37. //判断你的.class文件名是不是一个bean
    38. //就是看你的对象有没有@Componment注解
    39. //通过反射判断获是否有@Componment注解
    40. if (fileName.endsWith(".class")){
    41. //com\service\UserService
    42. //获得类名
    43. String className = fileName.substring(fileName.indexOf("com"), fileName.indexOf(".class"));
    44. className = className.replace("\\",".");
    45. System.out.println(className);
    46. try {
    47. Class clazz = classLoader.loadClass(className);
    48. if(clazz.isAnnotationPresent(Component.class)){
    49. // Bean
    50. }
    51. }catch (ClassNotFoundException e){
    52. e.printStackTrace();;
    53. }
    54. }
    55. }
    56. }
    57. }
    58. }
    59. public Object getBean(String beanName){
    60. return null;
    61. }

    三、模拟BeanDefinition的生成

    创建BeanDifinition类,生成getter()、setter()方法,通过判断是否含有scope注解来进行生成

    第二步和第三步总的来说就是先扫描-->BeanDefinition-->beanDefinitionMap,扫描之后创建对象,将对象放入map容器当中,然后将所有的单例都查找出来并且创建对象实例化单例Bean存到单例池里面。

    四、测试

     我们可以测试一下,在test中获取UserService对象的时候,Userservice中不添加@Scope("prototype")和添加是否不同

    可以很明显的看出单例和多例的区别

  • 相关阅读:
    Java的设计模式基本概念及使用场景
    [论文笔记] Scaling Laws for Neural Language Models
    【每日一题】2216.美化数组的最少删除数-2023.11.21
    行列式、逆矩阵、列空间和零空间(3Blue1Brown学习笔记)
    MyBatis概述
    Pytorch中CrossEntropyLoss()详解
    Copilot with GPT-4与文心一言4.0:AI技术的未来
    UDP-GlcNAc,UDPAG,尿苷二磷酸-N-乙酰基葡萄糖胺,UDP-N-乙酰葡糖胺
    数据库(2):表的CRUD\内置函数\多表符合查询
    基于opencv 的OCR小票识别(1)
  • 原文地址:https://blog.csdn.net/qq_50838572/article/details/132863040