我还是有点不理解为什么使用三级缓存解决循环依赖

46 阅读6分钟

不使用代理

现在有四个类Aservice,Bservice,Cservice,Dservice
1.使用spring.properties文件配置四个类路径,Aservice,Bservice,Cservice,Dservice
其中Aservice依赖BService,Cservice依赖Dservice,Dservice依赖Cservice
2.oneMap存储最终初始化好的对象,同时也存实例化但未初始化的对象
3.四个类中除了所需的对象外没有其他属性。而判断其是否需要初始化属性就是判断其是否有属性存在
image.png

代码如下 noProxy.properties

Aservice=springload.noProxy.service.Aservice
Bservice=springload.noProxy.service.Bservice
Cservice=springload.noProxy.service.Cservice
Dservice=springload.noProxy.service.Dservice

四个类

public class Aservice {

    private Bservice bservice;
    @Override
    public String toString() {
        return "A创建成功,["+bservice.print()+"]";
    }

    public String print(){
        return "A创建成功---";
    }
}
------------------------------------------
public class Bservice {
    @Override
    public String toString() {
        return "B创建成功";
    }

    public String print(){
        return "B创建成功---";
    }
}
-------------------------------------------
public class Cservice {

    private Dservice dservice;

    @Override
    public String toString() {
        return "C创建成功,["+dservice.print() +"]";
    }

    public String print(){
        return "C创建成功---";
    }
}
----------------------------------------
public class Dservice {

    private Cservice cservice;

    @Override
    public String toString() {
        return "D创建成功,["+ cservice.print()+"]";
    }

    public String print(){
        return "D创建成功---";
    }
}

//工具类

package utils;

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

/**
 * Bean工具
 *
 * @author sk
 * @date 2024/4/9
 */
public class BeanUtils {

    /**
     * 反射创建对象
     * @param path
     * @param aClass
     * @return
     * @param <T>
     * @throws Exception
     */
    public static <T>T getBean(String path, Class<T>aClass) throws Exception {
        Class<?> class1 = Class.forName(path);
        Constructor<?> constructor = class1.getConstructor();
        Object o = constructor.newInstance();
        return (T) o;
    }

    /**
     * 判断class是否存在指定注解
     * @param tClass
     * @return
     */
    public static boolean verfity(Class<?>tClass,Class aClass) throws Exception {
        if(tClass == null || aClass == null){
            throw new Exception("class为空!");
        }
        return tClass.isAnnotationPresent(aClass);
    }

    /**
     * 判断是否是代理对象
     * @param object
     * @return
     */
    public static boolean isProxyBean(Object object) {
        return Proxy.isProxyClass(object.getClass());
    }
}
----------------------------------------------------
public class PropertiesUtils {
    /**
     * 获取Properties对象
     * @param path
     * @return
     * @throws Exception
     */
    public static Properties load(String path){
        File file = new File(path);
        try (InputStream input = new FileInputStream(file)) {
            Properties prop = new Properties();
            prop.load(input);
            return prop;
        } catch (Exception ex) {
            System.out.format("解析文件出错,%s",ex);
        }
        return  null;
    }
}

加载配置类

public class BeanConfig {

    private static final String PATH = "src/main/resources/springload/noProxy/noProxy.properties";
    /*容器*/
    private static Map<Class,Object>oneMap = new HashMap<>();

    private static Properties load ;

