学习样例: 手写spring核心功能

文章目录


前言:
先前写过一篇基础版的spring控制反转及依赖注入的demo, 后面自身通过渠道学习, 对spring有了更清晰的认知, 故整理了spring核心功能如下代码样例:

先前的文章地址: 模拟spring控制反转及依赖注入

1.学习收获

通过手写模拟,了解Spring的底层源码启动过程
通过手写模拟,了解BeanDefinition、BeanPostProcessor的概念
通过手写模拟,了解Spring解析配置类等底层源码工作流程
通过手写模拟,了解依赖注入,Aware回调等底层源码工作流程
通过手写模拟,了解Spring AOP的底层源码工作流程

2.注意事项

该案例仅用于学习使用, demo中使用的都是java开发所必会的基础技能, 所以不用担心看不懂, but程序中会有一些小bug, 例没有处理循环依赖; 扫描时未递归查询clazz文件目录等, 故动手能力一般的不要随便调整文件的存放结构(包结构)

3.实现代码

  • spring注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Autowired {

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

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

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

    String value() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface WrxValue {

    String value() default "";
}
  • spring接口
/**
 * 核心: spring中有很多的"啊伟"回调
 * 说明: 实现思路与 InitializingBean差不多,都是在创建bean时去回调方法
 */
public interface BeanNameAware {
    /**
    * 创建bean时给实现类设置beanName
    * @Param: name beanName
    * @Author: wrx
    * @Date: 2021/9/5 14:53
    */
    void setBeanName(String name);
}
/**
* 核心: bean的后置处理器
* 说明: 创建bean的过程中,每一个bean都会遍历调用该接口的实现类方法,该功能非常强大,发挥你天马行空的想象力
* @Author: wrx
* @Date: 2021/9/5 13:20
*/
public interface BeanPostProcessor {

    /**
     * 后置处理器初始化前执行的方法
     * @Param: bean bean的实例
     * @Param: beanName bean名
     * @Return:
     * @Author: wrx
     * @Date: 2021/9/5 14:09
     */
    default Object postProcessBeforeInitialization(Object bean, String beanName) {
        return bean;
    }

    /**
    * 后置处理器初始化后执行的方法
    * @Param: bean bean的实例
    * @Param: beanName bean名
    * @Return:
    * @Author: wrx
    * @Date: 2021/9/5 14:09
    */
    default Object postProcessAfterInitialization(Object bean, String beanName) {
        return bean;
    }
}
/**
* 创建bean时的初始化接口
* @Author: wrx
* @Date: 2021/9/5 13:18
*/
public interface InitializingBean {
    /**
     * 创建bean过程中的自定义操作
     */
    void afterPropertiesSet();
}
  • spring BeanDefinition 及 ApplicationContext
/**
* 核心: Bean定义类
* 说明: 该类只是'bean定义',还需主动创建'bean'
* @Author: wrx
* @Date: 2021/9/4 18:10
*/
public class BeanDefinition {
    /**
     * 定义Class类型
     */
    private Class type;
    /**
     * 单例 or 多例
     */
    private String scope;
    /**
     * 是否懒加载
     */
    private boolean isLazy;

    public Class getType() {
        return type;
    }

    public void setType(Class type) {
        this.type = type;
    }

    public String getScope() {
        return scope;
    }

    public void setScope(String scope) {
        this.scope = scope;
    }

    public boolean isLazy() {
        return isLazy;
    }

    public void setLazy(boolean lazy) {
        isLazy = lazy;
    }
}
/**
* 容器
* @Author: wrx
* @Date: 2021/9/4 18:21
*/
public class WrxApplicationContext {

    /**
     * 配置类、即包扫描类,用于指定要扫描的路径
     */
    private Class configClass;
    /**
     * 扫描时存储BeanDefinition的 Map   key: BeanName   value: bean定义
     */
    private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
    /**
     * 扫描后创建单例bean
     */
    private Map<String, Object> singletonObjects = new HashMap<>();
    /**
     * 扫描时加入BeanPostProcessor的实现类到 后置处理器集合
     */
    private List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();

    /**
    * ApplicationContext构造方法,初始化时即做好创建Bean定义、创建Bean
    * @Param: configClass 包扫描类
    * @Author: wrx
    * @Date: 2021/9/4 23:28
    */
    public WrxApplicationContext(Class configClass) {
        this.configClass = configClass;
        // 扫描
        scan(configClass);
        // 扫描结束后,根据beanDefinitionMap存储单例Bean到singletonObjects
        for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
            String beanName = entry.getKey();
            BeanDefinition beanDefinition = entry.getValue();
            if (beanDefinition.getScope().equals("singleton")) {
                Object bean = createBean(beanName, beanDefinition);
                singletonObjects.put(beanName, bean);
            }
            //多例每次getBean都要new新的,不用处理
        }

    }

    /**
     * 创建Bean,且该过程需要对属性进行依赖注入
     * @param beanName
     * @param beanDefinition
     * @return
     */
    private Object createBean(String beanName, BeanDefinition beanDefinition) {
        Class clazz = beanDefinition.getType();
        Object instance = null;
        try {
            //此案例只处理了bean的无参构造的情况,实际还得处理有参的
            //clazz.newInstance 只能调用无参构造, clazz.getConstructor().newInstance()则可以支持有参构造
            instance = clazz.getConstructor().newInstance();
            for (Field field : clazz.getDeclaredFields()) {
                //对属性进行注解的依赖注入
                if (field.isAnnotationPresent(Autowired.class)) {
                    field.setAccessible(true);
                    //此处实际得先根据beanType找,多个再根据beanName去找,该demo只实现根据字段名找bean
                    field.set(instance, getBean(field.getName()));
                }
            }
            //与InitializingBean思路差不多
            if (instance instanceof BeanNameAware) {
                ((BeanNameAware)instance).setBeanName(beanName);
            }
            //每一个bean初始时前都要调用所有BeanPostProcessor实现类的postProcessBeforeInitialization方法
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
                instance = beanPostProcessor.postProcessBeforeInitialization(instance, beanName);
            }
            //添加对Bean初始化过程自定义操作的支持(实现InitializingBean即可)
            if (instance instanceof InitializingBean) {
                ((InitializingBean)instance).afterPropertiesSet();
            }
            //每一个bean初始时后都要调用所有BeanPostProcessor实现类的postProcessAfterInitialization方法
            //aop就是基于该功能实现
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
                instance = beanPostProcessor.postProcessAfterInitialization(instance, beanName);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return instance;
    }


    /**
    * 根据名称获取Bean
    * @Param: beanName bean名,例 userService
    * @Return: Bean对象
    * @Author: wrx
    * @Date: 2021/9/4 18:04
    */
    public Object getBean(String beanName) {
        //未定义的bean则直接抛异常
        if (!beanDefinitionMap.containsKey(beanName)) {
            throw new NullPointerException();
        }
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        //判断是bean定义中存储的是 单例还是多例
        if (beanDefinition.getScope().equals("singleton")) {
            //单例模式每次都会从单例池中获取bean,无则创建
            Object singletonBean = singletonObjects.get(beanName);
            if (singletonBean == null) {
                singletonBean = createBean(beanName, beanDefinition);
                singletonObjects.put(beanName, singletonBean);
            }
            return singletonBean;
        } else {
            //原型模式则直接创建bean
            Object prototypeBean = createBean(beanName, beanDefinition);
            return prototypeBean;
        }
    }


    /**
    * @Description: 包扫描,初始化Bean等
    * @Param: configClass 配置类
    * @Author: wrx
    * @Date: 2021/9/4 17:03
    */
    private void scan(Class configClass) {
        if (configClass.isAnnotationPresent(ComponentScan.class)) {
            ComponentScan componentScanAnnotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
            String path = componentScanAnnotation.value();
            // 例 com.wrx.service => com/wrx/service
            path = path.replace(".", "/");

            //ClassLoader classLoader = wrxApplicationContext.class.getClassLoader();
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            //根据相对路径获取到全路径
            URL resource = classLoader.getResource(path);
            File file = new File(resource.getFile());

            if (file.isDirectory()) {
                for (File f : file.listFiles()) {
                    //获取绝对路径
                    String absolutePath = f.getAbsolutePath();
                    //截取从com开始, .class结束 ,并由 com/wrx/service/xxx.class => com.wrx.service.xxx.class
                    absolutePath = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));
                    absolutePath = absolutePath.replace("\\", ".");

                    try {
                        //根据 com.wrx.service.xxx.class 加载为 Clazz
                        Class<?> clazz = classLoader.loadClass(absolutePath);
                        //判断该clazz是否包含 @Component, 包含则表示该类为Bean, 接着处理 '单例'及'多例'
                        if (clazz.isAnnotationPresent(Component.class)) {
                            //判断一个类是否实现了 BeanPostProcessor,是则实例化添加进集合
                            if (BeanPostProcessor.class.isAssignableFrom(clazz)) {
                                BeanPostProcessor instance = (BeanPostProcessor) clazz.getConstructor().newInstance();
                                beanPostProcessorList.add(instance);
                            }else{
                                //否则添加bean定义
                                createAndPutBeanDefinition(clazz);
                            }
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    /**
    * 创建bean定义并添加进map
    * @Param: clazz
    * @Author: wrx
    * @Date: 2021/9/5 13:55
    */
    private void createAndPutBeanDefinition(Class<?> clazz) {
        Component componentAnnotation = clazz.getAnnotation(Component.class);
        String beanName = componentAnnotation.value();
        if ("".equals(beanName)) {
            //如果没有配置beanName,则默认以类名首字母小写
            beanName = Introspector.decapitalize(clazz.getSimpleName());
        }
        //只要类包含@Compent表示该类为Bean,直接创建Bean定义
        BeanDefinition beanDefinition = new BeanDefinition();
        beanDefinition.setType(clazz);
        //看下该类是否有@Scope,有则直接设置配置的scope,无则默认单例
        if (clazz.isAnnotationPresent(Scope.class)) {
            Scope scopeAnnotation = clazz.getAnnotation(Scope.class);
            String value = scopeAnnotation.value();
            beanDefinition.setScope(value);
        } else {
            beanDefinition.setScope("singleton");
        }
        beanDefinitionMap.put(beanName, beanDefinition);
    }
}
  • 我们(程序员)使用spring的代码
package com.wrx.config;
import com.spring.annotation.ComponentScan;

@ComponentScan("com.wrx.service")
public class AppConfig {
}
package com.wrx.service;
import com.spring.annotation.Component;

/**
 * @author wrx
 */
@Component
public class OrderService {

    public void test() {
        System.out.println("OrderService test");
    }
}
package com.wrx.service;

/**
 * 仅用来测试jdk动态代理
 */
public interface UserInterface {

    void test();

    void test2();

    void test3();
}
package com.wrx.service;

import com.spring.Interface.BeanNameAware;
import com.spring.annotation.Autowired;
import com.spring.annotation.Component;
import com.spring.annotation.WrxValue;

/**
 * @author wrx
 */
@Component
//@Scope("prototype")
//@Scope("singleton")
public class UserService implements UserInterface, BeanNameAware {

    @Autowired
    private OrderService orderService;

    @WrxValue("测试bean初始化前给test赋值")
    private String initValue;

    /**
     * 假设你希望知道该bean的名字,可以实现aware,创建bean时会回调aware中的方法
     */
    private String beanName;

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
    }

    @Override
    public void test() {
        System.out.println(beanName);
    }
    @Override
    public void test2() {
        orderService.test();
    }
    @Override
    public void test3() {
        System.out.println(initValue);
    }
}
package com.wrx.service;

import com.spring.Interface.BeanPostProcessor;
import com.spring.annotation.Component;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * BeanPostProcessor的实现类
 * @author wrx
 */
@Component
public class WrxBeanPostProcessor implements BeanPostProcessor {
    /**
     * 后置处理器初始化后执行的方法
     * @Param: bean bean的实例
     * @Param: beanName bean名
     * @Return:
     * @Author: wrx
     * @Date: 2021/9/5 14:09
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        //假设该后置处理器我只想针对 userService,因为每个bean初始化时都会调用BeanPostProcessor的实现方法,所以加if判断
        if (beanName.equals("userService")) {
            //AOP实际上也是基于BeanPostProcessor实现的,此处模拟aop的jdk代理,返回代理对象
            Object proxyInstance = Proxy.newProxyInstance(WrxBeanPostProcessor.class.getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    // 此处可以写切面逻辑
                    System.out.println("切面逻辑");
                    return method.invoke(bean, args);
                }
            });
            return proxyInstance;
        }
        return bean;
    }
}
package com.wrx.service;

import com.spring.Interface.BeanPostProcessor;
import com.spring.annotation.Component;
import com.spring.annotation.WrxValue;

import java.lang.reflect.Field;

/**
 * BeanPostProcessor的实现类
 * @author wrx
 */
@Component
public class WrxValueBeanPostProcessor implements BeanPostProcessor {

    /**
     * 后置处理器初始化前执行的方法
     * @Param: bean bean的实例
     * @Param: beanName bean名
     * @Return:
     * @Author: wrx
     * @Date: 2021/9/5 14:09
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        //此处我自定义的功能是,在bean初始化前,对有@WrxValue的属性进行赋值
        for (Field field : bean.getClass().getDeclaredFields()) {
            if (field.isAnnotationPresent(WrxValue.class)) {
                field.setAccessible(true);
                try {
                    field.set(bean, field.getAnnotation(WrxValue.class).value());
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
        return bean;
    }
}
  • 测试代码
package com.wrx;

import com.spring.WrxApplicationContext;
import com.wrx.config.AppConfig;
import com.wrx.service.UserInterface;

/**
 * @author wrx
 */
public class Test {

    public static void main(String[] args) {
        /*UserService.class --> 无参构造(多个时推断构造方法)-->普通对象-->依赖注入(属性赋值)
         -->初始化前(@PostCostruct)-->初始化(Initialzingean)-->初始化后(AOP,基于BeanPostProcess)-->代理对象-->Bean */

        // 扫描--->创建单例Bean BeanDefinition BeanPostPRocess
        WrxApplicationContext applicationContext = new WrxApplicationContext(AppConfig.class);

        UserInterface userService = (UserInterface) applicationContext.getBean("userService");
        userService.test();
        userService.test2();
        userService.test3();
    }
}
上一篇:AOP收集信息


下一篇:什么?CSS颜色基本样式