栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

手写简易版 Spring框架

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

手写简易版 Spring框架

文章目录
  • 前言
  • 目前已实现
    • 1 简单校验
    • 2 扫描配置
    • 3 根据扫描到的配置组装 BeanDefinition
    • 4 根据 BeanDefinition 创建非懒加载、并且是单例的bean,存储到单例池
    • 5 增加 BeanNameAware 接口
    • 6 增加 InitializingBean 接口
    • 7 增加 BeanPostProcessor 接口
    • 延伸阅读
  • 手写 Spring的代码
    • ApplicationContext
    • Autowird
    • BeanDefinition
    • BeanFactory
    • BeanNameAware
    • BeanPostProcessor
    • Component
    • ComponentScan
    • Configuration
    • DefaultAnnotationApplicationContext
    • InitializingBean
    • Lazy
    • Scope

前言

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

出于对其优化的目的,我重学了下 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;


public interface ApplicationContext extends BeanFactory {
}

Autowird
package org.feng.framework;

import java.lang.annotation.*;


@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;


@ToString
@Data
@AllArgsConstructor
@NoArgsConstructor
public class BeanDefinition {

    private Class beanClass;
    private String scope;
    private boolean isLazy;
}

BeanFactory
package org.feng.framework;


public interface BeanFactory {

    Object getBean(String name);


    T getBean(String name, Class clazz);
}


BeanNameAware
package org.feng.framework;


public interface BeanNameAware {

    void setBeanName(String name);
}


BeanPostProcessor
package org.feng.framework;


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.*;


@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {
    
    String value() default "";
}


ComponentScan
package org.feng.framework;

import java.lang.annotation.*;


@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponentScan {
    String value();
}


Configuration
package org.feng.framework;

import java.lang.annotation.*;


@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;


public class DefaultAnnotationApplicationContext implements ApplicationContext {

    
    private final Class configClass;

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

    
    private static final Map BEAN_DEFINITION_MAP = new HashMap<>(32);
    
    private static final Map SINGLETON_MAP = new ConcurrentHashMap<>();

    
    private static final List 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 getBean(String name, Class 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;
    }

    
    private void scanConfig() {
        // 获取要扫描的包名
        ComponentScan componentScan = configClass.getAnnotation(ComponentScan.class);
        String packageName = componentScan.value();
        // 获取包名下的完整类名
        List 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();
            }
        }
    }

    
    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);
            }
        });
    }


    
    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;
    }

    
    private List 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();
    }

    
    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;
    }

    
    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;


public interface InitializingBean {
    
    void afterPropertiesSet();
}

Lazy
package org.feng.framework;

import java.lang.annotation.*;


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


Scope
package org.feng.framework;

import java.lang.annotation.*;


@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Scope {
    String value() default "";
}


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/843212.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号