    static{
        load = PropertiesUtils.load(PATH);;
        load.forEach((k,v)->{
            try {
                Class<?> aClass = Class.forName((String) v);
                Object bean = getBean(aClass);
                if(bean == null){
                    load (aClass);
                }
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
        });
    }

    public static void load(Class<?> aClass){
        try {
            //先创建放入容器中
            Constructor<?> constructor = aClass.getConstructor();
            Object o = constructor.newInstance();
            oneMap.put(aClass,o);
            //查看aClass的属性
            Field[] fields = aClass.getDeclaredFields();
            if(fields.length > 0)
            {
                for(Field field:fields){
                    Class<?> declaringClass = field.getType();
                    Object bean = getBean(declaringClass);
                    if(bean == null){
                        load(declaringClass);
                    }
                    bean = getBean(declaringClass);
                    field.setAccessible(true);
                    field.set(o,bean);
                }
                oneMap.put(aClass,o);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取实例
     * @param aClass
     * @return
     * @param <T>
     */
    public static <T>T getBean(Class aClass){
        Object o = oneMap.get(aClass);
        if(o==null){
           return null;
        }
        return (T)o;
    }

    /**
     * 返回最终map
     * @return
     */
    public static Map<Class,Object> getMap(){
        return oneMap;
    }
}

测试

public class Test {
    public static void main(String[] args) {
        Map<Class, Object> map = BeanConfig.getMap();
        map.forEach((k,v)->{
            System.out.println(v.toString());
        });
    }
}

通过代码可以发现,目前只用了一个map容器就解决了循环依赖的问题。通过代码可以知道Cservice和Dservice都是提前创建的放入oneMap中 是通过无参构造创建的,如果依赖是存在构造函数中,就会发现循环依赖就解决不了了。上面代码还没有用到代理

下面使用代理的方式

项目结构如图所示

image.png

代码如下

/**
 * 标记是否需要代理
 * @author sk
 * @date 2024/4/10
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Proxy {
}
----------------------------------------------
package springload.proxy.config;

import springload.proxy.annotation.Proxy;
import springload.proxy.handle.BeanInvocationHandler;
import springload.proxy.prototype.BeanPrototype;
import utils.BeanUtils;
import utils.PropertiesUtils;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.*;

/**
 * @author sk
 * @date 2024/4/9
 */
public class BeanConfig {

    private static final String PATH = "src/main/resources/springload/proxy/proxy.properties";

    /*一级容器*/
    private static Map<Class,Object>oneMap = new HashMap<>();

    /*二级容器*/
    private static Map<Class,Object>twoMap = new HashMap<>();

    /*原型容器*/
    private static List<BeanPrototype>list = new ArrayList<>();

    private static Properties load ;

    static{
        load = PropertiesUtils.load(PATH);;
        load.forEach((k,v)->{
            try {
                Class<?> aClass = Class.forName((String) v);
                BeanPrototype beanPrototype = new BeanPrototype();
                beanPrototype.setaInterface(aClass.getInterfaces()[0]);
                beanPrototype.setaClass(aClass);
                beanPrototype.setFields(aClass.getDeclaredFields());
                beanPrototype.setProxy(BeanUtils.verfity(aClass, Proxy.class));
                list.add(beanPrototype);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });
        list.forEach(v->{
            try {
                Object o = getBean(v.getaInterface());
                if(null == o){
                    load (v);
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });
    }

    /**
     * 加载对象
     * @param prototype
     */
    public static void load(BeanPrototype prototype){
        try {
            //先创建放入容器中
            Class<?> aClass = prototype.getaClass();
            Class<?> aInterface = prototype.getaInterface();
            Constructor<?> constructor = aClass.getConstructor();
            Object o = constructor.newInstance();
            oneMap.put(aInterface,o);
            //查看aClass的属性
            Field[] fields = prototype.getFields();
            if(fields.length > 0)
            {
                Object bean;
                for(Field field:fields){
                    Class<?> declaringClass = field.getType();
                    BeanPrototype beanPrototype = getBeanPrototype(declaringClass);
                    bean = getBean(declaringClass);
                    if(bean == null){
                        load(beanPrototype);
                    }
                    bean = getBean(declaringClass);
                    field.setAccessible(true);
                    //判断是否需要代理
                    if(beanPrototype.isProxy()){
                        //判断其是否是代理,并返回代理对象
                        bean = BeanUtils.isProxyBean(bean)?bean:createProxy(bean);
                    }
                    field.set(o,bean);
                }
            }
            //判断自身是否需要代理,需要,判断twoMap是否存在对象
            if(prototype.isProxy()){
                //判断是否存在代理对象
                if(twoMap.get(aInterface) != null){
                    oneMap.put(aInterface,twoMap.get(aInterface));
                    twoMap.remove(aInterface);
                }else{
                    //创建代理
                    Object proxy = createProxy(o);
                    oneMap.put(aInterface,proxy);
                    twoMap.remove(aInterface);
                }
            }else{
                twoMap.remove(aInterface);
                oneMap.put(aInterface,o);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 判断是否存在需要加载的原型
     * @Param aClass 接口类型|类型
     * @return
     */
    public static BeanPrototype getBeanPrototype(Class<?>aClass){
        for(BeanPrototype beanPrototype: list){
            if(beanPrototype.getaClass().equals(aClass)){
                return beanPrototype;
            }
            if(beanPrototype.getaInterface().equals(aClass)){
                return beanPrototype;
            }
        }
        return null;
    }

    /**
     * 获取代理
     * @param t
     * @return
     * @param <T>
     */
    public static <T>T createProxy(T t){
        Object object = twoMap.get(t.getClass());
        if(object == null){
            BeanInvocationHandler handler = new BeanInvocationHandler(t);
            Class<?>[] interfaces = t.getClass().getInterfaces();
            Object o = java.lang.reflect.Proxy.newProxyInstance(BeanUtils.class.getClassLoader(), interfaces, handler);
            return (T)o;
        }
        return (T)object;
    }

    /**
     * 获取实例
     * @param aClass
     * @return
     * @param <T>
     */
    public static <T>T getBean(Class aClass){
        Object o = oneMap.get(aClass);
        if(o==null){
           return (T)twoMap.get(aClass);
        }
        return (T)o;
    }

    /**
     * 返回最终map
     * @return
     */
    public static Map<Class,Object> getMap(){
        return oneMap;
    }
}
----------------------------------------------------
/**
 * @author sk
 * @date 2024/4/10
 */
public class BeanInvocationHandler implements InvocationHandler, Serializable {
    private final Object target; // 代理的目标对象

    public BeanInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(target.toString()+"的代理方法执行了");
        Object result = method.invoke(target, args);
        return result;
    }
}
-------------------------------------------------------
/**
 * Bean原型
 * @author sk
 * @date 2024/4/10
 */
public class BeanPrototype {

    /**
     * 类型
     */
    private Class<?> aClass;

    /**
     * 接口
     */
    private Class<?> aInterface;

    //字段
    private Field[] fields;
    
    /**
     * 是否代理
     */
    private boolean isProxy;
    getter,setter方法
}
------------------------------------
//四个接口的方法一模一样
public interface IAservice {

    String print();
}
------------------------------------
//四个service
public class Aservice implements IAservice {

    private IBservice iBservice;

    @Override
    public String print(){
        return "A创建成功---";
    }
}
@Proxy
public class Bservice implements IBservice {
    @Override
    public String print(){
        return "B创建成功---";
    }
}
@Proxy
public class Cservice implements ICservice {

    private IDservice iDservice;
    @Override
    public String print(){
        return "C创建成功---";
    }
}
@Proxy
public class Dservice implements IDservice {

    private ICservice iCservice;
    @Override
    public String print(){
        return "D创建成功---";
    }
}
----------------------------------------------
//测试
public class Test {
    public static void main(String[] args) {
        Map<Class, Object> map = BeanConfig.getMap();
        map.forEach((k,v)->{
            Class<?> aClass = v.getClass();
            Method print;
            try {
                print = aClass.getDeclaredMethod("print");
                Object invoke = print.invoke(v);
                System.out.println(invoke);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });
    }
}

模块proxy,加入了代理 1.使用Aservice,Bservice,Cservice,Dservice这四个类 依赖关系Aservice依赖Bservice,Bservice不依赖任何对象。 Cservice依赖Dservice,Dservice依赖Cservice

2.对Bservice,Cservice,Dservice添加代理

3.预测注入的最终结果应该是下面这样 Aservice中注入的是Bservice的代理对象 Cservice中注入的是Dservice的代理对象 Dservice中注入的是Cservice的代理对象

4.上面依赖关系如果还是用一个容器容器的话,就会发现代理对象放哪?难道放oneMap吗? 肯定不行的,这样key用那个class呢,如果吧value改成list也不合适

5.引入twoMap容器

设计: A-B

-》A创建需要B,实例化A,将A放入oneMap

-》创建B,将B的原生对象放入oneMap,再创建代理对象Bproxy放twoMap,初始化B,发现B没有依赖其他对象。判断twoMap中是否存在B类型对象,存在就替换oneMap中的B,删除twoMap的B

-》再往A中注入B,先找oneMap,找到了Bproxy对象注入A中,判断twoMap中是否存在A类型对象,存在就替换oneMap中的A,删除twoMap的A

C-D

-》实例化C原生对象,放入oneMap,C依赖D,在查找D,依次oneMap,twoMap,没找到

-》实例化D原生对象放入oneMap,创建D的代理对象Dproxy放入twoMap,查找C,依次oneMap,twoMap,找到了C原生,判断C是否需要代理, 如果需要,当前对象是否是代理对象,是就直接注入,不是就创建C代理,将C代理放入twoMap,注入D原生中,判断twoMap中是否存在D类型对象,存在就替换oneMap中的D,删除twoMap的D

-》返回初始化C,查找D,依次oneMap,twoMap,找到D代理,注入C原生中。判断twoMap中是否存在C类型对象,存在就替换oneMap中的C,删除twoMap的C

可以发现最终的注入结果和预测的是一样的。

目前即便是存在代理,可以发现二级依赖就可以解决问题了。 但是为什么spring要三级缓存呢,还是不太懂,或者说我想要一个场景就是二级缓存解决不了,得三级缓存才能实现的场景,我问过ai,可是给出的回答差强人意。