不使用代理
现在有四个类Aservice,Bservice,Cservice,Dservice
1.使用spring.properties文件配置四个类路径,Aservice,Bservice,Cservice,Dservice
其中Aservice依赖BService,Cservice依赖Dservice,Dservice依赖Cservice
2.oneMap存储最终初始化好的对象,同时也存实例化但未初始化的对象
3.四个类中除了所需的对象外没有其他属性。而判断其是否需要初始化属性就是判断其是否有属性存在
代码如下 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中 是通过无参构造创建的,如果依赖是存在构造函数中,就会发现循环依赖就解决不了了。上面代码还没有用到代理
下面使用代理的方式
项目结构如图所示
代码如下
/**
* 标记是否需要代理
* @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,可是给出的回答差强人意。