diff --git a/docs/performance/optimize-app.md b/docs/performance/optimize-app.md
index ac164870c..56e088509 100644
--- a/docs/performance/optimize-app.md
+++ b/docs/performance/optimize-app.md
@@ -13,6 +13,7 @@
* `nop.auth.login.allow-create-default-user`不设置或者设置为false,启动时就不会检查数据库中是否至少存在一个用户。
* `nop.web.auto-load-dynamic-file`不设置或者设置为false, 启动时就不会自动将xjs翻译为js文件。
* `nop.graphql.eager-init-biz-object`设置为false, 启动时不会立刻解析meta文件等创建BizObject,而是访问到某个对象时再延迟创建
+* `nop.ioc.app-beans-container.concurrent-start`设置为true, 则启动时在线程池上执行bean容器的初始化操作,不阻塞主线程
## 优化应用运行时性能
* `nop.debug` 设置为false, 就不会在dump目录下产生输出
diff --git a/nop-api-core/src/main/java/io/nop/api/core/ioc/IBeanContainer.java b/nop-api-core/src/main/java/io/nop/api/core/ioc/IBeanContainer.java
index d7319ef79..98b6c0af6 100644
--- a/nop-api-core/src/main/java/io/nop/api/core/ioc/IBeanContainer.java
+++ b/nop-api-core/src/main/java/io/nop/api/core/ioc/IBeanContainer.java
@@ -17,6 +17,13 @@ public interface IBeanContainer extends IBeanProvider {
void start();
+ /**
+ * 异步启动时强制等待启动完毕
+ */
+ default void awaitStartFinished(){
+
+ }
+
void stop();
void restart();
diff --git a/nop-biz/src/main/resources/_vfs/nop/biz/beans/biz-defaults.beans.xml b/nop-biz/src/main/resources/_vfs/nop/biz/beans/biz-defaults.beans.xml
index dfbb85e8e..0252a0d49 100644
--- a/nop-biz/src/main/resources/_vfs/nop/biz/beans/biz-defaults.beans.xml
+++ b/nop-biz/src/main/resources/_vfs/nop/biz/beans/biz-defaults.beans.xml
@@ -74,9 +74,9 @@
-
+
diff --git a/nop-commons/src/main/java/io/nop/commons/CommonConfigs.java b/nop-commons/src/main/java/io/nop/commons/CommonConfigs.java
index f528444ad..0d639e677 100644
--- a/nop-commons/src/main/java/io/nop/commons/CommonConfigs.java
+++ b/nop-commons/src/main/java/io/nop/commons/CommonConfigs.java
@@ -24,7 +24,7 @@ public interface CommonConfigs {
@Description("全局工作线程池的大小")
IConfigReference CFG_CONCURRENT_GLOBAL_WORKER_MAX_POOL_SIZE = varRef(s_loc,
- "nop.commons.concurrent.global-worker.maxPoolSize", Integer.class, 50);
+ "nop.commons.concurrent.global-worker.maxPoolSize", Integer.class, 30);
@Description("限制StringHelper.repeat函数的参数值小于指定值,不会过大")
IConfigReference CFG_UTILS_STRING_MAX_REPEAT_LEN = varRef(s_loc, "nop.commons.util.string-max-repeat-len",
diff --git a/nop-demo/nop-quarkus-demo/src/main/resources/META-INF/native-image/io.nop.demo/nop-quarkus-demo/reflect-config.json b/nop-demo/nop-quarkus-demo/src/main/resources/META-INF/native-image/io.nop.demo/nop-quarkus-demo/reflect-config.json
index 1bb59991f..effd02ba9 100644
--- a/nop-demo/nop-quarkus-demo/src/main/resources/META-INF/native-image/io.nop.demo/nop-quarkus-demo/reflect-config.json
+++ b/nop-demo/nop-quarkus-demo/src/main/resources/META-INF/native-image/io.nop.demo/nop-quarkus-demo/reflect-config.json
@@ -6558,6 +6558,29 @@
"methods": [],
"name": "io.nop.integration.qrcode.ZxingQrcodeService"
},
+ {
+ "allDeclaredConstructors": true,
+ "allDeclaredMethods": true,
+ "allPublicConstructors": true,
+ "allPublicFields": true,
+ "allPublicMethods": true,
+ "fields": [
+ {
+ "name": "beanId"
+ },
+ {
+ "name": "created"
+ },
+ {
+ "name": "depends"
+ },
+ {
+ "name": "threadId"
+ }
+ ],
+ "methods": [],
+ "name": "io.nop.ioc.impl.BeanContainerImpl$BeanCreation"
+ },
{
"allDeclaredConstructors": true,
"allDeclaredMethods": true,
diff --git a/nop-demo/nop-quarkus-demo/src/main/resources/application.yaml b/nop-demo/nop-quarkus-demo/src/main/resources/application.yaml
index b8c5cccc8..4e6f292ed 100644
--- a/nop-demo/nop-quarkus-demo/src/main/resources/application.yaml
+++ b/nop-demo/nop-quarkus-demo/src/main/resources/application.yaml
@@ -75,7 +75,7 @@ nop:
auth:
login:
- allow-create-default-user: true # 如果用户表为空,则自动创建缺省账户nop, 密码nop-test
+ allow-create-default-user: false # 如果用户表为空,则自动创建缺省账户nop, 密码nop-test
datasource:
driver-class-name: org.h2.Driver
@@ -84,11 +84,11 @@ nop:
password:
web:
- validate-page-model: true
+ validate-page-model: false
auto-load-dynamic-file: false
orm:
- init-database-schema: true
+ init-database-schema: false
db-differ:
auto-upgrade-database: false
@@ -97,6 +97,9 @@ nop:
schema-introspection:
enabled: true
+ ioc:
+ app-beans-container:
+ concurrent-start: true
# devservices 会启用testcontainers来管理测试数据库
quarkus:
diff --git a/nop-demo/nop-quarkus-demo/src/main/resources/nop-vfs-index.txt b/nop-demo/nop-quarkus-demo/src/main/resources/nop-vfs-index.txt
index 61c2a41fb..c8ce25630 100644
--- a/nop-demo/nop-quarkus-demo/src/main/resources/nop-vfs-index.txt
+++ b/nop-demo/nop-quarkus-demo/src/main/resources/nop-vfs-index.txt
@@ -296,6 +296,7 @@
/nop/core/registry/dao-wf.register-model.xml
/nop/core/registry/dialect.register-model.xml
/nop/core/registry/dict.register-model.xml
+/nop/core/registry/fsm.register-model.xml
/nop/core/registry/gateway.register-model.xml
/nop/core/registry/graph-designer.register-model.xml
/nop/core/registry/imp.register-model.xml
@@ -433,9 +434,7 @@
/nop/dyn/model/NopDynPage/_NopDynPage.xbiz
/nop/dyn/model/NopDynPage/_NopDynPage.xmeta
/nop/dyn/model/NopDynPatch/NopDynPatch.xbiz
-/nop/dyn/model/NopDynPatch/NopDynPatch.xmeta
/nop/dyn/model/NopDynPatch/_NopDynPatch.xbiz
-/nop/dyn/model/NopDynPatch/_NopDynPatch.xmeta
/nop/dyn/model/NopDynPatchFile/NopDynPatchFile.xbiz
/nop/dyn/model/NopDynPatchFile/NopDynPatchFile.xmeta
/nop/dyn/model/NopDynPatchFile/_NopDynPatchFile.xbiz
@@ -510,11 +509,6 @@
/nop/dyn/pages/NopDynPage/main.page.yaml
/nop/dyn/pages/NopDynPage/picker.page.yaml
/nop/dyn/pages/NopDynPage/ref-module.page.yaml
-/nop/dyn/pages/NopDynPatch/NopDynPatch.lib.xjs
-/nop/dyn/pages/NopDynPatch/NopDynPatch.view.xml
-/nop/dyn/pages/NopDynPatch/_gen/_NopDynPatch.view.xml
-/nop/dyn/pages/NopDynPatch/main.page.yaml
-/nop/dyn/pages/NopDynPatch/picker.page.yaml
/nop/dyn/pages/NopDynPatchFile/NopDynPatchFile.lib.xjs
/nop/dyn/pages/NopDynPatchFile/NopDynPatchFile.view.xml
/nop/dyn/pages/NopDynPatchFile/_gen/_NopDynPatchFile.view.xml
diff --git a/nop-ioc/src/main/java/io/nop/ioc/IocConfigs.java b/nop-ioc/src/main/java/io/nop/ioc/IocConfigs.java
index 9f92ff1c7..d2fe89498 100644
--- a/nop-ioc/src/main/java/io/nop/ioc/IocConfigs.java
+++ b/nop-ioc/src/main/java/io/nop/ioc/IocConfigs.java
@@ -18,6 +18,9 @@ public interface IocConfigs {
IConfigReference CFG_IOC_APP_BEANS_CONTAINER_START_MODE = AppConfig
.varRef(s_loc, "nop.ioc.app-beans-container.start-mode", String.class, null);
+ @Description("是否初始化IoC容器")
+ IConfigReference CFG_IOC_APP_BEANS_CONCURRENT_START = AppConfig.varRef(s_loc, "nop.ioc.app-beans-container.concurrent-start", Boolean.class, false);
+
@Description("是否自动装载所有模块下的beans/app-*.beans.xml文件")
IConfigReference CFG_IOC_APP_BEANS_FILE_ENABLED = AppConfig.varRef(s_loc, "nop.ioc.app-beans-file.enabled",
Boolean.class, true);
diff --git a/nop-ioc/src/main/java/io/nop/ioc/impl/BeanContainerImpl.java b/nop-ioc/src/main/java/io/nop/ioc/impl/BeanContainerImpl.java
index 9d39b4b27..342df002c 100644
--- a/nop-ioc/src/main/java/io/nop/ioc/impl/BeanContainerImpl.java
+++ b/nop-ioc/src/main/java/io/nop/ioc/impl/BeanContainerImpl.java
@@ -14,9 +14,14 @@
import io.nop.api.core.exceptions.NopException;
import io.nop.api.core.ioc.BeanContainerStartMode;
import io.nop.api.core.ioc.IBeanContainer;
+import io.nop.api.core.util.FutureHelper;
+import io.nop.api.core.util.ICancellable;
+import io.nop.commons.concurrent.executor.GlobalExecutors;
import io.nop.commons.lang.IClassLoader;
+import io.nop.commons.lang.impl.Cancellable;
import io.nop.commons.util.ClassHelper;
import io.nop.core.lang.xml.XNode;
+import io.nop.core.model.graph.TaskExecutionGraph;
import io.nop.ioc.api.BeanScopeContext;
import io.nop.ioc.api.IBeanContainerImplementor;
import io.nop.ioc.api.IBeanDefinition;
@@ -35,6 +40,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import static io.nop.ioc.IocConstants.PRODUCER_BEAN_PREFIX;
@@ -62,7 +68,7 @@ public class BeanContainerImpl implements IBeanContainerImplementor {
private final List orderedBeans;
private volatile boolean running;
- private boolean started;
+ private volatile boolean started;
private final Map, BeanTypeMapping> beansByType = new ConcurrentHashMap<>();
private final Map, List> beansByAnnotation = new ConcurrentHashMap<>();
@@ -77,6 +83,12 @@ public class BeanContainerImpl implements IBeanContainerImplementor {
private BeanContainerStartMode startMode = BeanContainerStartMode.DEFAULT;
private Map aliases;
+ private Cancellable cancellable;
+
+ private boolean concurrentStart;
+
+ private CompletableFuture> startFuture;
+
public BeanContainerImpl(String id, Map enabledBeans,
Collection optionalBeans,
Map aliases, IBeanContainer parentContainer) {
@@ -138,6 +150,10 @@ public void setClassIntrospection(IBeanClassIntrospection classIntrospection) {
this.classIntrospection = classIntrospection;
}
+ public void setConcurrentStart(boolean concurrentStart) {
+ this.concurrentStart = concurrentStart;
+ }
+
public String getId() {
return id;
}
@@ -356,12 +372,17 @@ private Object getBean0(BeanDefinition beanDef, boolean onlyProducer, boolean in
if (includeCreating && beanScope != null) {
Object bean = beanScope.get(beanDef.getId());
if (bean != null) {
- bean = beanDef.getBeanInstance(bean, onlyProducer);
- if (bean == null)
- throw new NopException(ERR_IOC_PRODUCER_BEAN_NOT_INITED).param(ARG_BEAN, beanDef)
- .param(ARG_BEAN_NAME, beanDef.getId());
+ Object createdBean = beanDef.getBeanInstance(bean, onlyProducer);
+ if (createdBean == null) {
+ // 如果是并行启动,则允许等待一段时间
+ if (concurrentStart && !started)
+ createdBean = ((ProducedBeanInstance) bean).awaitGetBean(10000);
+ if (createdBean == null)
+ throw new NopException(ERR_IOC_PRODUCER_BEAN_NOT_INITED).param(ARG_BEAN, beanDef)
+ .param(ARG_BEAN_NAME, beanDef.getId());
+ }
- return bean;
+ return createdBean;
}
}
@@ -378,6 +399,7 @@ private Object getBean0(BeanDefinition beanDef, boolean onlyProducer, boolean in
if (bean == null) {
LOG.info("nop.new-bean:{}", beanDef);
bean = beanDef.newObject(beanScope, this);
+ LOG.trace("nop.new-bean-completed:{}", beanDef);
if (isStarted() && beanDef.hasDelayMethod()) {
beanDef.runDelayMethod(bean, beanScope, this);
}
@@ -439,35 +461,129 @@ public void start() {
if (running)
throw new NopException(ERR_IOC_CONTAINER_ALREADY_STARTED).param(ARG_CONTAINER_ID, id);
+ startFuture = null;
LOG.info("nop.ioc.start-container:containerId={}", getId());
running = true;
singletonScope = new BeanScopeImpl(ApiConstants.BEAN_SCOPE_SINGLETON, XLang.newEvalScope(), this);
try {
+ List startBeans = new ArrayList<>();
+
for (BeanDefinition bean : orderedBeans) {
if (bean.isSingleton()) {
if (startMode == BeanContainerStartMode.ALL_LAZY) {
// 只创建具有delayMethod的bean
if (bean.hasDelayMethod() && !bean.isLazyInit() || bean.isIocForceInit()) {
- getBean0(bean, true, true);
+ startBean(startBeans, bean);
}
} else if (startMode == BeanContainerStartMode.ALL_EAGER || !bean.isLazyInit()) {
- getBean0(bean, true, true);
+ startBean(startBeans, bean);
}
}
}
- runDelayMethod();
- } catch (Exception e) {
- try {
- stop();
- } catch (Exception e2) {
- LOG.error("nop.err.ioc.stop-failed", e2);
+ if (concurrentStart) {
+ startFuture = asyncStartBeans(startBeans).whenComplete((ret, err) -> {
+ if (err != null) {
+ handleStartError(err);
+ } else {
+ runDelayMethod();
+ started = true;
+ }
+ LOG.info("nop.ioc.async-start-finished:{}",getId());
+ });
+ } else {
+ runDelayMethod();
+ started = true;
+ LOG.info("nop.ioc.start-finished:{}",getId());
}
+ } catch (Exception e) {
+ // dumpCreations();
+ handleStartError(e);
throw e;
}
- started = true;
+ }
+
+ void handleStartError(Throwable e) {
+ LOG.error("nop.err.ioc.start-failed", e);
+ try {
+ stop();
+ } catch (Exception e2) {
+ LOG.error("nop.err.ioc.stop-failed", e2);
+ }
+ }
+
+ @Override
+ public void awaitStartFinished() {
+ if (startFuture != null)
+ FutureHelper.syncGet(startFuture);
+ }
+
+ /*
+ @DataBean
+ public static class BeanCreation {
+ final String threadName;
+ final String beanId;
+ final Set depends;
+ final boolean created;
+
+ public BeanCreation(String threadName, String beanId, Set depends, boolean created) {
+ this.threadName = threadName;
+ this.beanId = beanId;
+ this.depends = depends;
+ this.created = created;
+ }
+
+ public String toString() {
+ return StringHelper.rightPad(threadName,25,' ') + " " + beanId + (created ? depends : "");
+ }
+
+ public String getThreadName() {
+ return threadName;
+ }
+
+ public String getBeanId() {
+ return beanId;
+ }
+
+ public Set getDepends() {
+ return depends;
+ }
+
+ public boolean isCreated() {
+ return created;
+ }
+ }
+
+ Queue beanCreations = new LinkedTransferQueue<>();
+
+ void dumpCreations() {
+ System.out.println(StringHelper.join(beanCreations,"\r\n"));
+ }*/
+
+ CompletableFuture asyncStartBeans(List startBeans) {
+ TaskExecutionGraph graph = new TaskExecutionGraph("ioc-container-start");
+ for (BeanDefinition bean : startBeans) {
+ graph.addTaskWithDepends(bean.getId(),
+ () -> {
+ // beanCreations.add(new BeanCreation(Thread.currentThread().getName(), bean.getId(), graph.getDepends(bean.getId()), false));
+ getBean0(bean, true, false);
+ // beanCreations.add(new BeanCreation(Thread.currentThread().getName(), bean.getId(), graph.getDepends(bean.getId()), true));
+ },
+ bean.getDependBeanIds());
+ }
+ graph.analyze();
+ this.cancellable = new Cancellable();
+ return graph.runOnExecutor(GlobalExecutors.globalWorker(), this.cancellable);
+ }
+
+ void startBean(List startBeans, BeanDefinition bean) {
+ if (concurrentStart) {
+ startBeans.add(bean);
+ } else {
+ getBean0(bean, true, false);
+ }
}
void runDelayMethod() {
@@ -479,6 +595,7 @@ void runDelayMethod() {
beanDef.runDelayMethod(instance, beanScope, this);
}
}
+ LOG.info("nop.ioc.run-delay-method-finished");
}
@Override
@@ -486,6 +603,10 @@ public void stop() {
LOG.info("nop.ioc.stop-container:containerId={}", getId());
running = false;
started = false;
+ if (cancellable != null) {
+ cancellable.cancel(ICancellable.CANCEL_REASON_STOP);
+ cancellable = null;
+ }
if (singletonScope != null)
singletonScope.close();
BeanScopeContext.instance().onContainerStop(this);
diff --git a/nop-ioc/src/main/java/io/nop/ioc/impl/BeanDefinition.java b/nop-ioc/src/main/java/io/nop/ioc/impl/BeanDefinition.java
index f9909642c..70be98a97 100644
--- a/nop-ioc/src/main/java/io/nop/ioc/impl/BeanDefinition.java
+++ b/nop-ioc/src/main/java/io/nop/ioc/impl/BeanDefinition.java
@@ -89,6 +89,8 @@ public class BeanDefinition implements IBeanDefinition {
private boolean intercepted;
private boolean removed;
+ private List dependBeanIds;
+
private Set nextBeans = Collections.emptySet();
/**
@@ -135,6 +137,14 @@ public void setConstructorAutowired(boolean constructorAutowired) {
this.constructorAutowired = constructorAutowired;
}
+ public List getDependBeanIds() {
+ return dependBeanIds;
+ }
+
+ public void setDependBeanIds(List dependBeanIds) {
+ this.dependBeanIds = dependBeanIds;
+ }
+
public boolean isRemoved() {
return removed;
}
diff --git a/nop-ioc/src/main/java/io/nop/ioc/impl/BeanTopologySorter.java b/nop-ioc/src/main/java/io/nop/ioc/impl/BeanTopologySorter.java
index e9bf200ab..f47de61e8 100644
--- a/nop-ioc/src/main/java/io/nop/ioc/impl/BeanTopologySorter.java
+++ b/nop-ioc/src/main/java/io/nop/ioc/impl/BeanTopologySorter.java
@@ -105,6 +105,10 @@ private List sortBeans(List beans, Set l
}
}
+ for(BeanDefinition bean: beans){
+ bean.setDependBeanIds(graph.getSourceVertexes(bean.getId()));
+ }
+
if (LOG.isTraceEnabled())
LOG.trace(graph.toDot(node -> node, "beans"));
diff --git a/nop-ioc/src/main/java/io/nop/ioc/impl/ProducedBeanInstance.java b/nop-ioc/src/main/java/io/nop/ioc/impl/ProducedBeanInstance.java
index 6f27418cd..7dad5e6fe 100644
--- a/nop-ioc/src/main/java/io/nop/ioc/impl/ProducedBeanInstance.java
+++ b/nop-ioc/src/main/java/io/nop/ioc/impl/ProducedBeanInstance.java
@@ -7,15 +7,23 @@
*/
package io.nop.ioc.impl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import java.lang.reflect.InvocationHandler;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
/**
* 如果存在beanMethod,则createdBean为factoryBean, bean为对factoryBean.beanMethod()的返回结果进行aopProxy处理后的最终对象
* 如果不存在beanMethod,则createdBean则为根据bean的class设置所创建的InvocationHandler对象,而bean为经过aopProxy处理的结果
*/
public class ProducedBeanInstance {
+ static final Logger LOG = LoggerFactory.getLogger(ProducedBeanInstance.class);
+
private final Object createdBean;
private Object bean;
+ private final CountDownLatch latch = new CountDownLatch(1);
public ProducedBeanInstance(Object createdBean) {
this.createdBean = createdBean;
@@ -35,5 +43,17 @@ public synchronized Object getBean() {
public synchronized void setBean(Object bean) {
this.bean = bean;
+ latch.countDown();
+ }
+
+ public Object awaitGetBean(int timeout) {
+ try {
+ boolean b = latch.await(timeout, TimeUnit.MILLISECONDS);
+ if(!b)
+ LOG.debug("nop.ioc.await-get-bean-not-ready: bean={}, timeout={}", createdBean, timeout);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ return bean;
}
}
diff --git a/nop-ioc/src/main/java/io/nop/ioc/loader/AppBeanContainerLoader.java b/nop-ioc/src/main/java/io/nop/ioc/loader/AppBeanContainerLoader.java
index 0a1b80f14..95d0ac2ed 100644
--- a/nop-ioc/src/main/java/io/nop/ioc/loader/AppBeanContainerLoader.java
+++ b/nop-ioc/src/main/java/io/nop/ioc/loader/AppBeanContainerLoader.java
@@ -37,6 +37,7 @@
import java.util.Set;
import java.util.function.Predicate;
+import static io.nop.ioc.IocConfigs.CFG_IOC_APP_BEANS_CONCURRENT_START;
import static io.nop.ioc.IocConfigs.CFG_IOC_APP_BEANS_CONTAINER_START_MODE;
import static io.nop.ioc.IocConfigs.CFG_IOC_APP_BEANS_FILES;
import static io.nop.ioc.IocConfigs.CFG_IOC_APP_BEANS_FILE_ENABLED;
@@ -74,6 +75,7 @@ public IBeanContainerImplementor loadFromResource(String name, IResource resourc
public IBeanContainerImplementor loadAppContainer(IBeanContainer parentContainer) {
BeanContainerBuilder builder = new BeanContainerBuilder(classLoader, introspection, parentContainer);
+ builder.concurrentStart(CFG_IOC_APP_BEANS_CONCURRENT_START.get());
BeanContainerStartMode startMode = BeanContainerStartMode
.fromText(CFG_IOC_APP_BEANS_CONTAINER_START_MODE.get());
diff --git a/nop-ioc/src/main/java/io/nop/ioc/loader/BeanContainerBuilder.java b/nop-ioc/src/main/java/io/nop/ioc/loader/BeanContainerBuilder.java
index 99c4e7fc3..fa2e0bd60 100644
--- a/nop-ioc/src/main/java/io/nop/ioc/loader/BeanContainerBuilder.java
+++ b/nop-ioc/src/main/java/io/nop/ioc/loader/BeanContainerBuilder.java
@@ -66,6 +66,7 @@ public class BeanContainerBuilder implements IBeanContainerBuilder {
private final IBeanContainer parentContainer;
private BeanContainerStartMode startMode;
+ private boolean concurrentStart;
public BeanContainerBuilder(IClassLoader classLoader, IBeanClassIntrospection introspection,
IBeanContainer parentContainer) {
@@ -88,6 +89,11 @@ public IBeanContainerBuilder startMode(BeanContainerStartMode startMode) {
return this;
}
+ public IBeanContainerBuilder concurrentStart(boolean concurrentStart) {
+ this.concurrentStart = concurrentStart;
+ return this;
+ }
+
@Override
public IBeanContainerBuilder addResource(IResource resource) {
BeansModel beans = (BeansModel) new DslModelParser(IocConstants.XDEF_BEANS).parseFromResource(resource);
@@ -344,6 +350,8 @@ public IBeanContainerImplementor build(String containerId) {
enabledBeans, optionalBeans, aliases, parentContainer);
if (startMode != null)
container.setStartMode(startMode);
+ container.setConcurrentStart(concurrentStart);
+ container.setClassIntrospection(this.introspection);
return container;
}
}
\ No newline at end of file
diff --git a/nop-ioc/src/main/java/io/nop/ioc/loader/IBeanContainerBuilder.java b/nop-ioc/src/main/java/io/nop/ioc/loader/IBeanContainerBuilder.java
index 17cff2c42..131315bbf 100644
--- a/nop-ioc/src/main/java/io/nop/ioc/loader/IBeanContainerBuilder.java
+++ b/nop-ioc/src/main/java/io/nop/ioc/loader/IBeanContainerBuilder.java
@@ -26,6 +26,8 @@ public interface IBeanContainerBuilder {
IBeanContainerBuilder startMode(BeanContainerStartMode startMode);
+ IBeanContainerBuilder concurrentStart(boolean concurrentStart);
+
IBeanContainerBuilder registerBean(String beanName, Class beanClass,
Function supplier, Consumer customizer);
diff --git a/nop-quarkus/nop-quarkus-core-starter/src/main/java/io/nop/quarkus/core/dao/AgroalDataSourceFactoryBean.java b/nop-quarkus/nop-quarkus-core-starter/src/main/java/io/nop/quarkus/core/dao/AgroalDataSourceFactoryBean.java
index 333f34ed1..5ea54e075 100644
--- a/nop-quarkus/nop-quarkus-core-starter/src/main/java/io/nop/quarkus/core/dao/AgroalDataSourceFactoryBean.java
+++ b/nop-quarkus/nop-quarkus-core-starter/src/main/java/io/nop/quarkus/core/dao/AgroalDataSourceFactoryBean.java
@@ -199,7 +199,8 @@ private void exportMetrics(MeterRegistry metricsFactory, String dataSourceName,
@PreDestroy
public void destroy() {
- dataSource.close();
+ if (dataSource != null)
+ dataSource.close();
}
@BeanMethod
diff --git a/nop-xlang/src/test/java/io/nop/xlang/xdsl/TestGenericDslParser.java b/nop-xlang/src/test/java/io/nop/xlang/xdsl/TestGenericDslParser.java
index 1b43d151d..9e2a7d17a 100644
--- a/nop-xlang/src/test/java/io/nop/xlang/xdsl/TestGenericDslParser.java
+++ b/nop-xlang/src/test/java/io/nop/xlang/xdsl/TestGenericDslParser.java
@@ -84,6 +84,15 @@ public void testParseError() {
public void testFilter() {
XNode node = XNodeParser.instance().parseFromText(null, "");
TreeBean bean = (TreeBean) new DslModelParser().parseFromNode(node);
- System.out.println(JsonTool.serialize(bean,true));
+ System.out.println(JsonTool.serialize(bean, true));
+ }
+
+ @Test
+ public void testXGen() {
+ String text = "";
+ XNode node = XNodeParser.instance().parseFromText(null, text);
+ DynamicObject result = new GenericDslParser().parseFromNode(node);
+ System.out.println(JsonTool.serialize(result, true));
+ assertEquals("true", result.prop_get("ui:default"));
}
}
\ No newline at end of file