手搓spring迷你框架之旅-01 基本结构实现

手搓spring迷你框架之旅-01 基本结构实现

本人突然特别感兴趣于轮子开发 然现在很多公司对spring源码都有理解考察 并且学校只教简单的spring框架应用 知其然而不知其所以然 故本人将会借助深度思考ai加上自己的理解 完成我第一个轮子开发之spring框架的开发 起名为Shanshan框架

本篇将会实现最简单的自定义component注解+beanFactory进行测试

核心思想

首先整理一下简单的基础思想 spring最基本的思想是容器化思想 也就是借助component注解来将类放在容器BeanFactory中进行管理 BeanFactory作为核心容器类 需要对项目包结构进行扫描 然后将带有component注解的类给利用反射给加载进容器当中 从而实现管理

那么开始新建项目

首先新建一个maven项目 项目结构为:

(cmd命令tree /f . >tr.txt 生成)

├─src
│  ├─main
│  │  ├─java
│  │  │  └─com
│  │  │      └─dms
│  │  │          └─shanshan
│  │  │              │  Main.java
│  │  │              │  test.java
│  │  │              │  
│  │  │              └─core
│  │  │                  │  BeanFactory.java
│  │  │                  │  
│  │  │                  └─Annotation
│  │  │                          Component.java
│  │  │                          
│  │  └─resources
│  └─test

然后自定义Component.java注解 在Annotation包下创建Component.java 并写如下代码:

自定义注解

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

解释:

  • @Target(ElementType.TYPE):此注解仅允许在类中使用

  • @Retention(RetentionPolicy.RUNTIME) 此注解在运行时有效

有了这个注解 我们接下来就可以对类进行标记 在之后告诉BeanFactory我们要管理这个类

接下来 要实现BeanFactory容器

BeanFactory作为一个容器,我们的需求就是 对具有@Component注解的类进行管理 读取与加载 所以我们首先要扫描整个包 处理包路径 然后获得类路径 然后扫描具有@Component注解的类 故我们首先创建一下

public class BeanFactory {
    private Map<String, Object> beansMap=new HashMap<String, Object>();

    public Map<String, Object> getBeansMap() {
        return beansMap;
    }

    public BeanFactory(String basePackage){
        scanBean(basePackage);
    }
}

BeanFactory类 具有一个map作为属性 map的key为类的名称 value为类对象

加上一个路径构造器 传入一个base包路径

接着需要完善scanBean方法

public void scanBean(String basePackage){
        //baserPackage:包路径 把包路径替换为文件路径
        String path = basePackage.replace(".", "/");
        URL url=this.getClass().getClassLoader().getResource(path);
        //获取资源url
        if (url == null) {
            throw new RuntimeException("Package not found: " + basePackage);
        }
        File dir=new File(url.getFile());
        for (File file:dir.listFiles()){
            if (file.isDirectory()){
                scanBean(basePackage+"."+file.getName());
            } else if (file.getName().endsWith(".class")) {
                String className=basePackage+"."+file.getName().replace(".class", "");
                try{
                    //反射创建类
                    Class<?> clazz=Class.forName(className);
                    //判断是否有component注解
                    if (clazz.isAnnotationPresent(Component.class)){
                        Object instance=clazz.getDeclaredConstructor().newInstance();
                        //默认无参构造对象
                        beansMap.put(clazz.getSimpleName(), instance);
                    }
                }catch (Exception e){
                    System.out.println("出现错误 反射这边");
                }


            }
        }

    }

反射部分学习与解释:

  • 前面根据路径遍历listFiles当中的每个文件 如果文件是目录 就继续带上文件名递归扫描下一个包 知道扫描到.class

  • 扫描到类以后 利用反射加载类 类名就是Classname=basePackage+"."+file.getName().replace(".class", "");(全限定名)

  • 然后判断是否有@Component注解 如果有就创建无参构造对象( Object instance=clazz.getDeclaredConstructor().newInstance();)这样就创建的一个bean

  • 最后放进beansMap当中 BeanFactory的职责也就结束了

综上 进行测试

public class Main {
    public static void main(String[] args) {
        BeanFactory beanFactory=new BeanFactory("com.dms.shanshan");
        System.out.println(beanFactory.getBeansMap().toString());
    }
}

我们可以看到 我们将test类成功进行了管理并且能够读取到 大功告成!

本次同时学习了反射的基本原理和基本方法 和spring框架当中的容器化管理思想,也是小有成就 希望接下来能够不断完善 对spring源码有所理解

后记

仓库地址(不断更新):

https://gitee.com/du-mingshen1/hand-rubbing-spring-framework

全系列:杜明珅的手搓spring迷你框架系列

下一篇:手搓spring迷你框架之旅-02 依赖注入的实现