手写Spring框架源码,你离大厂又进了一步

379 阅读5分钟

手写一个简易版Spring框架源码

之前跟着周瑜老师手写了一个简易版spring,代码不多,通俗易懂,能帮大家更简单的理解spring底层实现

准备工作

先写一个spring项目基础的几个部分

启动测试类

package com.hong;

import com.hong.service.OrderService;
import com.spring.HongApplicationContext;

public class Test {

    public static void main(String[] args) {
        // 启动 spring
        HongApplicationContext hongApplicationContext = new HongApplicationContext(AppConfig.class);

        // getBean()
        OrderService orderService = (OrderService) hongApplicationContext.getBean("orderService");
        System.out.println(orderService);
}

配置类 AppConfig

package com.hong;

import com.spring.ComponmentScan;

@ComponmentScan("com.hong.service")
public class AppConfig {
}

业务层

OrderService

package com.hong.service;

import com.spring.Component;

@Component("userService")
public class UserService{

}

OrderService

package com.hong.service;

import com.spring.*;

@Component("orderService")
@Scope("prototype")
public class OrderService implements InitializingBean, BeanNameAware {

    @AutoWired
    private UserService userService;

    private String beanName;

    public void test() {
        System.out.println(userService);
        System.out.println("Aware="+beanName);
    }

    @Override
    public void afterPropertiesSet() {
        System.out.println("初始化");
    }

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

基本注解

AutoWired

package com.spring;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.METHOD,ElementType.CONSTRUCTOR})
public @interface AutoWired {

}

Component

实例化到spring容器中

package com.spring;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

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

    String value() default "";
}

ComponentScan

作用就是根据定义的扫描路径,把符合扫描规则的类装配到spring容器中

package com.spring;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

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

    String value() default "";

}

Scope(作用域)

import java.lang.annotation.Target;

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

    String value() default "singleton";
}

实现Spring的扫描逻辑

核心类

HongApplicationContext 核心接口或容器,允许容器通过应用程序上下文环境创建、获取、管理bean。为应用程序提供配置的中央接口

