手写Spring基础源码(1)

简介: 手写Spring基础源码(1)

前言

通过手写模拟Spring源码了解Spring底层源码启动原理与工作工程。第一部分为通过@ComponetScan扫描相应的包获取Bean实例。这里未设置@Scope,默认都是单例。


一、目录结构


a497a370d6bd4d50b2f586b9b36701e0.png

二、相关部分代码

1.Spring启动类

public class Test {
    public static void main(String args[]){
        try {
            ApplicationContext applicationContext=new ApplicationContext(AppConfig.class);
             Userservice bean = (Userservice)applicationContext.getBean("userservice");
             bean.test();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

2.AppConfig类和ComponentScan注解

1. @ComponentScan("com.example.service")
2. public class AppConfig {
3. }
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ComponentScan {
    String value() default "";
}

3.BeanDefinition

public class BeanDefinition {
    private  Class clazz;
    public BeanDefinition(Class clazz) {
        this.clazz = clazz;
    }
    public BeanDefinition() {
    }
    public Class getClazz() {
        return clazz;
    }
    public void setClazz(Class clazz) {
        this.clazz = clazz;
    }
}

4.ApplicationContext类

获取配置类的注解扫描路径,通过类加载器获取该路径下的资源,然后遍历资源下的各个文件,判断当前类是不是一个Bean实例,将BeanName和BeanDefinition对象存储到Map集合中。然后遍历该Map集合,添加到单例池中。

public ApplicationContext(Class configClass) throws ClassNotFoundException {
        this.configClass = configClass;
        ComponentScan annotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
        String value = annotation.value();
        System.out.println(value);
        value=value.replace('.','/');
//        类加载器应用
        ClassLoader classLoader=ApplicationContext.class.getClassLoader();
//        获取类加载器下当前目录下的资源
        URL resource = classLoader.getResource(value);
        File file=new File(resource.getFile());
        if(file.isDirectory()){
            File[] files=file.listFiles();
            for(File f:files){
//                获取当前资源下的class文件
                String absolutePath = f.getAbsolutePath();
                if(absolutePath.endsWith(".class")){
                    String className=absolutePath.substring(absolutePath.indexOf("com"),absolutePath.indexOf(".class"));
                    className=className.replace("\\",".");
                    Class<?> loadClass = classLoader.loadClass(className);
                    if(loadClass.isAnnotationPresent(Componet.class)){
                        Componet declaredAnnotation = loadClass.getDeclaredAnnotation(Componet.class);
                        String value1 = declaredAnnotation.value();
                        BeanDefinition beanDefinition=new BeanDefinition();
                        beanDefinition.setClazz(loadClass);
                        beanDefinitionHashMap.put(value1,beanDefinition);
                    }
                }
            }
        }
        for(String beanName:beanDefinitionHashMap.keySet()){
               BeanDefinition beanDefinition=beanDefinitionHashMap.get(beanName);
            Object bean = createBean(beanDefinition);
            hashMap.put(beanName,bean);
        }
    }

createBean方法

 public  Object createBean(BeanDefinition beanDefinition){
         Class clazz=beanDefinition.getClazz();
        try {
            Object o = clazz.getDeclaredConstructor().newInstance();
            return o;
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return null;
    }

getBean方法

public Object getBean(String beanName){
        if(beanDefinitionHashMap.containsKey(beanName)){
            BeanDefinition beanDefinition = beanDefinitionHashMap.get(beanName);
            Object o = hashMap.get(beanName);
            return o;
        }
        else {
            throw new NullPointerException();
        }
    }

总结

通过简单手写Spring源码,有了更深的理解。

相关文章
|
1月前
|
XML 缓存 Java
Spring源码之 Bean 的循环依赖
循环依赖是 Spring 中经典问题之一,那么到底什么是循环依赖?简单说就是对象之间相互引用, 如下图所示: 代码层面上很好理解,在 bean 创建过程中 class A 和 class B 又经历了怎样的过程呢? 可以看出形成了一个闭环,如果想解决这个问题,那么在属性填充时要保证不二次创建 A对象 的步骤,也就是必须保证从容器中能够直接获取到 B。 一、复现循环依赖问题 Spring 中默认允许循环依赖的存在,但在 Spring Boot 2.6.x 版本开始默认禁用了循环依赖 1. 基于xml复现循环依赖 定义实体 Bean java复制代码public class A {
|
2月前
|
监控 数据可视化 关系型数据库
微服务架构+Java+Spring Cloud +UniApp +MySql智慧工地系统源码
项目管理:项目名称、施工单位名称、项目地址、项目地址、总造价、总面积、施工准可证、开工日期、计划竣工日期、项目状态等。
307 6
|
2月前
Spring5源码(45)-@Transactional声明式事物(三)事物创建
Spring5源码(45)-@Transactional声明式事物(三)事物创建
41 0
|
2月前
|
Java 关系型数据库 数据库连接
Spring源码解析--深入Spring事务原理
本文将带领大家领略Spring事务的风采,Spring事务是我们在日常开发中经常会遇到的,也是各种大小面试中的高频题,希望通过本文,能让大家对Spring事务有个深入的了解,无论开发还是面试,都不会让Spring事务成为拦路虎。
35 1
|
2月前
|
Java 应用服务中间件 Spring
Spring5源码(50)-SpringMVC源码阅读环境搭建
Spring5源码(50)-SpringMVC源码阅读环境搭建
42 0
|
1月前
|
Java 测试技术 数据库连接
【Spring源码解读!底层原理高级进阶】【下】探寻Spring内部:BeanFactory和ApplicationContext实现原理揭秘✨
【Spring源码解读!底层原理高级进阶】【下】探寻Spring内部:BeanFactory和ApplicationContext实现原理揭秘✨
|
2天前
|
XML 人工智能 Java
Spring Bean名称生成规则(含源码解析、自定义Spring Bean名称方式)
Spring Bean名称生成规则(含源码解析、自定义Spring Bean名称方式)
|
9天前
|
Java 关系型数据库 MySQL
一套java+ spring boot与vue+ mysql技术开发的UWB高精度工厂人员定位全套系统源码有应用案例
UWB (ULTRA WIDE BAND, UWB) 技术是一种无线载波通讯技术,它不采用正弦载波,而是利用纳秒级的非正弦波窄脉冲传输数据,因此其所占的频谱范围很宽。一套UWB精确定位系统,最高定位精度可达10cm,具有高精度,高动态,高容量,低功耗的应用。
一套java+ spring boot与vue+ mysql技术开发的UWB高精度工厂人员定位全套系统源码有应用案例
|
1月前
|
Java Spring
使用spring实现邮件的发送(含测试,源码,注释)
使用spring实现邮件的发送(含测试,源码,注释)
7 0
|
1月前
|
Java Spring 容器
【Spring源码】单例创建期间进行同步可能会导致死锁?
通过这个标题我们就可以思考本次的阅读线索了,看起来可以学到不少东西。1. 旧代码的死锁是怎么产生的。2. 贡献者通过改变什么来解决本次PR的问题呢?而阅读线索2的答案也显而易见,就是上文提到的通过后台线程来创建Micrometer单例...
42 3