IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 手写简易版 Spring框架 -> 正文阅读

[Java知识库]手写简易版 Spring框架

作者:token keyword

前言

最近项目里有大量的 “长的很像的代码”。这类代码,用到了工厂模式、建造者模式,但是最终由于业务复杂,而且功能上是对接平台的,因此会有上百个这种类,每个都不一样。

出于对其优化的目的,我重学了下 Spring 框架,看看从框架层面,能不能有什么突破点。
后来,在对 Spring 的 Bean 的生命周期的学习中,看中了 BeanPostProcessor 这个前置和后置处理器。发现这框架还是得好好研究下,可能能让我们目前的项目代码能更加灵活、易懂。甚至达到开闭原则。

也正是这种想法,那对于简单的学习框架的使用,已经不能满足了,得从源码学起。而学习源码的第一课就是【写一个简易版的 Spring 框架】,用以熟悉框架中的思想。

我的简易版的代码位于这个仓库中:
https://gitee.com/fengsoshuai/demo-spring

目前已实现

1 简单校验

主要是对 Configuration 注解和 ComponentScan 注解的校验,要求配置类上要有这俩注解。

2 扫描配置

根据启动时传入的配置类,获取配置类上的注解 ComponentScan 中的参数,即包名。 根据包名扫描该包下的所有的 .class 文件,包的深度现在设置的是20,应该是够用了。

将扫描到的 .class 文件名,使用字符串截取的方式,组装出要用的类的全限定名。

3 根据扫描到的配置组装 BeanDefinition

根据第2步获取到的类名,加载到类。得到 Class。 再根据Class解析Class上是否带有 Component注解。

如果带有 Component 注解,将该注解上的属性进行解析,作为 bean 的名称。如果没有指定名称默认使用类名小写第一个字母作为bean的名称。

BeanDefinition 中有 以下属性:


    private Class<?> beanClass;
    private String scope;
    private boolean isLazy;

其中 beanClass 是bean对应的 Class 就是根据第2步获得的类的完整名称加载出来的。 scope 用来表示是单例bean还是多例bean。 isLazy表示当前生成bean是否是懒加载。

最终存储时,使用 beanName 作为 key,BeanDefinition 作为 value存储到一个Map中。

4 根据 BeanDefinition 创建非懒加载、并且是单例的bean,存储到单例池

这一步是根据 BeanDefinition 中的 beanClass,获取到该类的无参数构造器,在根据这个无参数构造器生成一个bean,同时将该bean存储到单例池中。

5 增加 BeanNameAware 接口

BeanNameAware 当类中需要使用 beanName时,实现此接口。 在初始化设置属性之后,对beanName 进行赋值。

6 增加 InitializingBean 接口

当对实例需要做属性设置值之后,再进行操作。 常用于对实例的属性值进行校验。

7 增加 BeanPostProcessor 接口

bean的后置处理器: 常用于扩展,在Bean初始化,设置属性值之后执行。或在刚刚通过构造器创建实例后执行(设置属性之前)。

延伸阅读

测试&包文件说明
在org.feng.demo包下,有一个Test类,目前暂时在里边使用 main方法进行测试。 至于 org.feng.framework,就是模拟spring框架的注解,接口,类的定义的位置。

其中各个注解的具体实现逻辑,基本都在DefaultAnnotationApplicationContext类内。

手写 Spring的代码

在这里插入图片描述
所有的代码就是这红框中的内容了。至于 org.feng.demo,是为了测试这个框架好不好用写的测试。

ApplicationContext

package org.feng.framework;

/**
 * 应用上下文
 *
 * @version v1.0
 * @author: fengjinsong
 * @date: 2022年04月09日 14时40分
 */
public interface ApplicationContext extends BeanFactory {
}

Autowird

package org.feng.framework;

import java.lang.annotation.*;

/**
 * 自动注入
 *
 * @version v1.0
 * @author: fengjinsong
 * @date: 2022年04月09日 14时47分
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Autowird {
}


BeanDefinition


package org.feng.framework;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

/**
 * bean描述
 *
 * @version v1.0
 * @author: fengjinsong
 * @date: 2022年04月09日 16时45分
 */
@ToString
@Data
@AllArgsConstructor
@NoArgsConstructor
public class BeanDefinition {

