1 Star 1 Fork 0

丶ajax / spring-m

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README

模拟SpringIoc初始化

Spring如何管理Bean

先看一下Spring是如何管理Bean

public class TestDemo {

    public static void main(String[] args) {
        ApplicationContext context=new AnnotationConfigApplicationContext("com.itmck.beans");
        UserServiceImpl bean = context.getBean("userServiceImpl",UserServiceImpl.class);
        bean.sayHi();

    }

}

通过AnnotationConfigApplicationContext 构造函数如下可知:

public class AnnotationConfigApplicationContext {

	public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
		this();
		register(componentClasses);
		refresh();
	}

	public AnnotationConfigApplicationContext(String... basePackages) {
		this();
		scan(basePackages);
		refresh();
	}
}

大致步骤:

  • 扫描配置生成BeanDefinitionMap
  • 遍历BeanDefinitionMap创建Bean实例
  • Bean属性赋值
  • 使用Bean

开始模拟

手写Spring中Bean的实例化过程

创建AnnotationConfigApplicationContext

我们创建了AnnotationConfigApplicationContext并且拥有一个扫描方法,一个刷新方法(创建Bean方法),还有getBean()方法.简单架子如下所示:

package com.itmck.spring.core;

/**
 * 太阳当空照,花儿对我笑
 * <p>
 * Create by M ChangKe 2021/11/25 10:17
 **/
public class AnnotationConfigApplicationContext {

    /**
     * 通过构造方法传入配置类
     *
     * @param myConfigClass 配置类
     */
    public AnnotationConfigApplicationContext(Class<?> myConfigClass) {

        scan(myConfigClass);
        refresh();
    }

    /**
     * 扫描配置类
     *
     * @param myConfigClass 配置类
     */
    private void scan(Class<?> myConfigClass) {
    }

    /**
     * 创建Bean
     */
    private void refresh() {

    }


    /**
     * 通过BeanName获取Bean对象
     *
     * @param beanName Bean别名
     * @return Bean对象
     */
    public Object getBean(String beanName) {
        return null;
    }


    /**
     * 通过通过BeanName一级Bean class获取Bean对象
     *
     * @param beanName Bean别名
     * @param tClass   bean class类型
     * @param <T>      实例泛型
     * @return Bean对象
     */
    public <T> T getBean(String beanName, Class<T> tClass) {
        return tClass.cast(getBean(beanName));
    }
}

模拟Spring的注解

  • @Component
package com.itmck.spring.annotation;

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 "";
}
  • @Autowired
package com.itmck.spring.annotation;

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)
public @interface Autowired {


}
  • @ComponentScan
package com.itmck.spring.annotation;

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

/**
 * 类扫描注解
 *
 * 太阳当空照,花儿对我笑
 * <p>
 * Create by M ChangKe 2021/9/11 16:44
 **/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponentScan {

    String value() default "";
}
  • @Scope
package com.itmck.spring.annotation;

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 Scope {

    String value() default "";
}

创建BeanDefinition

扫描的目的就是扫描出BeanDefinition集合.BeanDefinition中包含了Bean类型,是否单例,是否懒加载....等

package com.itmck.spring.core;

/**
 * 太阳当空照,花儿对我笑
 * <p>
 * Create by M ChangKe 2021/9/11 17:28
 **/
public class BeanDefinition {

    /**
     * bean类型
     */
    private Class<?> type;

    /**
     * 是否是单例
     */
    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;
    }
}

AnnotationConfigApplicationContext#scan()创建

scan()扫面得到Bean定义用于Bean的创建,详细代码参考下面完整代码

AnnotationConfigApplicationContext#refresh()方法创建

refresh(),主要是遍历beanDefinitionMap,创建出所有的Bean,详细代码参考下面完整代码

完整代码如下:

package com.itmck.spring.core;

import com.itmck.spring.annotation.Component;
import com.itmck.spring.annotation.ComponentScan;
import com.itmck.spring.annotation.Scope;

import java.beans.Introspector;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

/**
 * 太阳当空照,花儿对我笑
 * <p>
 * Create by M ChangKe 2021/11/25 10:17
 **/
