From 21500f40ad4e9b04c13aaf4e1b15293605c02a9e Mon Sep 17 00:00:00 2001 From: Vincent Date: Wed, 4 Mar 2026 11:02:08 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B9=B6=E8=A1=8C=E5=90=AF=E5=8A=A8=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E5=AF=B9Collect=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../factory/ModuleBeanFactory.java | 108 +++++++++++++----- .../factory/PlatformBeanFactory.java | 58 ++-------- 2 files changed, 91 insertions(+), 75 deletions(-) diff --git a/caf-multicontext/src/main/java/io/iec/edp/caf/multicontext/factory/ModuleBeanFactory.java b/caf-multicontext/src/main/java/io/iec/edp/caf/multicontext/factory/ModuleBeanFactory.java index c8f9b6298..cec4a5b21 100644 --- a/caf-multicontext/src/main/java/io/iec/edp/caf/multicontext/factory/ModuleBeanFactory.java +++ b/caf-multicontext/src/main/java/io/iec/edp/caf/multicontext/factory/ModuleBeanFactory.java @@ -18,12 +18,12 @@ package io.iec.edp.caf.multicontext.factory; import io.iec.edp.caf.multicontext.config.ParallelConfigReader; import io.iec.edp.caf.multicontext.config.ParallelSetting; -import io.iec.edp.caf.multicontext.context.PlatformApplicationContext; import lombok.extern.slf4j.Slf4j; import lombok.var; import org.springframework.beans.BeanWrapper; import org.springframework.beans.BeansException; import org.springframework.beans.factory.*; +import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory; import org.springframework.beans.factory.support.AbstractBeanDefinition; @@ -38,7 +38,6 @@ import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.List; import java.util.concurrent.ConcurrentMap; /** @@ -86,50 +85,26 @@ public class ModuleBeanFactory extends DefaultListableBeanFactory { return super.containsBeanDefinition(beanName); } - //加锁 防止死锁 - //todo 后期实现模块间完全隔离后 可将相关逻辑全部去掉 性能可以得到大幅度提升 @Override public Object getSingleton(String beanName, ObjectFactory singletonFactory) { -// synchronized (this.getParentBeanFactory()) { return super.getSingleton(beanName, singletonFactory); -// } } -// //集中包扫描路径配置 -// @Override -// public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException { -// if (ENTITY_SCAN_PACKAGES.equals(beanName)) { -// return ((DefaultListableBeanFactory) this.getParentBeanFactory()).getBeanDefinition(beanName); -// } -// -// return super.getBeanDefinition(beanName); -// } - - @Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { var specialBeans = new ArrayList(){{ add("wfTaskServerEndpointExporter");//WF注册了一个ServletContainer 必须在WebApplication中才能用 因此要注册到底座里去 add("serverEndpointExporter");//消息注册了一个ServletContainer 必须在WebApplication中才能用 因此要注册到底座里去 - //add("getWebSocket"); }}; -// specialBeans.addAll(settting.getSpecilBeans()); - - if(beanDefinition.getSource()!=null && beanDefinition.getSource() instanceof MethodMetadata){ String returnTypeName = ((MethodMetadata)beanDefinition.getSource()).getReturnTypeName(); - if(((MethodMetadata)beanDefinition.getSource()).getReturnTypeName().equalsIgnoreCase("org.springframework.web.socket.server.standard.ServerEndpointExporter")){ + if(returnTypeName.equalsIgnoreCase("org.springframework.web.socket.server.standard.ServerEndpointExporter")){ specialBeans.add(beanName); - } else if(((MethodMetadata)beanDefinition.getSource()).getReturnTypeName().equalsIgnoreCase("io.iec.edp.caf.core.context.BizContextBuilder")) { + } else if(returnTypeName.equalsIgnoreCase("io.iec.edp.caf.core.context.BizContextBuilder")) { specialBeans.add(beanName); } -// else if(((MethodMetadata)beanDefinition.getSource()).getReturnTypeName().equalsIgnoreCase("io.iec.edp.caf.rest.RESTEndpoint")){ -// StartupAnalysisLog.countRestBean(moduleName); -// }else if((MethodMetadata)((MethodMetadata) beanDefinition.getSource()).getAnnotationAttributes("RpcService")!=null){ -// StartupAnalysisLog.countRpcBean(moduleName); -// } } //这些特殊的bean需要注册到底座里,当面主要的是基于原生java的websocket类型的, @@ -406,4 +381,81 @@ public class ModuleBeanFactory extends DefaultListableBeanFactory { return null; } + + /** + * 单例Bean创建前方法, 用于判断Bean是否存在循环依赖 + */ + public void beforeSingletonCreation(String beanName) { + super.beforeSingletonCreation(beanName); + + /* + 如果Bean的声明类型标记了@Collect注解, 则额外执行PlatformBeanFactory的该方法, 将beanName也注册到底座容器的[singletonsCurrentlyInCreation]中. + + spring机制: 允许当 BeanFactory 正在创建某个类型A Bean时, 内部通过 getBeansOfType(A.class) 获取该类型的其他Bean。如: + spring: + @Bean + public A 01() { ... } + + @Bean + public A 02() { + // others包含 02 之外的其他A类型Bean, 即只包含 01 + // BeanFactory.getBeansOfType方法内部逻辑会通过类型A寻找所有Bean名称, 会同时找到 01、02, 在尝试创建 02 时发生循环依赖报错 + // 但该方法内部会根据[singletonsCurrentlyInCreation]识别到当前正在创建02, 会吞掉循环依赖报错, 继续执行 + Map others = BeanFactory.getBeansOfType(A.class); + ... + } + + 在并行启动模式下, 由于IoC容器分为Platform和Module两层, 在使用@Collect搜集Module中的Bean时, beanName只会注册到Module的IoC容器中 + 但由于@Collect的特殊机制, 当Platform容器触发BeanFactory.getBeansOfType(A.class)时, 它会通过类型A寻找所有Bean名称, 这包含Platform的, 也包含Module的 + 当它创建Module的Bean时, 依然会出现循环依赖报错 + 当出现报错时, 由于beanName只在Module的[singletonsCurrentlyInCreation]中; 但当前是由Platform容器处理这个异常, Platform的[singletonsCurrentlyInCreation]并不包含该beanName, 异常抛出, 启动中断 + parallel: + 底座: + @Bean + public A 01() { ... } + + 业务: + @Bean + public A 02() { + Map others = SpringBeanUtils.getApplicationContext().getBeansOfType(A.class); + ... + } + */ + BeanDefinition beanDefinition = getBeanDefinition(beanName); + if (beanDefinition instanceof AnnotatedBeanDefinition) { + AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) beanDefinition; + MethodMetadata factoryMethodMetadata = annotatedBeanDefinition.getFactoryMethodMetadata(); + if (factoryMethodMetadata != null) { + String returnTypeName = factoryMethodMetadata.getReturnTypeName(); + + try { + Class type = Class.forName(returnTypeName); + PlatformBeanFactory platformBeanFactory = (PlatformBeanFactory) getParentBeanFactory(); + if (platformBeanFactory.isTypeCollected(type)) platformBeanFactory.beforeSingletonCreation(beanName); + } catch (Exception ignored) { + } + } + } + } + + public void afterSingletonCreation(String beanName) { + super.afterSingletonCreation(beanName); + + BeanDefinition beanDefinition = getBeanDefinition(beanName); + if (beanDefinition instanceof AnnotatedBeanDefinition) { + AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) beanDefinition; + MethodMetadata factoryMethodMetadata = annotatedBeanDefinition.getFactoryMethodMetadata(); + if (factoryMethodMetadata != null) { + String returnTypeName = factoryMethodMetadata.getReturnTypeName(); + + try { + Class type = Class.forName(returnTypeName); + PlatformBeanFactory platformBeanFactory = (PlatformBeanFactory) getParentBeanFactory(); + if (platformBeanFactory.isTypeCollected(type)) platformBeanFactory.afterSingletonCreation(beanName); + } catch (Exception ignored) { + } + } + } + } + } diff --git a/caf-multicontext/src/main/java/io/iec/edp/caf/multicontext/factory/PlatformBeanFactory.java b/caf-multicontext/src/main/java/io/iec/edp/caf/multicontext/factory/PlatformBeanFactory.java index c8a6bd23b..448c03a77 100644 --- a/caf-multicontext/src/main/java/io/iec/edp/caf/multicontext/factory/PlatformBeanFactory.java +++ b/caf-multicontext/src/main/java/io/iec/edp/caf/multicontext/factory/PlatformBeanFactory.java @@ -49,7 +49,6 @@ import java.util.*; @Slf4j public class PlatformBeanFactory extends DefaultListableBeanFactory { -// private final String ENTITY_SCAN_PACKAGES = EntityScanPackages.class.getName(); private final ModuleManager moduleManager; @@ -63,24 +62,6 @@ public class PlatformBeanFactory extends DefaultListableBeanFactory { return this.moduleManager; } -// //--------------------------------------------------------------------- -// // Implementation of BeanFactory interface -// //--------------------------------------------------------------------- -// @Override -// public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition){ -// super.registerBeanDefinition(beanName,beanDefinition); -// -// if(beanDefinition.getSource()!=null && beanDefinition.getSource() instanceof MethodMetadata){ -// var moduleName="platform"; -// if(((MethodMetadata)beanDefinition.getSource()).getReturnTypeName().equalsIgnoreCase("io.iec.edp.caf.rest.RESTEndpoint")){ -// StartupAnalysisLog.countRestBean(moduleName); -// }else if((MethodMetadata)((MethodMetadata) beanDefinition.getSource()).getAnnotationAttributes("RpcService")!=null){ -// StartupAnalysisLog.countRpcBean(moduleName); -// } -// } -// } - - @Override public Object getBean(String name) throws BeansException { return doGetBeanByName(name, null, null); @@ -262,33 +243,6 @@ public class PlatformBeanFactory extends DefaultListableBeanFactory { return resultMap; } -// @Override -// public String[] getBeanNamesForAnnotation(Class annotationType) { -// Set resultList = new HashSet<>(); -// -// for (Module module : moduleManager) { -// ListableBeanFactory beanFactory = module.getBeanFactory(); -// resultList.addAll(Arrays.asList(beanFactory.getBeanNamesForAnnotation(annotationType))); -// } -// -// resultList.addAll(Arrays.asList(super.getBeanNamesForAnnotation(annotationType))); -// return resultList.toArray(new String[]{}); -// } - -// @Override -// public Map getBeansWithAnnotation(Class annotationType) -// throws BeansException { -// Map resultMap = new HashMap<>(); -// -// for (Module module : moduleManager) { -// ListableBeanFactory beanFactory = module.getBeanFactory(); -// resultMap.putAll(beanFactory.getBeansWithAnnotation(annotationType)); -// } -// -// resultMap.putAll(super.getBeansWithAnnotation(annotationType)); -// return resultMap; -// } - @Override public String[] getBeanNamesForType(@Nullable Class type, boolean includeNonSingletons, boolean allowEagerInit) { if (!isTypeCollected(type)) { @@ -952,7 +906,7 @@ public class PlatformBeanFactory extends DefaultListableBeanFactory { * @param type * @return */ - private boolean isTypeCollected(Class type) { + protected boolean isTypeCollected(Class type) { if (type.getName().equals("javax.servlet.Filter")) { return true; } @@ -966,4 +920,14 @@ public class PlatformBeanFactory extends DefaultListableBeanFactory { return false; } + + // 重写以支持ModuleBeanFactory调用 + public void beforeSingletonCreation(String beanName) { + super.beforeSingletonCreation(beanName); + } + + public void afterSingletonCreation(String beanName) { + super.afterSingletonCreation(beanName); + } + } -- Gitee