    private Class<?> beanClass;
    private String scope;
    private boolean isLazy;
}

BeanFactory

package org.feng.framework;

/**
 * 获取Bean的工厂类
 *
 * @version v1.0
 * @author: fengjinsong
 * @date: 2022年04月09日 14时43分
 */
public interface BeanFactory {

    Object getBean(String name);


    <T>T getBean(String name, Class<T> clazz);
}


BeanNameAware

package org.feng.framework;

/**
 * 设置bean名称:当想在该类中使用spring的beanName时,实现这个接口
 *
 * @version v1.0
 * @author: fengjinsong
 * @date: 2022年04月09日 18时17分
 */
public interface BeanNameAware {

    void setBeanName(String name);
}


BeanPostProcessor

package org.feng.framework;

/**
 * Bean的后置处理器
 *
 * @version v1.0
 * @author: fengjinsong
 * @date: 2022年04月09日 18时53分
 */
public interface BeanPostProcessor {

    default Object postProcessBeforeInitialization(Object bean, String beanName){
        return bean;
    };

    default Object postProcessAfterInitialization(Object bean, String beanName){
        return bean;
    };
}


Component

package org.feng.framework;

import java.lang.annotation.*;

/**
 * 组件注解
 *
 * @version v1.0
 * @author: fengjinsong
 * @date: 2022年04月09日 14时39分
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {
    /**
     * 对组件命名
     *
     * @return 存进容器时的名称
     */
    String value() default "";
}


ComponentScan

package org.feng.framework;

import java.lang.annotation.*;

/**
 * 组件扫描路径
 *
 * @version v1.0
 * @author: fengjinsong
 * @date: 2022年04月09日 14时49分
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponentScan {
    String value();
}


Configuration

package org.feng.framework;

import java.lang.annotation.*;

/**
 * 配置类的注解
 *
 * @version v1.0
 * @author: fengjinsong
 * @date: 2022年04月09日 14时56分
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Configuration {
}


DefaultAnnotationApplicationContext

package org.feng.framework;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 应用上下文实现
 *
 * @version v1.0
 * @author: fengjinsong
 * @date: 2022年04月09日 14时41分
 */
public class DefaultAnnotationApplicationContext implements ApplicationContext {

    /**
     * 配置类
     */
    private final Class<?> configClass;

    private static final String PROTOTYPE = "prototype";
    private static final String SINGLETON = "singleton";

    /**
     * beanName 和 bean 定义的映射
     */
    private static final Map<String, BeanDefinition> BEAN_DEFINITION_MAP = new HashMap<>(32);
    /**
     * 单例池
     */
    private static final Map<String, Object> SINGLETON_MAP = new ConcurrentHashMap<>();

    /**
     * 后置处理器
     */
    private static final List<BeanPostProcessor> BEAN_POST_PROCESSORS = new ArrayList<>();

    public DefaultAnnotationApplicationContext(Class<?> configClass) {
        this.configClass = configClass;
        // 校验配置、注解使用是否正常
        check(configClass);

        // 扫描包,获得bean定义
        scanConfig();

        // 非懒加载、单例bean生成实例
        createNonLazySingletonBean();
    }


    @Override
    public Object getBean(String name) {
        BeanDefinition beanDefinition = BEAN_DEFINITION_MAP.get(name);
        if (beanDefinition != null) {
            // 单例bean
            if (SINGLETON.equals(beanDefinition.getScope())) {
                // 处理懒加载
                if (beanDefinition.isLazy()) {
                    if (SINGLETON_MAP.containsKey(name)) {
                        return SINGLETON_MAP.get(name);
                    }
                    Object instance = creatInstance(name, beanDefinition);
                    SINGLETON_MAP.put(name, instance);
                    return instance;
                }
                // 非懒加载从单例池中取
                return SINGLETON_MAP.get(name);
            }

            // 多例bean
            if (PROTOTYPE.equals(beanDefinition.getScope())) {
                return creatInstance(name, beanDefinition);
            }
        }
        return null;
    }

