手写Spring基础源码(1)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

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


一、目录结构

二、相关部分代码

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注解

@ComponentScan("com.example.service")
public class AppConfig {
}
@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源码,有了更深的理解。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山河亦问安

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值