diff --git a/caf-multicontext/src/main/java/io/iec/edp/caf/multicontext/context/PlatformApplicationContext.java b/caf-multicontext/src/main/java/io/iec/edp/caf/multicontext/context/PlatformApplicationContext.java index 8842e079db413ce8966e3b0232e246a81884fd65..4342f390cfe4626e4c16ea717469e4d7f91cdf10 100644 --- a/caf-multicontext/src/main/java/io/iec/edp/caf/multicontext/context/PlatformApplicationContext.java +++ b/caf-multicontext/src/main/java/io/iec/edp/caf/multicontext/context/PlatformApplicationContext.java @@ -35,14 +35,7 @@ import io.iec.edp.caf.multicontext.factory.ModuleBeanFactory; import io.iec.edp.caf.multicontext.factory.PlatformBeanFactory; import io.iec.edp.caf.multicontext.hibernate.CustomHibernatePropertiesCustomizer; import io.iec.edp.caf.multicontext.resolver.MultiContextResourceResolver; -import io.iec.edp.caf.multicontext.support.BeanCollectorBeanFactoryPostProcessor; -import io.iec.edp.caf.multicontext.support.LocalThreadModule; -import io.iec.edp.caf.multicontext.support.Module; -import io.iec.edp.caf.multicontext.support.ModuleManager; -import io.iec.edp.caf.multicontext.support.ModuleMetadataReaderFactoryPostProcessor; -import io.iec.edp.caf.multicontext.support.ModuleSplittingCalculator; -import io.iec.edp.caf.multicontext.support.ServiceUnitManager; -import io.iec.edp.caf.multicontext.support.SpringFactoriesOperator; +import io.iec.edp.caf.multicontext.support.*; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import lombok.var; @@ -65,7 +58,6 @@ import org.springframework.core.io.support.ResourcePatternResolver; import java.io.File; import java.lang.annotation.Annotation; - import java.net.URL; import java.net.URLClassLoader; import java.util.*; @@ -347,6 +339,10 @@ public class PlatformApplicationContext extends AnnotationConfigServletWebServer moduleApplicationContext.setEnvironment(this.getEnvironment()); moduleApplicationContext.addBeanFactoryPostProcessor(new ModuleMetadataReaderFactoryPostProcessor()); moduleApplicationContext.addBeanFactoryPostProcessor(new BeanCollectorBeanFactoryPostProcessor()); + if (CafEnvironment.getEnvironment().getProperty("caf-boot.persistence.repository.lazy", "false").equals("true")) { + // 模块添加 BeanFactoryPostProcessor + moduleApplicationContext.addBeanFactoryPostProcessor(new LazyRepositoryBeanFactoryPostProcessor()); + } log.info(module.getName()); moduleManager.addModule(new Module(module.getName(), classLoader, module.getIncludes(), moduleApplicationContext, moduleBeanFactory)); @@ -545,12 +541,6 @@ public class PlatformApplicationContext extends AnnotationConfigServletWebServer break; } } -// ConstructorArgumentValues constructorArguments = beanDefinition.getConstructorArgumentValues(); -// if(constructorArguments.getArgumentValue(0, String[].class)!=null){ -// String[] value = (String[]) constructorArguments.getArgumentValue(0, String[].class).getValue(); -// packages.addAll(Arrays.asList(value)); -// module.getBeanFactory().removeBeanDefinition(EntityScanPackages.class.getName()); -// } } EntityScanPackages.register((BeanDefinitionRegistry) this.getBeanFactory(), packages); @@ -568,7 +558,6 @@ public class PlatformApplicationContext extends AnnotationConfigServletWebServer for (Module module : moduleManager) { ModuleApplicationContext context = module.getContext(); -// executor.execute(countDownLatchWrap(() -> context.registerBeanPostProcessors(null), countDownLatch, module, "registerBeanPostProcessors")); executor.execute(countDownLatchWrap(() -> { /** * 模块自身注册BeanPostProcessors之后先把platformacontext里的一些属于我们自己的beanpostprocesser也注册到模块里 @@ -651,8 +640,6 @@ public class PlatformApplicationContext extends AnnotationConfigServletWebServer @Override protected void onRefresh() { long time = System.currentTimeMillis(); -// long logTime = System.currentTimeMillis(); -// long logCost = System.currentTimeMillis()-logTime; super.onRefresh(); log.info("platform onRefresh total time: " + (System.currentTimeMillis()-time) + "ms"); @@ -667,9 +654,7 @@ public class PlatformApplicationContext extends AnnotationConfigServletWebServer LocalThreadModule.purgeModule(); }, countDownLatch, module, "onRefresh")); -// logTime = System.currentTimeMillis(); StartupAnalysisLog.countBeanMap(module.getName(),module.getBeanFactory()); -// logCost += (System.currentTimeMillis()-logTime); } try { @@ -885,23 +870,25 @@ public class PlatformApplicationContext extends AnnotationConfigServletWebServer * @param stage * @return */ - private Runnable countDownLatchWrap(Runnable runnable, CountDownLatch countDownLatch, io.iec.edp.caf.multicontext.support.Module module, String stage) { + private Runnable countDownLatchWrap(Runnable runnable, CountDownLatch countDownLatch, Module module, String stage) { return () -> { + Thread.currentThread().setName(module.getName()); long time = System.currentTimeMillis(); try { + if (log.isDebugEnabled()) log.debug("[{}] - {} started", module.getName(), stage); runnable.run(); } catch (Exception e) { - log.error("Failed to start " + module.getName()+":"+stage, e); + log.error("Failed to start " + module.getName() + ":" + stage, e); //默认检查 - String parallelMode = this.getEnvironment().getProperty("parallel.mode","check"); - if(!parallelMode.equals("start")){ + String parallelMode = this.getEnvironment().getProperty("parallel.mode", "check"); + if (!parallelMode.equals("start")) { throw new ParallelStartUpException(e); } } finally { long cost = System.currentTimeMillis() - time; - StartupAnalysisLog.countBeanStepTime(module.getName(),stage,cost); + if (log.isDebugEnabled()) log.debug("[{}] - {} completed in {} ms", module.getName(), stage, cost); + StartupAnalysisLog.countBeanStepTime(module.getName(), stage, cost); countDownLatch.countDown(); - log.info(module.getName() + " " + stage + " time: " + cost + "ms"); } }; } diff --git a/caf-multicontext/src/main/java/io/iec/edp/caf/multicontext/support/LazyRepositoryBeanFactoryPostProcessor.java b/caf-multicontext/src/main/java/io/iec/edp/caf/multicontext/support/LazyRepositoryBeanFactoryPostProcessor.java new file mode 100644 index 0000000000000000000000000000000000000000..7d75057ea0080800c0772f74e43b94c3fffbb16f --- /dev/null +++ b/caf-multicontext/src/main/java/io/iec/edp/caf/multicontext/support/LazyRepositoryBeanFactoryPostProcessor.java @@ -0,0 +1,92 @@ +package io.iec.edp.caf.multicontext.support; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.config.DependencyDescriptor; +import org.springframework.beans.factory.support.AbstractBeanFactory; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver; +import org.springframework.data.repository.Repository; + +import java.util.ArrayList; +import java.util.List; + +/** + * 懒加载 原生Repository Bean(并行模式下发挥作用) + * @since 2026/5/11 + */ +@Slf4j +public class LazyRepositoryBeanFactoryPostProcessor implements BeanFactoryPostProcessor { + + // JPA Repository类型集合(必须为实例变量,实现并行启动单元隔离) + private final List JPA_REPOSITORY_TYPE = new ArrayList<>(512); + + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { + long amount = 0; + + if (log.isInfoEnabled()) + log.info("Start modifying the bean definition of JpaRepositoryFactoryBean to set lazyInit to true"); + + // 1.将 repository 类型Bean设置 lazyInit=true + String[] beanNames = beanFactory.getBeanDefinitionNames(); + for (String beanName : beanNames) { + // 处理 BeanDefinition + BeanDefinition definition = beanFactory.getBeanDefinition(beanName); + // 判断是否是 Repository 的 FactoryBean: 包含 JpaRepositoryFactoryBean + String beanClassName = definition.getBeanClassName(); + if (beanClassName != null && beanClassName.contains("JpaRepositoryFactoryBean") && !beanClassName.contains("CafJpaRepositoryFactoryBean")) { + // 在实例化发生前,将初始化模式设为 lazy + definition.setLazyInit(true); + definition.getPropertyValues().addPropertyValue("lazyInit", true); + + // 记录 Repository 真实类型 + Object factoryBeanObjectType = definition.getAttribute("factoryBeanObjectType"); + if (factoryBeanObjectType != null) JPA_REPOSITORY_TYPE.add(factoryBeanObjectType.toString()); + + amount++; + } + } + + // 2.清理mergedBeanDefinition缓存 + if (beanFactory instanceof AbstractBeanFactory) { + if (log.isInfoEnabled()) log.info("Start clear BeanFactory metadataCache"); + + ((AbstractBeanFactory) beanFactory).clearMetadataCache(); + } + + // 3.覆盖AutowireCandidateResolver + ((DefaultListableBeanFactory) beanFactory).setAutowireCandidateResolver(new LazyRepoContextAnnotationAutowireCandidateResolver(this)); + + if (log.isInfoEnabled()) + log.info("Finish modifying the bean definition of JpaRepositoryFactoryBean, the amount is {}, JPA_REPOSITORY_TYPE amount: {}", amount, JPA_REPOSITORY_TYPE.size()); + } + + /** + * 将通过 spring-data-jpa @EnableJpaRepositories 发布的 repository 设定为 lazy-init + */ + static class LazyRepoContextAnnotationAutowireCandidateResolver extends ContextAnnotationAutowireCandidateResolver { + private LazyRepositoryBeanFactoryPostProcessor postProcessor; + + public LazyRepoContextAnnotationAutowireCandidateResolver(LazyRepositoryBeanFactoryPostProcessor postProcessor) { + this.postProcessor = postProcessor; + } + + protected boolean isLazy(DependencyDescriptor descriptor) { + Class type = descriptor.getDependencyType(); + if (Repository.class.isAssignableFrom(type) && this.postProcessor.JPA_REPOSITORY_TYPE.contains(type.getName())) { + if (log.isDebugEnabled()) + log.debug("Repository [{}] has been set to lazy initialization.", type.getName()); + + return true; + } + + return super.isLazy(descriptor); + } + + } + +}