    @Override
    public <T> T getBean(String name, Class<T> clazz) {
        BeanDefinition beanDefinition = BEAN_DEFINITION_MAP.get(name);
        if (beanDefinition != null) {
            // 单例bean
            if (SINGLETON.equals(beanDefinition.getScope()) && clazz == beanDefinition.getBeanClass()) {
                // 处理懒加载
                if (beanDefinition.isLazy()) {
                    if (SINGLETON_MAP.containsKey(name)) {
                        return (T) SINGLETON_MAP.get(name);
                    }
                    Object instance = creatInstance(name, beanDefinition);
                    SINGLETON_MAP.put(name, instance);
                    return (T) instance;
                }
                // 非懒加载从单例池中取
                return (T) SINGLETON_MAP.get(name);
            }

            // 多例bean
            if (PROTOTYPE.equals(beanDefinition.getScope()) && clazz == beanDefinition.getBeanClass()) {
                return (T) creatInstance(name, beanDefinition);
            }
        }
        return null;
    }

    /**
     * 扫描配置并注册bean定义
     */
    private void scanConfig() {
        // 获取要扫描的包名
        ComponentScan componentScan = configClass.getAnnotation(ComponentScan.class);
        String packageName = componentScan.value();
        // 获取包名下的完整类名
        List<String> fullClassNameList = parsePackageToFullClassNameList(packageName);
        for (String className : fullClassNameList) {
            try {
                // 通过类名加载类
                Class<?> aClass = DefaultAnnotationApplicationContext.class.getClassLoader().loadClass(className);
                // 该类使用了 Component 注解
                if (aClass.isAnnotationPresent(Component.class)) {
                    BeanDefinition beanDefinition = new BeanDefinition();
                    // 设置bean对应的类
                    beanDefinition.setBeanClass(aClass);
                    // 当前bean是后置处理器的实现类:当实现了BeanPostProcessor接口时
                    if (BeanPostProcessor.class.isAssignableFrom(aClass)) {
                        BEAN_POST_PROCESSORS.add((BeanPostProcessor) aClass.getDeclaredConstructor().newInstance());
                    }
                    // 懒加载
                    if (aClass.isAnnotationPresent(Lazy.class)) {
                        beanDefinition.setLazy(true);
                    }

                    // 判断是多例bean还是单例bean
                    if (aClass.isAnnotationPresent(Scope.class)) {
                        Scope scope = aClass.getAnnotation(Scope.class);
                        String scopeValue = scope.value();
                        if (scopeValue == null || "".equals(scopeValue) || SINGLETON.equals(scopeValue)) {
                            beanDefinition.setScope(SINGLETON);
                        }
                        // 多例bean
                        if (PROTOTYPE.equals(scopeValue)) {
                            beanDefinition.setScope(PROTOTYPE);
                        }
                    } else {
                        // 单例bean
                        beanDefinition.setScope(SINGLETON);
                    }

                    // 将 key=beanName,value=beanDefinition的映射存储到容器中
                    Component component = aClass.getAnnotation(Component.class);
                    String beanName = fixBeanName(component.value(), aClass);
                    BEAN_DEFINITION_MAP.put(beanName, beanDefinition);
                }
            } catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException | IllegalAccessException | InstantiationException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 非懒加载、单例bean生成实例,注册到容器
     */
    private void createNonLazySingletonBean() {
        BEAN_DEFINITION_MAP.forEach((beanName, beanDefinition) -> {
            // 非懒加载 并且是单例bean
            if (!beanDefinition.isLazy() && SINGLETON.equals(beanDefinition.getScope())) {
                Object instance = creatInstance(beanName, beanDefinition);
                SINGLETON_MAP.put(beanName, instance);
            }
        });
    }


    /**
     * 创建Bean
     *
     * @param beanDefinition bean定义
     * @param beanName       bean名称
     * @return 实例bean
     */
    private Object creatInstance(String beanName, BeanDefinition beanDefinition) {
        Object instance = null;
        Class<?> beanClass = beanDefinition.getBeanClass();
        try {
            instance = beanClass.getDeclaredConstructor().newInstance();

            // 属性赋值之前处理
            for (BeanPostProcessor beanPostProcessor : BEAN_POST_PROCESSORS) {
                beanPostProcessor.postProcessBeforeInitialization(instance, beanName);
            }

            // 属性填充
            Field[] declaredFields = beanClass.getDeclaredFields();
            for (Field declaredField : declaredFields) {
                if (declaredField.isAnnotationPresent(Autowird.class)) {
                    Object fieldBean = getBean(declaredField.getName());
                    declaredField.setAccessible(true);
                    declaredField.set(instance, fieldBean);
                }
            }

            // 设置beanName
            if (instance instanceof BeanNameAware) {
                ((BeanNameAware) instance).setBeanName(beanName);
            }
            // 属性设置后,增加的操作
            if (instance instanceof InitializingBean) {
                ((InitializingBean) instance).afterPropertiesSet();
            }

            // bean后置处理里
            for (BeanPostProcessor beanPostProcessor : BEAN_POST_PROCESSORS) {
                beanPostProcessor.postProcessAfterInitialization(instance, beanName);
            }
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            e.printStackTrace();
        }
        return instance;
    }

    /**
     * 解析传入的包名,获取其下的所有的类名(包深度是20)
     *
     * @param packageName 包名
     * @return 包名下的完整类名
     */
    private List<String> parsePackageToFullClassNameList(String packageName) {
        ClassLoader classLoader = DefaultAnnotationApplicationContext.class.getClassLoader();
        // 获取资源文件路径
        String path = packageName.replaceAll("\\.", "/");
        URL resource = classLoader.getResource(path);
        // 解析当前的类路径
        assert resource != null;
        try {
            // 获取包下的完整类名,文件深度为20
            return Files.walk(Path.of(resource.toURI()), 20)
                    .map(Path::toFile)
                    .filter(file -> file.getName().endsWith(".class"))
                    .map(File::getAbsolutePath)
                    .map(filePath -> filePath.replaceAll("\\\\", "/"))
                    .map(filePath -> filePath.substring(filePath.indexOf(path), filePath.indexOf(".class")))
                    .map(filePath -> filePath.replaceAll("/", "."))
                    .collect(Collectors.toList());
        } catch (IOException | URISyntaxException e) {
            e.printStackTrace();
        }
        return Collections.emptyList();
    }

    /**
     * 将类名首字母小写作为beanName的默认值
     *
     * @param beanName 实例在容器中的名称,可能为空
     * @param aClass   当前实例的类
     * @return 修正过的实例在容器中的名称
     */
    private String fixBeanName(String beanName, Class<?> aClass) {
        if (beanName == null || "".equals(beanName)) {
            String simpleName = aClass.getSimpleName();
            String firstLetter = simpleName.substring(0, 1);
            return firstLetter.toLowerCase(Locale.ROOT) + simpleName.substring(1);
        }
        return beanName;
    }

    /**
     * 校验注解 Configuration、ComponentScan 是否有在使用
     *
     * @param configClass 配置类
     */
    private void check(Class<?> configClass) {
        // 当前配置类必须有 Configuration注解
        boolean isConfigClass = configClass.isAnnotationPresent(Configuration.class);
        if (!isConfigClass) {
            throw new RuntimeException("请给配置类上加 Configuration 注解");
        }
        // 当前配置类必须有 ComponentScan注解
        boolean hasComponentScan = configClass.isAnnotationPresent(ComponentScan.class);
        if (!hasComponentScan) {
            throw new RuntimeException("请给配置类上加 ComponentScan 注解");
        }
    }
}


InitializingBean


package org.feng.framework;

/**
 * 初始化bean,在给bean属性赋值之后,执行方法。
 * <br>使用场景:在初始化后要做一些操作时。多用于属性校验检查
 *
 * @version v1.0
 * @author: fengjinsong
 * @date: 2022年04月09日 18时26分
 */
public interface InitializingBean {
    /**
     * 在属性设置之后执行
     */
    void afterPropertiesSet();
}

Lazy

package org.feng.framework;

import java.lang.annotation.*;

/**
 * 标注一个懒加载的类
 *
 * @version v1.0
 * @author: fengjinsong
 * @date: 2022年04月09日 16时25分
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Lazy {
}


Scope

package org.feng.framework;

import java.lang.annotation.*;

/**
 * 定义类在容器中是多例bean、单例bean<br>
 * 默认单例bean,标注value=prototype时,表示是一个多例bean
 *
 * @version v1.0
 * @author: fengjinsong
 * @date: 2022年04月09日 16时26分
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Scope {
    String value() default "";
}


  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-04-28 11:39:48  更:2022-04-28 11:42:12 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 2:45:38-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码