Spring扫描逻辑原码解析(带图好理解)

news2025/7/19 16:39:06

先上流程图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

再上类图

在这里插入图片描述

再上代码

    public static void main(String[] args) {
        XsmApplicationContext applicationContext=new XsmApplicationContext(AppConfig.class);
        System.out.println(applicationContext.getBean("userService"));
        System.out.println(applicationContext.getBean("userService"));
        System.out.println(applicationContext.getBean("userService"));
    }
@ComponentScan("com.xiashiman.service")
public class AppConfig {}

@Component("userService")
//@Scope("prototype")
public class UserService {}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponentScan {
    String value();
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {
    String value();
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Scope {
    String value();
}
public class BeanDefinition {

    private Class clazz;
    private String scope;

    public BeanDefinition(Class clazz, String scope) {
        this.clazz = clazz;
        this.scope = scope;
    }

    public BeanDefinition() {
    }

    public Class getClazz() {
        return clazz;
    }

    public void setClazz(Class clazz) {
        this.clazz = clazz;
    }

    public String getScope() {
        return scope;
    }

    public void setScope(String scope) {
        this.scope = scope;
    }
}
public class XsmApplicationContext {

    private  Class configClass;

    private ConcurrentHashMap<String,Object> singletonObjects=new ConcurrentHashMap<>();//单例池
    private ConcurrentHashMap<String,BeanDefinition> beanDefinitionMap=new ConcurrentHashMap<>();

    public XsmApplicationContext(Class configClass) {
        this.configClass = configClass;
        //ComponentScan注解--->扫描路径---》扫描---》Beandefinition--->BeanDefinitionMap
        scan(configClass);
        //在启动时把所有单例bean创建好
        for(Map.Entry<String,BeanDefinition> entry:beanDefinitionMap.entrySet()){
            String beanName=entry.getKey();
            BeanDefinition beanDefinition=entry.getValue();
            if(beanDefinition.getScope().equals("singleton")){
                Object bean= createBean(beanDefinition); //单例bean
                singletonObjects.put(beanName,bean);
            }
        }
    }
    //根据bean的生命周期创建对象
    public Object createBean(BeanDefinition beanDefinition){
        Class clazz = beanDefinition.getClazz();
        try {
            Object instance = clazz.getDeclaredConstructor().newInstance();
            return instance;//返回实例对象
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return null;
    }

    private void scan(Class configClass) {
        if(configClass.isAnnotationPresent(ComponentScan.class)){
            //解析配置类
            //ComponentScan注解--->扫描路径---》扫描
            ComponentScan declaredAnnotation = (ComponentScan) configClass.getDeclaredAnnotation(ComponentScan.class);
            String path = declaredAnnotation.value(); //扫描路径 com.xiashiman.service
            path=path.replace(".","/"); //把·替换成/---》 com/xiashiman/service
            //扫描--->找出包下面的所有类
            //类加载器
            //Bootstrap----jre/lib
            //Ext----->jre/ext/lib
            //App----->classpath-----:E:\project\common\shousiCode\target\classes
            ClassLoader classLoader=XsmApplicationContext.class.getClassLoader();//app类加载器
            URL resource = classLoader.getResource(path);//通过路径获取资源
            File file=new File(resource.getFile());
            //判断是否是目录
            if(file.isDirectory()){
                File[] files = file.listFiles();//拿到目录下的所以文件
                for (File f:files){
                    String fileName = f.getAbsolutePath(); //E:\project\common\shousiCode\target\classes\com\xiashiman\service\UserService.class
                    //判断是否是class文件
                    if(fileName.endsWith(".class")){
                        //截取com到.class前的部分
                        String className= fileName.substring(fileName.indexOf("com\\"), fileName.indexOf(".class"));
                        className=className.replace("\\",".");  //替换成:com.xiashiman.service.UserService
                        //准备通过反射实例化对象
                        Class clazz=null;
                        try{
                            clazz=classLoader.loadClass(className); //反射获取类模板对象

                            if(clazz.isAnnotationPresent(Component.class)){
                                //表示当前类是一个bean
                                //解析类:判断是单例 还是原型
                                // BeanDefinition
                                Component componentAnntotaion= (Component) clazz.getDeclaredAnnotation(Component.class);
                                String beanName = componentAnntotaion.value();
                                BeanDefinition beanDefinition=new BeanDefinition();
                                beanDefinition.setClazz(clazz);
                                if(clazz.isAnnotationPresent(Scope.class)){
                                    Scope scopeAnntation= (Scope) clazz.getDeclaredAnnotation(Scope.class);
                                    beanDefinition.setScope(scopeAnntation.value());
                                }else{
                                    beanDefinition.setScope("singleton");
                                }
                                beanDefinitionMap.put(beanName,beanDefinition);
                            }
                        }catch (ClassNotFoundException e){
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

    public Object getBean(String beanName){
        if(beanDefinitionMap.containsKey(beanName)){
            BeanDefinition beanDefinition=beanDefinitionMap.get(beanName);
            if(beanDefinition.getScope().equals("singleton")){
                Object o=singletonObjects.get(beanName);
                return o;
            }else{
                //创建bean对象  怎么创建呢
                Object bean=createBean(beanDefinition);
                return bean;
            }
        }else{
            throw new NullPointerException("不存在对应的bean");
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/369887.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Laravel框架学习笔记——Laravel环境配置及安装(Ubuntu20.04为例)

目录引言1、安装Nginx2、安装PHP3、安装Composer4、搭建Laravel框架项目5、修改Nginx映射6、安装MySQL引言 好久没写博客了&#xff0c;因为个人需要&#xff0c; 所以要涉及到Laravel框架的学习&#xff0c;所以会出一系列的关于PHP的Laravel框架学习笔记&#xff0c;希望能够…

【平台数仓设计——2023】

平台数仓设计——2023前言一、选取大数据平台1、CDH大数据平台2、HDP大数据平台3、CDP大数据平台4、各种云数据中台二、选取调度平台1、DolphinScheduler(海豚调度)2、AzKaban3、Oozie4、Airflow5、corntab命令三、选取数仓设计方案1、离线数仓2、实时数仓3、离线实时一体化数仓…

尚医通 (二十二)预约下单

目录一、预约下单功能(一)1、需求2、搭建订单模块3、封装Feign调用获取就诊人接口4、封装Feign调用获取排班下单信息接口二、预约下单功能(二)1、实现生成订单接口三、预约下单功能(三)四、预约下单功能(四)1、生成订单后处理逻辑-封装短信接口2、生成订单后处理逻辑-更新排班数…

cracklib与libpwquality 评估密码的安全性

一、cracklib 检测密码强弱linux中采用pam pam_cracklib module来实现对密码强度的检测&#xff0c;可以通过配置让linux系统自动检测用户的密码是否为弱密码。yuminstall cracklib # centos apt-get install libcrack2 # ubuntu # 如果需要依赖此库做开发的话需要安装这个 y…

墨者——内部文件上传系统漏洞分析溯源 内部文件上传系统漏洞分析溯源

墨者——内部文件上传系统漏洞分析溯源 内部文件上传系统漏洞分析溯源 1.选择合适的文件上传 2.可以看到为*.asp文件 3.可以推测出此站点为IIS 4.上传shell.asp试试 5.上传报错&#xff0c;将其改名为shell.asp.txt上传&#xff0c;发现上传成功 6.有个问题就是服务器将我们所…

Node 10.0.8.6:9003 is unknown to cluster

解决方案解决方案一解决方案一 ① 概念介绍 公网ip&#xff1a;就是任意两台连接了互联网的电脑可以互相ping ip,能够通的ip 内网ip&#xff1a;只是在内网中使用无法与外网连接的ip ②问题背景 在腾讯云上搭建的一个redis集群&#xff0c;集群启动后 可以看到启动节点…

腾讯企微、泛微、契约锁举办的这场大会,超1000人共商数字化转型

全程数字化运营平台体验大会 2月23日下午&#xff0c;腾讯企业微信、泛微、契约锁在上海联合举办了全程数字化运营平台体验大会&#xff0c;旨在推动政企客户的数字化转型。 活动以“智能、协同、高效”为主题&#xff0c;吸引了上千位政府及企事单位的信息化负责人参与。 在…

Tapdata 和 Databend 数仓数据同步实战

作者&#xff1a;韩山杰https://github.com/hantmacDatabend Cloud 研发工程师基础架构在云计算时代也发生着翻天地覆的变化&#xff0c;对于业务的支持变成了如何能利用好云资源实现降本增效&#xff0c;同时更好的支撑业务也成为新时代技术人员的挑战。 本篇文章通过&#xf…

含泪推荐5款小体积,超实用的工具

大家好&#xff0c;我又来啦&#xff0c;今天给大家带来的5款软件&#xff0c;共同特点都是体积小、无广告、超实用&#xff0c;大家观看完可以自行搜索下载哦。 1.文字自动验证工具——LanguageTool LanguageTool是一款文字自动验证工具&#xff0c;不仅支持中英文&#xff…

如何将虚拟机ubuntu设置网路连接为桥接模式

当将虚拟机的网络适配器设置为NAT模式时&#xff0c;一切正常&#xff0c;可以ping通所有ip, 但是当设置为桥接模式时&#xff0c;ping命令会提示ubuntu connect: Network is unreachable 这是因为桥接模式没有设置正确&#xff0c;通过下面的步骤可以将桥接模式配置正确。 1…

iOS 生命周期 (最新最完整)

要知道APP的生命周期&#xff0c;首先要了解一下生命周期的5种状态&#xff0c;结合状态理解生命周期的使用。 一、应用的状态 应用的状态包括&#xff1a; 1.1 未运行&#xff08;Not running&#xff09; 程序没启动 1.2 未激活&#xff08;Inactive&#xff09; 程序在…

尚医通 (二十一)预约挂号功能

目录一、预约挂号详情1、需求2、预约挂号详情接口3、预约挂号详情前端二、预约确认1、需求2、预约确认接口3、预约确认前端一、预约挂号详情 1、需求 接口分析 &#xff08;1&#xff09;根据预约周期&#xff0c;展示可预约日期数据&#xff0c;按分页展示 &#xff08;2&…

JAVA设计模式之工厂模式讲解

目录 前言 开始表演 前言 Java中使用工厂模式的主要原因是为了实现代码的灵活性和可维护性。工厂模式是一种创建型设计模式&#xff0c;它提供了一种将对象的创建和使用进行分离的方式。具体来说&#xff0c;工厂模式可以将对象的创建过程封装在一个独立的工厂类中&#xff…

自动微分记录

计算图(数据流图):AI系统化问题 - 计算图的提出 计算图和自动微分 单算子切分、图的切分和调度 前端->统一表示->优化层->运行时态->底层库 语言 计算网络模型中间表示 计算图 自动微分 计算图优化 内存管理、计算图调度和执行 内核代码优化与编译 多硬件支持…

ip-guard如何在控制台上判断策略是否下发成功?

方法1.看控制台策略设置是否带*号,一般带*,然后刷新控制台依旧带*,说明策略没下发。可以点击刷新按钮进行刷新。 方法2.运行cmd,将控制台程序拖入命令行中,加参数-ad,回车运行。 然后,选中指定客户端,在维护-命令行,输入policy,

骨传导耳机是怎么发声的,骨传导耳机值得入手嘛

现在市面上除了我们平时比较常见的有线耳机、头戴耳机、真无线耳机&#xff0c;近两年还涌现出了一种有着黑科技之称的特别耳机——骨传导耳机&#xff0c;并且因其在运动场景下的优势过于明显而得到了众多运动爱好者的大力追捧。那么今天我们就来聊聊这款所谓的黑科技骨传导耳…

webform如何升级mvc

1.创建项目 给项目起名字然后指定存储位置 选择asp.net 空项目 2.新建model namespace WebFormToMvc {/// <summary>/// 用户模型/// </summary>public class UserModel{/// <summary>/// id/// </summary>public int Id { get; set; }/// <sum…

解决Chrome浏览器内置翻译无法使用的问题

hosts文件 hosts是一个没有扩展名的系统文件&#xff0c;可以用记事本等工具打开&#xff0c;主要作用是定义IP地址和主机名的映射关系&#xff0c;是一个映射IP地址和主机名的规定。当用户在浏览器中输入一个需要登录的网址时&#xff0c;系统会首先自动从hosts文件中寻找对应…

上海亚商投顾:沪指收跌0.62% 东数西算板块逆势领涨

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。市场情绪三大指数今日震荡调整&#xff0c;盘中集体跌超1%&#xff0c;随后沪指跌幅有所收窄。东数西算概念午后走强&#xf…

【FLASH存储器系列二十一】如何评估固态硬盘的性能?

我们以三星消费级SSD 990 PRO为例进行介绍&#xff0c;下图为其产品配置&#xff1a; 简单说明一下产品配置&#xff1a;990 pro容量有1T和2T两种规格&#xff0c;固态硬盘容量计算一般是1T1000GB1000000MB&#xff0c;与操作系统容量计算1T1024GB不一样&#xff0c;使用M.2外形…