手写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月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
76 2
|
1月前
|
数据采集 监控 前端开发
二级公立医院绩效考核系统源码,B/S架构,前后端分别基于Spring Boot和Avue框架
医院绩效管理系统通过与HIS系统的无缝对接,实现数据网络化采集、评价结果透明化管理及奖金分配自动化生成。系统涵盖科室和个人绩效考核、医疗质量考核、数据采集、绩效工资核算、收支核算、工作量统计、单项奖惩等功能,提升绩效评估的全面性、准确性和公正性。技术栈采用B/S架构,前后端分别基于Spring Boot和Avue框架。
|
21天前
|
存储 缓存 Java
Spring面试必问:手写Spring IoC 循环依赖底层源码剖析
在Spring框架中,IoC(Inversion of Control,控制反转)是一个核心概念,它允许容器管理对象的生命周期和依赖关系。然而,在实际应用中,我们可能会遇到对象间的循环依赖问题。本文将深入探讨Spring如何解决IoC中的循环依赖问题,并通过手写源码的方式,让你对其底层原理有一个全新的认识。
41 2
|
1月前
|
前端开发 Java 开发者
Spring生态学习路径与源码深度探讨
【11月更文挑战第13天】Spring框架作为Java企业级开发中的核心框架,其丰富的生态系统和强大的功能吸引了无数开发者的关注。学习Spring生态不仅仅是掌握Spring Framework本身,更需要深入理解其周边组件和工具,以及源码的底层实现逻辑。本文将从Spring生态的学习路径入手,详细探讨如何系统地学习Spring,并深入解析各个重点的底层实现逻辑。
66 9
|
3月前
|
缓存 安全 Java
Spring框架中Bean是如何加载的?从底层源码入手,详细解读Bean的创建流程
从底层源码入手,通过代码示例,追踪AnnotationConfigApplicationContext加载配置类、启动Spring容器的整个流程,并对IOC、BeanDefinition、PostProcesser等相关概念进行解释
327 24
|
3月前
|
缓存 Java 开发工具
Spring是如何解决循环依赖的?从底层源码入手,详细解读Spring框架的三级缓存
三级缓存是Spring框架里,一个经典的技术点,它很好地解决了循环依赖的问题,也是很多面试中会被问到的问题,本文从源码入手,详细剖析Spring三级缓存的来龙去脉。
232 24
|
3月前
|
XML 缓存 Java
手写Spring源码(简化版)
Spring包下的类、手写@ComponentScan注解、@Component注解、@Autowired注解、@Scope注解、手写BeanDefinition、BeanNameAware、InitializingBean、BeanPostProcessor 、手写AnnotationConfigApplicationContext
手写Spring源码(简化版)
|
2月前
|
Java Spring
Spring底层架构源码解析(三)
Spring底层架构源码解析(三)
166 5
|
2月前
|
XML Java 数据格式
Spring底层架构源码解析(二)
Spring底层架构源码解析(二)
|
2月前
|
Java Spring 容器
Spring IOC、AOP与事务管理底层原理及源码解析
【10月更文挑战第1天】Spring框架以其强大的控制反转(IOC)和面向切面编程(AOP)功能,成为Java企业级开发中的首选框架。本文将深入探讨Spring IOC和AOP的底层原理,并通过源码解析来揭示其实现机制。同时,我们还将探讨Spring事务管理的核心原理,并给出相应的源码示例。
148 9