public class AnnotationConfigApplicationContext {

    /**
     * beanDefinitionMap 存放多个Bean定义 其中key为BeanName,value为BeanDefinition
     */
    private final Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();

    /**
     * 单例池,如果创建的是单例对象则放入单例池中
     */
    private final Map<String, Object> singletonObjects = new HashMap<>(256);

    /**
     * 通过构造方法传入配置类
     *
     * @param myConfigClass 配置类
     */
    public AnnotationConfigApplicationContext(Class<?> myConfigClass) {

        scan(myConfigClass);
        refresh();
    }

    /**
     * 扫描配置类
     *
     * @param myConfigClass 配置类
     */
    private void scan(Class<?> myConfigClass) {
        if (myConfigClass.isAnnotationPresent(ComponentScan.class)) {
            //如果当前配置类上存在注解@ComponentScan,则代表当前类为配置类
            ComponentScan componentScan = myConfigClass.getAnnotation(ComponentScan.class);
            //获取value内容  com.itmck.mck
            String path = componentScan.value();
            path = path.replace(".", "/");//将com.itmck.mck-->com/itmck/mck
            //获取当前类加载器
            ClassLoader classLoader = this.getClass().getClassLoader();
            URL resource = classLoader.getResource(path);
            assert resource != null;
            File file = new File(resource.getFile());
            if (file.isDirectory()) {
                File[] files = file.listFiles();
                assert files != null;
                for (File f : files) {
                    String absolutePath = f.getAbsolutePath();
                    absolutePath = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));
                    absolutePath = absolutePath.replace("\\", ".");
                    Class<?> aClass = null;
                    try {
                        //通过类加载器,加载当前类信息
                        aClass = classLoader.loadClass(absolutePath);
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }
                    assert aClass != null;
                    if (aClass.isAnnotationPresent(Component.class)) {
                        //如果当前类上存在存在@Component注解
                        Component component = aClass.getAnnotation(Component.class);
                        String beanName = component.value();
                        if ("".equals(beanName)) {
                            //如果没有给默认值,则使用类的首字母小写
                            beanName = Introspector.decapitalize(aClass.getSimpleName());
                        }
                        //扫描的目的就是获取BeanDefinition
                        BeanDefinition beanDefinition = new BeanDefinition();
                        beanDefinition.setType(aClass);
                        //判断是否存在Scope注解标记
                        if (aClass.isAnnotationPresent(Scope.class)) {
                            Scope scope = aClass.getAnnotation(Scope.class);
                            String value = scope.value();
                            beanDefinition.setScope(value);
                        } else {
                            beanDefinition.setScope("singleton");
                        }
                        beanDefinitionMap.put(beanName, beanDefinition);
                    }
                }
            }
        }
    }

    /**
     * 创建Bean
     */
    private void refresh() {
        //在这里拿到beanDefinitionMap后即可对Bean进行创建
        beanDefinitionMap.forEach((beanName, beanDefinition) -> {
            if ("singleton".equals(beanDefinition.getScope())) {
                try {
                    Object bean = createBean(beanName, beanDefinition);
                    singletonObjects.put(beanName, bean);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    private Object createBean(String beanName, BeanDefinition beanDefinition) {
        Class<?> aClass = beanDefinition.getType();
        Object instance = null;
        if (aClass.isAnnotationPresent(Component.class)) {
            try {
                instance = aClass.getConstructor().newInstance();//无参构造创建Bean
                Field[] declaredFields = aClass.getDeclaredFields();
                for (Field field : declaredFields) {
                    String name = field.getName();
                    field.setAccessible(true);
                    field.set(instance, getBean(name));
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return instance;
    }


    /**
     * 通过BeanName获取Bean对象
     *
     * @param beanName Bean别名
     * @return Bean对象
     */
    public Object getBean(String beanName) {
        if (!beanDefinitionMap.containsKey(beanName)) {
            throw new NullPointerException();
        }
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        //如果是获取的Bean在单例池中存在则从单例池中取,否则新建
        if ("singleton".equals(beanDefinition.getScope())) {
            Object singletonBean = singletonObjects.get(beanName);
            if (singletonBean == null) {
                singletonBean = createBean(beanName, beanDefinition);
                singletonObjects.put(beanName, singletonBean);
            }
            return singletonBean;
        } else {
            // 原型Bean
            return createBean(beanName, beanDefinition);
        }
    }


    /**
     * 通过通过BeanName一级Bean class获取Bean对象
     *
     * @param beanName Bean别名
     * @param tClass   bean class类型
     * @param <T>      实例泛型
     * @return Bean对象
     */
    public <T> T getBean(String beanName, Class<T> tClass) {
        return tClass.cast(getBean(beanName));
    }
}

编写main方法

  • OneConfig.class
package com.itmck.one;

import com.itmck.spring.annotation.ComponentScan;
@ComponentScan("com.itmck.one")
public class OneConfig {

}
  • User
package com.itmck.one;

import com.itmck.spring.annotation.Autowired;
import com.itmck.spring.annotation.Component;

@Component
public class User {

    public void run() {
        System.out.println("User#run() is running...");
    }
}
  • MckSpringApplication#main()
package com.itmck.one;

import com.itmck.mck.MyConfig;
import com.itmck.mck.UserA;
import com.itmck.mck.UserB;
import com.itmck.spring.core.AnnotationConfigApplicationContext;
import com.itmck.spring.core.AnnotationConfigApplicationContext2;

/**
 * 太阳当空照,花儿对我笑
 * <p>
 * Create by M ChangKe 2021/11/24 9:36
 **/
public class TestDemo2 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
        User user = applicationContext.getBean("user", User.class);
        user.run();
    }
}

运行结果 User#run() is running...

注:上述代码是针对单个Bean进行扫描以及创建的简单流程梳理,但spring中远不止这些.

循环依赖

什么是循环依赖?

循环依赖就是A依赖B,B依赖A,互相依赖.主要分为一个类之间,两个类,多个类之间的依赖

Spring在创建Bean的时候是如何解决循环依赖问题?

spring中使用三级缓存解决循环依赖

手写循环依赖实现

  • UserA
package com.itmck.mck;

import com.itmck.spring.annotation.Autowired;
import com.itmck.spring.annotation.Component;

/**
 * 太阳当空照,花儿对我笑
 * <p>
 * Create by M ChangKe 2021/9/11 18:08
 **/
@Component
public class UserA {

    @Autowired
    private UserB userB;

    public void run() {
        System.out.println("UserA");
    }
    //省略get/set
}
  • UserB
package com.itmck.mck;

import com.itmck.spring.annotation.Autowired;
import com.itmck.spring.annotation.Component;

/**
 * 太阳当空照,花儿对我笑
 * <p>
 * Create by M ChangKe 2021/9/11 18:08
 **/
@Component
public class UserB {

    @Autowired
    private UserA userA;

    public void run(){
        System.out.println("UserB");
    }
    //略get/set

}

修改上述代码

修改createBean()方法是关键.因为A依赖B,在创建A的时候给A属性赋值,这时需要创建B.然后创建B又依赖到A....循环往复.怎么办????

  • 调用createBean()进行递归创建
  • 防止递归循环需要添加一个出口函数
private Object createBean(String beanName, BeanDefinition beanDefinition) {
    //使用一级缓存解决循环依赖
    //**在这里先判断一级缓存中是否存在,这里是解决循环依赖的关键,添加一个递归出口,防止无限递归**
    Object singleton = getSingleton(beanName);
    if (singleton != null) {
        return singleton;
    }
    Class<?> aClass = beanDefinition.getType();
    Object instance = null;
    if (aClass.isAnnotationPresent(Component.class)) {
        try {
            instance = aClass.getConstructor().newInstance();//无参构造创建Bean
            singletonObjects.put(beanName,instance);//将instance放入一级缓存
            Field[] declaredFields = aClass.getDeclaredFields();
            for (Field field : declaredFields) {
                field.setAccessible(true);
                //**在这里调用自身方法进行递归操作获取bean**
                field.set(instance,createBean(field.getName(), beanDefinitionMap.get(field.getName())));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    return instance;
}

public Object getSingleton(String beanName) {
    if (singletonObjects.containsKey(beanName)) {
        return singletonObjects.get(beanName);
    }
    return null;

}

运行MckSpringApplication

package com.itmck;

import com.itmck.mck.MyConfig;
import com.itmck.mck.UserA;
import com.itmck.mck.UserB;
import com.itmck.one.OneConfig;
import com.itmck.one.User;
import com.itmck.spring.core.AnnotationConfigApplicationContext;
import com.itmck.spring.core.AnnotationConfigApplicationContext2;

/**
 * 太阳当空照,花儿对我笑
 * <p>
 * Create by M ChangKe 2021/11/24 9:36
 **/
public class MckSpringApplication {

    public static void main(String[] args) throws Exception {
        AnnotationConfigApplicationContext2 applicationContext = new AnnotationConfigApplicationContext2(MyConfig.class);
        UserA userA = applicationContext.getBean("userA", UserA.class);
        UserB userB1 = userA.getUserB();
        System.out.println("UserA#userB.run()");
        userB1.run();
        UserB userB = applicationContext.getBean("userB", UserB.class);
        UserA userA1 = userB.getUserA();
        System.out.println("UserB#userA.run()");
        userA1.run();
    }
}

结果如下,表示循环依赖已经解决

UserA#userB.run()
UserB
UserB#userA.run()
UserA

现在看上去一级缓存已经能够解决循环依赖问题,如果是多线程环境下:假如现有2个线程,第一个线程在创建beanA的时候,属性赋值后加入一级缓存,第二个线程去getBeanA,拿到的是不完整的beanA。所以需要二级缓存

  • 修改代码如下,新增二级缓存earlySingletonObjects用于存放纯净Bean

private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

  • 改造scan()与getSingleton()方法

注意:earlySingletonObjects.put(beanName, instance)与singletonObjects.put(beanName, instance)位置

private Object createBean(String beanName, BeanDefinition beanDefinition) {
    //使用一级缓存解决循环依赖
    //在这里先判断一级缓存中是否存在,这里是解决循环依赖的关键,添加一个递归出口,防止无限递归
    Object singleton = getSingleton(beanName);
    if (singleton != null) {
        return singleton;
    }
    Class<?> aClass = beanDefinition.getType();
    Object instance = null;
    if (aClass.isAnnotationPresent(Component.class)) {
        try {
            instance = aClass.getConstructor().newInstance();//无参构造创建Bean
            earlySingletonObjects.put(beanName, instance);//这里新增二级缓存存放新鲜反射出来的纯净Bean
            Field[] declaredFields = aClass.getDeclaredFields();
            for (Field field : declaredFields) {
                field.setAccessible(true);
                field.set(instance, createBean(field.getName(), beanDefinitionMap.get(field.getName())));//在这里调用自身方法进行递归操作获取bean
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //初始化在这里
    //init------
    singletonObjects.put(beanName, instance);//将instance放入一级缓存,这里的Bean是完成了属性赋值,初始化等完整的单例Bean
    return instance;
}


/**
 * 通过判断
 *
 * @param beanName Bean别名
 * @return Bean对象
 */
public Object getSingleton(String beanName) {
    if (singletonObjects.containsKey(beanName)) {
        return singletonObjects.get(beanName);
    }else if (earlySingletonObjects.containsKey(beanName)){
        //新增二级缓存后,一级缓存没有从二级缓存中取
        return earlySingletonObjects.get(beanName);
    }
    return null;

}

最后运行结果与上述一致.

一级缓存和二级缓存的作用

  • 一级缓存: 解决循环依赖的问题,但是不能完全解决,因为存在多线程问题
  • 二级缓存: 在创建实例bean和放入到一级缓存之间还有一段间隙. 如果在这之间从一级缓存拿实例, 肯定是返回null的. 为了避免这个问题, 增加了二级缓存.(多线程问题)

aop创建时机

我们在创建bean 的时候, 会有很多Bean的后置处理器BeanPostProcessor. 如果有AOP, 会在什么时候创建呢? 在初始化以后, 调用BeanPostProcessor创建动态代理.

结合上面的代码, 我们想一想, 其实在初始化以后创建动态代理就晚了. 为什么呢? 因为, 如果有循环依赖, 在初始化之后才调用, 那就不是动态代理. 其实我们这时候应该在实例化之后, 放入到二级缓存之前调用. 如果判断有循环依赖此时进行AOP,那么最佳位置应该是在判断二级缓存存在说明是循环依赖,此时进行aop然后将新的实例放入二级缓存

修改后代码如下:

public Object getSingleton(String beanName) {
    if (singletonObjects.containsKey(beanName)) {
        return singletonObjects.get(beanName);
    }else if (earlySingletonObjects.containsKey(beanName)){
        //新增二级缓存后,一级缓存没有从二级缓存中取

        /**
         * 第一次创建bean是正常的instanceBean. 他并不是循环依赖. 第二次进来判断, 这个bean已经存在了, 就说明是循环依赖了
         * 这时候通过动态代理创建bean. 然后将这个bean在放入到二级缓存中覆盖原来的instanceBean.
         * 这样我们在循环依赖的时候就完成了AOP的创建. 这是在二级缓存里创建的AOP
         */
        Object instance = new CglibProxyBeanPostProcessor().getEarlyBeanReference(earlySingletonObjects.get(beanName), beanName);
        earlySingletonObjects.put(beanName, instance);
        return earlySingletonObjects.get(beanName);
    }
    return null;
}

创建CglibProxyBeanPostProcessor

package com.itmck.mck;

import com.itmck.spring.annotation.Component;
import com.itmck.spring.core.SmartInstantiationAwareBeanPostProcessor;
import com.itmck.spring.proxy.MyEnhancer;
import com.itmck.spring.proxy.MyProxy;
import net.sf.cglib.proxy.Enhancer;

/**
 * 太阳当空照,花儿对我笑
 * <p>
 * Create by M ChangKe 2021/9/11 18:08
 **/
@Component
public class CglibProxyBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {

    @Override
    public Object getEarlyBeanReference(Object bean, String beanName) {
        // 假设A被切点命中 需要创建代理  @PointCut("execution(* *..InstanceA.*(..))")
        /**
         * 这里, 我们简单直接判断bean是不是InstanceA实例, 如果是, 就创建动态代理.
         * 这里没有去解析切点, 解析切点是AspectJ做的事.
         */
        if (bean instanceof UserA) {
            MyEnhancer myEnhancer = new MyEnhancer(new MyProxy(),bean);
            Enhancer enhancer = myEnhancer.getEnhancer();
            bean = enhancer.create();
        }
        return bean;
    }
}

MyEnhancer

使用cglib代理需要引入pom

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>
package com.itmck.spring.proxy;

import net.sf.cglib.proxy.Enhancer;

/**
 * 太阳当空照,花儿对我笑
 * <p>
 * Create by M ChangKe 2021/11/25 15:11
 **/
public class MyEnhancer {

    private final MyProxy myProxy;
    private final Object object;

    public MyEnhancer(MyProxy myProxy, Object object) {
        this.myProxy = myProxy;
        this.object = object;
    }

    public Enhancer getEnhancer(){
        Enhancer enhancer = new Enhancer();  // 通过CGLIB动态代理获取代理对象的过程
        enhancer.setSuperclass(object.getClass());     // 设置enhancer对象的父类
        enhancer.setCallback(myProxy);    // 设置enhancer的回调对象
        return enhancer;
    }
}

MyProxy implements MethodInterceptor

package com.itmck.spring.proxy;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class MyProxy implements MethodInterceptor {
    /**
     *
     * @param o cglib生成的代理对象
     * @param method 被代理对象的方法
     * @param objects     传入方法的参数
     * @param methodProxy 代理的方法
     * @return
     * @throws Throwable
     */
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("这里可以插入执行关键代码之前的逻辑");
        Object o1 = methodProxy.invokeSuper(o, objects);//关键代码:
        System.out.println("这里可以插入执行关键代码之后的逻辑");
        return o1;
    }
}

此时运行代码结果

UserA#userB.run()
UserB
UserB#userA.run()
这里可以插入执行关键代码之前的逻辑
UserA
这里可以插入执行关键代码之后的逻辑

到这里可以发现使用二级缓存就可以解决循环依赖中Aop的问题.那么为什Spring使用了三级缓存?

三级缓存是为了单一职责 如果在getBean的时候写,不符合标准。后置处理器是在bean的创建过程中去给它增强的

引入三级缓存

在createBean中实例化之后进行保存ObjectFactory 到三级缓存singletonFactories

private Object createBean(String beanName, BeanDefinition beanDefinition) {
    //使用一级缓存解决循环依赖
    //在这里先判断一级缓存中是否存在,这里是解决循环依赖的关键,添加一个递归出口,防止无限递归
    Object singleton = getSingleton(beanName);
    if (singleton != null) {
        return singleton;
    }
    // 正在创建
    singletonsCurrentlyInCreation.add(beanName);

    Class<?> aClass = beanDefinition.getType();
    Object instance = null;
    if (aClass.isAnnotationPresent(Component.class)) {
        try {
            instance = aClass.getConstructor().newInstance();//无参构造创建Bean
            //在这里直接进行aop不合理,因为没有进行判断,所以要先判断是否需要进行代理,如果需要才进行aop,在哪里判断?
            //当有循环依赖的时候,二级缓存不为null,所以在getSingleton()中判断
            //instance = new JdkProxyBeanPostProcessor().getEarlyBeanReference(instance, beanName);

            //实例化之后保 级缓存就是存函数接口的
            singletonFactories.put(beanName,() -> new CglibProxyBeanPostProcessor().getEarlyBeanReference(earlySingletonObjects.get(beanName), beanName));

            earlySingletonObjects.put(beanName, instance);//这里新增二级缓存存放新鲜反射出来的纯净Bean
            Field[] declaredFields = aClass.getDeclaredFields();
            for (Field field : declaredFields) {
                field.setAccessible(true);
                field.set(instance, createBean(field.getName(), beanDefinitionMap.get(field.getName())));//在这里调用自身方法进行递归操作获取bean
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 第四步: 初始化
     * 初始化就是设置类的init-method.这个可以设置也可以不设置. 我们这里就不设置了
     */

    //正常的代理实在初始化之后,就是这里进行,但是如果存在循环依赖必须在实例化之后进行
    //instance = new JdkProxyBeanPostProcessor().getEarlyBeanReference(instance, beanName);


    // 由于递归完后A 还是原实例,, 所以要从二级缓存中拿到proxy 。
    if (earlySingletonObjects.containsKey(beanName)) {
        instance = earlySingletonObjects.get(beanName);
    }

    //将instance放入一级缓存,这里的Bean是完成了属性赋值,初始化等完整的单例Bean
    singletonObjects.put(beanName, instance);
    return instance;
}

getSingleton()修改如下

public Object getSingleton(String beanName) {
    // 先从一级缓存中拿
    Object bean = singletonObjects.get(beanName);
    // 说明是循环依赖
    if (bean == null && singletonsCurrentlyInCreation.contains(beanName)) {
        bean = earlySingletonObjects.get(beanName);
        // 如果二级缓存没有就从三级缓存中拿
        if (bean == null) {
            // 从三级缓存中拿
            ObjectFactory<?> factory = singletonFactories.get(beanName);
            if (factory != null) {
                try {
                    bean = factory.getObject(); // 拿到动态代理
                    earlySingletonObjects.put(beanName, bean);
                    //然后从二级缓存移除singletonFactory
                    this.singletonFactories.remove(beanName);
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        }
    }
    return bean;
}

完整代码

package com.itmck.spring.core;

import com.itmck.mck.CglibProxyBeanPostProcessor;
import com.itmck.spring.annotation.Component;
import com.itmck.spring.annotation.ComponentScan;
import com.itmck.spring.annotation.Scope;

import java.beans.Introspector;
import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 太阳当空照,花儿对我笑
 * <p>
 * Create by M ChangKe 2021/11/25 10:17
 *
 * 模拟spring读取配置文件以及创建Bean,引入三级缓存目的,存放ObjectFactory,单一自责
 *
 **/
public class AnnotationConfigApplicationContext3 {

    /**
     * beanDefinitionMap 存放多个Bean定义 其中key为BeanName,value为BeanDefinition
     */
    private final Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();

    /**
     * 单例池,如果创建的是单例对象则放入单例池中
     */
    private final Map<String, Object> singletonObjects = new HashMap<>(256);

    //早期Bean,还未被初始化以及属性赋值
    private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

    // 三级缓存
    public final Map<String, ObjectFactory<?>> singletonFactories = new ConcurrentHashMap<>();

    //循环依赖标识
    public final Set<String> singletonsCurrentlyInCreation = new HashSet<>();

    /**
     * 通过构造方法传入配置类
     *
     * @param myConfigClass 配置类
     */
    public AnnotationConfigApplicationContext3(Class<?> myConfigClass) {

        scan(myConfigClass);
        refresh();
    }

    /**
     * 扫描配置类
     *
     * @param myConfigClass 配置类
     */
    private void scan(Class<?> myConfigClass) {
        if (myConfigClass.isAnnotationPresent(ComponentScan.class)) {
            //如果当前配置类上存在注解@ComponentScan,则代表当前类为配置类
            ComponentScan componentScan = myConfigClass.getAnnotation(ComponentScan.class);
            //获取value内容  com.itmck.mck
            String path = componentScan.value();
            path = path.replace(".", "/");//将com.itmck.mck-->com/itmck/mck
            //获取当前类加载器
            ClassLoader classLoader = this.getClass().getClassLoader();
            URL resource = classLoader.getResource(path);
            assert resource != null;
            File file = new File(resource.getFile());
            if (file.isDirectory()) {
                File[] files = file.listFiles();
                assert files != null;
                for (File f : files) {
                    String absolutePath = f.getAbsolutePath();
                    absolutePath = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));
                    absolutePath = absolutePath.replace("\\", ".");
                    Class<?> aClass = null;
                    try {
                        //通过类加载器,加载当前类信息
                        aClass = classLoader.loadClass(absolutePath);
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }
                    assert aClass != null;
                    if (aClass.isAnnotationPresent(Component.class)) {
                        //如果当前类上存在存在@Component注解
                        Component component = aClass.getAnnotation(Component.class);
                        String beanName = component.value();
                        if ("".equals(beanName)) {
                            //如果没有给默认值,则使用类的首字母小写
                            beanName = Introspector.decapitalize(aClass.getSimpleName());
                        }
                        //扫描的目的就是获取BeanDefinition
                        BeanDefinition beanDefinition = new BeanDefinition();
                        beanDefinition.setType(aClass);
                        //判断是否存在Scope注解标记
                        if (aClass.isAnnotationPresent(Scope.class)) {
                            Scope scope = aClass.getAnnotation(Scope.class);
                            String value = scope.value();
                            beanDefinition.setScope(value);
                        } else {
                            beanDefinition.setScope("singleton");
                        }
                        beanDefinitionMap.put(beanName, beanDefinition);
                    }
                }
            }
        }
    }

    /**
     * 创建Bean
     */
    private void refresh() {
        //在这里拿到beanDefinitionMap后即可对Bean进行创建
        beanDefinitionMap.forEach((beanName, beanDefinition) -> {
            if ("singleton".equals(beanDefinition.getScope())) {
                try {
                    createBean(beanName, beanDefinition);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    private Object createBean(String beanName, BeanDefinition beanDefinition) {
        //使用一级缓存解决循环依赖
        //在这里先判断一级缓存中是否存在,这里是解决循环依赖的关键,添加一个递归出口,防止无限递归
        Object singleton = getSingleton(beanName);
        if (singleton != null) {
            return singleton;
        }
        // 正在创建
        singletonsCurrentlyInCreation.add(beanName);

        Class<?> aClass = beanDefinition.getType();
        Object instance = null;
        if (aClass.isAnnotationPresent(Component.class)) {
            try {
                instance = aClass.getConstructor().newInstance();//无参构造创建Bean
                Object finalInstance = instance;
                singletonFactories.put(beanName, (ObjectFactory<?>)()-> new CglibProxyBeanPostProcessor().getEarlyBeanReference(finalInstance, beanName));
                earlySingletonObjects.put(beanName, instance);//这里新增二级缓存存放新鲜反射出来的纯净Bean
                Field[] declaredFields = aClass.getDeclaredFields();
                for (Field field : declaredFields) {
                    field.setAccessible(true);
                    field.set(instance, createBean(field.getName(), beanDefinitionMap.get(field.getName())));//在这里调用自身方法进行递归操作获取bean
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        /**
         * 第四步: 初始化
         * 初始化就是设置类的init-method.这个可以设置也可以不设置. 我们这里就不设置了
         */
        // 由于递归完后A 还是原实例,, 所以要从二级缓存中拿到proxy 。
        if (earlySingletonObjects.containsKey(beanName)) {
            instance = earlySingletonObjects.get(beanName);
        }

        //将instance放入一级缓存,这里的Bean是完成了属性赋值,初始化等完整的单例Bean
        singletonObjects.put(beanName, instance);
        return instance;
    }

    public Object getSingleton(String beanName) {
        // 先从一级缓存中拿
        Object bean = singletonObjects.get(beanName);
        // 说明是循环依赖
        if (bean == null && singletonsCurrentlyInCreation.contains(beanName)) {
            bean = earlySingletonObjects.get(beanName);
            // 如果二级缓存没有就从三级缓存中拿
            if (bean == null) {
                // 从三级缓存中拿
                ObjectFactory<?> factory = singletonFactories.get(beanName);
                if (factory != null) {
                    try {
                        bean = factory.getObject(); // 拿到动态代理
                        earlySingletonObjects.put(beanName, bean);
                        //然后从二级缓存移除singletonFactory
                        this.singletonFactories.remove(beanName);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                }
            }
        }
        return bean;
    }

    public Object getBean(String beanName) {
        if (!beanDefinitionMap.containsKey(beanName)) {
            throw new NullPointerException();
        }
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        //如果是获取的Bean在单例池中存在则从单例池中取,否则新建
        if ("singleton".equals(beanDefinition.getScope())) {
            Object singletonBean = singletonObjects.get(beanName);
            if (singletonBean == null) {
                singletonBean = createBean(beanName, beanDefinition);
            }
            return singletonBean;
        } else {
            // 原型Bean
            return createBean(beanName, beanDefinition);
        }
    }


    /**
     * 通过通过BeanName一级Bean class获取Bean对象
     *
     * @param beanName Bean别名
     * @param tClass   bean class类型
     * @param <T>      实例泛型
     * @return Bean对象
     */
    public <T> T getBean(String beanName, Class<T> tClass) {
        return tClass.cast(getBean(beanName));
    }
}

运行结果与上述一致

总结

spring使用三级缓存解决循环依赖

  • 一级缓存能解决循环依赖,但是不能解决多线程环境下循环依赖
  • 二级缓存用于存放纯净Bean(实例化之后还未赋值以及初始化的Bean),并且能解决多线程下循环依赖.其次二级缓存也能解决aop
  • 三级缓存则是存放ObjectFactory用于创建aop之久的代理Bean.spring也是考虑职责单一

这样以来.职责明确.一级缓存单例池,二级缓存纯净Bean,三级缓存存放用于创建代理Bean的ObjectFactory.

在创建bean的时候, 在哪里创建的动态代理, 这个应该怎么回答呢?

面试题: 在创建bean的时候, 在哪里创建的动态代理, 这个应该怎么回答呢?
很多人会说在初始化之后, 或者在实例化之后.
其实更严谨的说, 有两种情况: 第一种是在初始化之后调用 . 第二种是出现了循环依赖, 会在实例化之后调用

空文件

简介

手写spring 创建Bean的过程,包括如何解决循环依赖 展开 收起
Java
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
1
https://gitee.com/itmc/spring-m.git
git@gitee.com:itmc/spring-m.git
itmc
spring-m
spring-m
master

搜索帮助