Class HongApplicationContext
    private List<Class> scan(Class configClass) {
        List<Class> classList = new ArrayList<>();
        ComponmentScan componmentScan = (ComponmentScan) configClass.getAnnotation(ComponmentScan.class);
        String scanPath = componmentScan.value();  // com.hong.service  ----> com/hong/service
        // 非懒加载的单例 @Lazy @Scope
        // 生成单例bean---->单例池

        scanPath = scanPath.replace(".","/");

        // 如何扫描类
        ClassLoader classLoader = HongApplicationContext.class.getClassLoader();
        URL resource = classLoader.getResource(scanPath);

        String s = null;
        try {
            s = URLDecoder.decode(resource.getFile(), "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        File file = new File(s);  // 目录

        // 指定的目录下的文件列表,可能是class,可能是txt
        File[] files = file.listFiles();

        for (File f : files) {
            String absolutePath = f.getAbsolutePath();
            absolutePath = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"))
                    .replace("\", ".");
            System.out.println("absolutePath="+absolutePath);
            // class文件加载进来
            try {
                Class<?> clazz = classLoader.loadClass(absolutePath);

                classList.add(clazz);

            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        return classList;
    }

@AutoWired注解的实现原理

spring bean的建模对象----BeanDefinition

bean的作用域,bean的注入模型,bean是否是懒加载等等信息,Class是无法抽象出来的,故而需要一个BeanDefinition类来抽象这些信息,以便于spring能够完美的实例化一个bean

package com.spring;

// 表示bean的定义
public class BeanDefinition {

    private String scope;
    private Class beanClass;

    public String getScope() {
        return scope;
    }

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

    public Class getBeanClass() {
        return beanClass;
    }

    public void setBeanClass(Class beanClass) {
        this.beanClass = beanClass;
    }
}

核心类中扩展代码

private ConcurrentMap<String,BeanDefinition> beanDefinitionMap = new ConcurrentHashMap();
// 单例池
private ConcurrentHashMap<String,Object> singletonObjects = new ConcurrentHashMap();

public HongApplicationContext(Class configClass) {
    // 扫描类
    List<Class> classList = scan(configClass);
    // 扫描到类了之后。解析这个类,Component,BeanDefinition(@Scope)
    for (Class clazz : classList) {
        BeanDefinition beanDefinition = new BeanDefinition();
        beanDefinition.setBeanClass(clazz);
        // if (clazz.isAnnotationPresent(Component.class)){}
        Component component = (Component) clazz.getAnnotation(Component.class);
        // 存在这个注解,证明就是个bean,拿到bean的名字
        String beanName = component.value();
        System.out.println("beanName="+beanName);
        if (clazz.isAnnotationPresent(Scope.class)){
            Scope scope = (Scope) clazz.getAnnotation(Scope.class);
            beanDefinition.setScope(scope.value());
        }else {
            beanDefinition.setScope("singleton");
        }
        beanDefinitionMap.put(beanName,beanDefinition);
   }
    for (String beanName : beanDefinitionMap.keySet()) {
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if (beanDefinition.getScope().equals("singleton")){
            // 生成这个bean
            Object bean = createBean(beanName,beanDefinition);
            singletonObjects.put(beanName,bean);
        }
    }
    // 生成单例bean(非懒加载) ---> 单例池
 }
 

private Object createBean(String beanName,BeanDefinition beanDefinition) {
    Class beanClass = beanDefinition.getBeanClass();
    try {
        // 实例化
        Object bean = beanClass.getDeclaredConstructor().newInstance();
        // 填充属性(依赖注入)
        Field[] fields = beanClass.getDeclaredFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(AutoWired.class)) {
                // 拿到属性
                Object userService = getBean(field.getName());
                // 赋值
                field.setAccessible(true);
                field.set(bean,userService);
                }
            }
            return bean;
        }catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return null;
    }

    public Object getBean(String beanName){
        // 原型的话 判断是不是原型
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if (beanDefinition.getScope().equals("prototype")){
            return createBean(beanName,beanDefinition);
        }else {
            // 单例池中去拿
            Object bean = singletonObjects.get(beanName);
            if (bean == null){
                Object o = createBean(beanName,beanDefinition);
                singletonObjects.put(beanName,o);

                return o;
            }
            return bean;
        }
    }
}

Spring中bean初始化原理

运行顺序

  • Spring IOC容器实例化Bean
  • 调用BeanPostProcessorpostProcessBeforeInitialization方法
  • 调用bean实例的初始化方法
  • 调用BeanPostProcessorpostProcessAfterInitialization方法

ii.png

InitializingBean

InitializingBean接口为bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是继承该接口的类,在初始化bean的时候都会执行该方法。

package com.spring;

public interface InitializingBean {

    public void afterPropertiesSet();
}

BeanNameAware接口

让Bean对Name或id有知觉

@AutoWired
private UserService userService;

private String beanName;

userService通过@AutoWired注解依赖注入,而beanName就需要实现BeanNameAware接口来赋值操作

package com.spring;

public interface BeanNameAware {

    public void setBeanName(String beanName);
}

BeanPostProcessor

Spring IOC容器给我们提供的一个扩展接口,可以在对象初始化前后执行程序逻辑

public interface BeanPostProcessor {

    //bean初始化方法调用前被调用
    Object postProcessBeforeInitialization(Object bean, String beanName);

    //bean初始化方法调用后被调用
    Object postProcessAfterInitialization(Object bean, String beanName);
}

HongBeanPostProcessor

package com.hong.service;

import com.spring.BeanPostProcessor;
import com.spring.Component;

// @Component不仅仅代表@Bean的功能 是个组件
@Component
public class HongBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        System.out.println("初始化前");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        System.out.println("初始化后");
        return bean;
    }
}

HongApplicationContext完整逻辑代码

package com.spring;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

public class HongApplicationContext {

    private ConcurrentMap<String,BeanDefinition> beanDefinitionMap = new ConcurrentHashMap();
    // 单例池
    private ConcurrentHashMap<String,Object> singletonObjects = new ConcurrentHashMap();
    // 扩展
    private List<BeanPostProcessor> beanPostProcessorsList = new ArrayList<>();

    public HongApplicationContext(Class configClass) {
        // 扫描类
        List<Class> classList = scan(configClass);
        // 扫描到类了之后。解析这个类,Component,BeanDefinition(@Scope)
        for (Class clazz : classList) {
            BeanDefinition beanDefinition = new BeanDefinition();
            beanDefinition.setBeanClass(clazz);
            // if (clazz.isAnnotationPresent(Component.class)){}
            Component component = (Component) clazz.getAnnotation(Component.class);
            // 存在这个注解,证明就是个bean,拿到bean的名字
            String beanName = component.value();
            System.out.println("beanName="+beanName);
            if (clazz.isAnnotationPresent(Scope.class)){
                Scope scope = (Scope) clazz.getAnnotation(Scope.class);
                beanDefinition.setScope(scope.value());
            }else {
                beanDefinition.setScope("singleton");
            }
            // clazz是不是BeanPostProcessor派生出来的
            if (BeanPostProcessor.class.isAssignableFrom(clazz) ){
                try {
                    BeanPostProcessor bpp = (BeanPostProcessor) clazz.getDeclaredConstructor().newInstance();
                    beanPostProcessorsList.add(bpp);
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                }
            }

            beanDefinitionMap.put(beanName,beanDefinition);
        }

        for (String beanName : beanDefinitionMap.keySet()) {
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
            if (beanDefinition.getScope().equals("singleton")){
                // 生成这个bean
                Object bean = createBean(beanName,beanDefinition);
                singletonObjects.put(beanName,bean);
            }
        }
        // 生成单例bean(非懒加载) ---> 单例池

    }

    private Object createBean(String beanName,BeanDefinition beanDefinition) {
        Class beanClass = beanDefinition.getBeanClass();
        try {
            // 实例化
            Object bean = beanClass.getDeclaredConstructor().newInstance();
            // 填充属性(依赖注入)
            Field[] fields = beanClass.getDeclaredFields();
            for (Field field : fields) {
                if (field.isAnnotationPresent(AutoWired.class)) {
                    // 拿到属性
                    Object userService = getBean(field.getName());
                    // 赋值
                    field.setAccessible(true);
                    field.set(bean,userService);
                }
            }
            // Aware 新建一个接口 方法新加一个参数(扩展机制)
            if (bean instanceof BeanNameAware) {
                ((BeanNameAware) bean).setBeanName(beanName);
            }
            // 初始化之前 可以调用程序员定义的逻辑
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorsList) {
                bean = beanPostProcessor.postProcessBeforeInitialization(bean, beanName);
            }

            // 初始化
            if (bean instanceof InitializingBean) {
                ((InitializingBean)bean).afterPropertiesSet();
            }
            // 初始化之后 可以调用程序员定义的逻辑 可以aop
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorsList) {
                bean = beanPostProcessor.postProcessAfterInitialization(bean,beanName);
            }
            return bean;
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return null;
    }


    public Object getBean(String beanName){
        // 原型的话 判断是不是原型
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if (beanDefinition.getScope().equals("prototype")){
            return createBean(beanName,beanDefinition);
        }else {
            // 单例池中去拿
            Object bean = singletonObjects.get(beanName);
            if (bean == null){
                Object o = createBean(beanName,beanDefinition);
                singletonObjects.put(beanName,o);

                return o;
            }
            return bean;
        }
    }

    private List<Class> scan(Class configClass) {
        List<Class> classList = new ArrayList<>();
        ComponmentScan componmentScan = (ComponmentScan) configClass.getAnnotation(ComponmentScan.class);
        String scanPath = componmentScan.value();  // com.hong.service  ----> com/hong/service
        // 非懒加载的单例 @Lazy @Scope
        // 生成单例bean---->单例池

        scanPath = scanPath.replace(".","/");

        // 如何扫描类
        ClassLoader classLoader = HongApplicationContext.class.getClassLoader();
        URL resource = classLoader.getResource(scanPath);

        String s = null;
        try {
            s = URLDecoder.decode(resource.getFile(), "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        File file = new File(s);  // 目录

        // 指定的目录下的文件列表,可能是class,可能是txt
        File[] files = file.listFiles();

        for (File f : files) {
            String absolutePath = f.getAbsolutePath();
            absolutePath = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"))
                    .replace("\", ".");
            System.out.println("absolutePath="+absolutePath);
            // class文件加载进来
            try {
                Class<?> clazz = classLoader.loadClass(absolutePath);

                classList.add(clazz);

            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        return classList;
    }

}

结果如下

iii.png