You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
414 lines
17 KiB
414 lines
17 KiB
package com.fanruan.boot.env; |
|
|
|
import com.fanruan.boot.FSProperties; |
|
import com.fanruan.boot.KVProperties; |
|
import com.fanruan.boot.LoggerProperties; |
|
import com.fanruan.boot.SchedulerCoreComponent; |
|
import com.fanruan.carina.Carina; |
|
import com.fanruan.carina.annotions.FineComponent; |
|
import com.fanruan.carina.annotions.JPAEntityScan; |
|
import com.fanruan.carina.annotions.Start; |
|
import com.fanruan.carina.annotions.Stop; |
|
import com.fanruan.carina.annotions.Supplemental; |
|
import com.fanruan.config.ConfigProviderFactory; |
|
import com.fanruan.config.realm.ConfigRealm; |
|
import com.fanruan.dao.context.DBContextProvider; |
|
import com.fanruan.dao.context.DBContextStarter; |
|
import com.fanruan.dao.property.DBPropertyProvider; |
|
import com.fanruan.dao.shell.DBContextShell; |
|
import com.fanruan.dao.shell.DBPropertyShell; |
|
import com.fanruan.fs.DesignFileRepository; |
|
import com.fanruan.fs.FileServer; |
|
import com.fanruan.fs.RepositoryFactory; |
|
import com.fanruan.fs.repository.local.LocalFileRepository; |
|
import com.fanruan.kv.CarinaKV; |
|
import com.fanruan.kv.factory.KVStoreFactory; |
|
import com.fanruan.kv.manager.CarinaKVManager; |
|
import com.fanruan.kv.store.KVStore; |
|
import com.fanruan.kv.store.KVStoreHolder; |
|
import com.fanruan.workplace.http.RepositoryManager; |
|
import com.fr.cbb.dialect.security.InsecurityElementFactory; |
|
import com.fr.cluster.ClusterBridge; |
|
import com.fr.cluster.lock.ClusterLock; |
|
import com.fr.config.BaseDBEnv; |
|
import com.fr.config.ConfigEvent; |
|
import com.fr.config.Configuration; |
|
import com.fr.config.FinalPreferenceConfig; |
|
import com.fr.config.dao.DaoContext; |
|
import com.fr.config.dao.impl.BatchSubmitClassHelperDao; |
|
import com.fr.config.dao.impl.BatchSubmitEntityDao; |
|
import com.fr.config.dao.impl.BatchSubmitXmlEntityDao; |
|
import com.fr.config.dao.impl.hibernate.HibernateClassHelperDao; |
|
import com.fr.config.dao.impl.hibernate.HibernateEntityDao; |
|
import com.fr.config.dao.impl.hibernate.HibernateXmlEnityDao; |
|
import com.fr.config.dao.impl.remote.RemoteClassHelperDao; |
|
import com.fr.config.dao.impl.remote.RemoteEntityDao; |
|
import com.fr.config.dao.impl.remote.RemoteXmlEntityDao; |
|
import com.fr.config.holder.ConfigChangeListener; |
|
import com.fr.config.holder.ValidateConfigManger; |
|
import com.fr.config.impl.ConfConfigProviderImpl; |
|
import com.fr.config.impl.ConfigInsecurityElementProviderImpl; |
|
import com.fr.decision.service.context.ServiceContext; |
|
import com.fr.design.backup.EnvBackupHelper; |
|
import com.fr.env.detect.EnvDetectorCenter; |
|
import com.fr.event.EventDispatcher; |
|
import com.fr.general.FRLogger; |
|
import com.fr.general.log.Log4jConfig; |
|
import com.fr.general.log.Log4jUtils; |
|
import com.fr.intelli.metrics.Compute; |
|
import com.fr.intelli.metrics.DBMonitorInterceptor; |
|
import com.fr.intelli.metrics.MonitorInterceptor; |
|
import com.fr.intelli.record.Focus; |
|
import com.fr.intelli.record.FocusInterceptor; |
|
import com.fr.intelli.record.PerformancePoint; |
|
import com.fr.intelli.record.PerformancePointInterceptor; |
|
import com.fr.io.base.ResourcePaths; |
|
import com.fr.io.repository.ResourceRepository; |
|
import com.fr.io.repository.ResourceRepositoryWrapper; |
|
import com.fr.io.utils.ResourceIOUtils; |
|
import com.fr.log.FineLoggerFactory; |
|
|
|
import com.fr.record.analyzer.AnalyzerConfiguration; |
|
import com.fr.record.analyzer.AnalyzerMutableGroup; |
|
import com.fr.record.analyzer.DBMetrics; |
|
import com.fr.scheduler.QuartzContext; |
|
import com.fr.scheduler.SchedulerEvent; |
|
import com.fr.scheduler.tenant.ScheduleThreadCurrentTenantProvider; |
|
import com.fr.security.encryption.EncryptionInitialization; |
|
import com.fr.security.encryption.SystemEncryptionManager; |
|
import com.fr.security.encryption.core.EncryptionScaffold; |
|
import com.fr.security.encryption.provider.SecuritySeedProvider; |
|
import com.fr.security.encryption.storage.keys.LoadSeedSecurityKey; |
|
|
|
import com.fr.stable.StringUtils; |
|
import com.fr.stable.db.DBContext; |
|
import com.fr.stable.db.properties.FineMicroServicesDBProperties; |
|
import com.fr.stable.db.session.DBSession; |
|
import com.fr.stable.project.ProjectConstants; |
|
import com.fr.tenant.context.TenantContext; |
|
import com.fr.tenant.context.provider.CurrentTenantKey; |
|
import com.fr.third.apache.logging.log4j.core.config.Configurator; |
|
import com.fr.third.net.bytebuddy.implementation.MethodDelegation; |
|
import com.fr.third.net.bytebuddy.matcher.ElementMatchers; |
|
import com.fr.third.org.hibernate.jdbc.AbstractWork; |
|
import com.fr.tolerance.FaultTolerance; |
|
import com.fr.tolerance.FaultToleranceInterceptor; |
|
import com.fr.transaction.Configurations; |
|
import com.fr.transaction.FineConfigurationHelper; |
|
import com.fr.transaction.HibernateTransactor; |
|
import com.fr.transaction.RemoteTransactor; |
|
import com.fr.transaction.TransactorFactory; |
|
import com.fr.workspace.WorkContext; |
|
|
|
import java.net.URI; |
|
import java.sql.Connection; |
|
import java.sql.SQLException; |
|
import java.util.Properties; |
|
|
|
/** |
|
* 设计器env模块,环境切换的底层模块 |
|
* |
|
* @author Destiny.Lin |
|
* @since 11.0 |
|
* Created on 2024/6/7 |
|
*/ |
|
@FineComponent(name = "design_env_prepare") |
|
@JPAEntityScan({"com.fr.config.entity", |
|
"com.fr.decision.authority.entity", |
|
"com.fanruan.user.oa.basic.db.entity", |
|
"com.fr.decision.system.entity", |
|
"com.fr.decision.workflow.bean", |
|
"com.fr.report.entity", |
|
"com.fr.report.write.entity" |
|
}) |
|
public class DesignEnvComponent { |
|
|
|
/** |
|
* prepare |
|
*/ |
|
@Supplemental |
|
public void prepare() { |
|
Carina.getApplicationContext().group(AnalyzerMutableGroup.class).add(AnalyzerConfiguration.create((builder, typeDescription, classLoader, module) -> builder |
|
.method(ElementMatchers.isAnnotatedWith(Focus.class)) |
|
.intercept(MethodDelegation.to(FocusInterceptor.class)))); |
|
Carina.getApplicationContext().group(AnalyzerMutableGroup.class).add(AnalyzerConfiguration.create((builder, typeDescription, classLoader, module) -> builder |
|
.method(ElementMatchers.isAnnotatedWith(Compute.class)) |
|
.intercept(MethodDelegation.to(MonitorInterceptor.class)))); |
|
Carina.getApplicationContext().group(AnalyzerMutableGroup.class).add(AnalyzerConfiguration.create((builder, typeDescription, classLoader, module) -> builder |
|
.method(ElementMatchers.isAnnotatedWith(DBMetrics.class)) |
|
.intercept(MethodDelegation.to(DBMonitorInterceptor.class)))); |
|
Carina.getApplicationContext().group(AnalyzerMutableGroup.class).add(AnalyzerConfiguration.create((builder, typeDescription, classLoader, module) -> builder |
|
.method(ElementMatchers.isAnnotatedWith(PerformancePoint.class)) |
|
.intercept(MethodDelegation.to(PerformancePointInterceptor.class)))); |
|
Carina.getApplicationContext().group(AnalyzerMutableGroup.class).add(AnalyzerConfiguration.create((builder, typeDescription, classLoader, module) -> builder |
|
.method(ElementMatchers.isAnnotatedWith(FaultTolerance.class)) |
|
.intercept(MethodDelegation.to(FaultToleranceInterceptor.class)))); |
|
Carina.getApplicationContext().group(CurrentTenantKey.class).add(ScheduleThreadCurrentTenantProvider.INSTANCE); |
|
} |
|
|
|
@Start |
|
public void start() throws Exception { |
|
// 1.环境准备 |
|
startEnvPrepare(); |
|
// 2.core准备 |
|
startCorePrepare(); |
|
// 3.dao启动 |
|
startDao(); |
|
// 4.config启动 |
|
startConfConfig(); |
|
// 5.fileServer启动 |
|
startFileServer(); |
|
// 6.logger启动 |
|
startLogger(); |
|
// 7.kv |
|
startKv(); |
|
// 8.scheduler |
|
startScheduler(); |
|
} |
|
|
|
private void startScheduler() { |
|
if (WorkContext.getCurrent().isLocal()) { |
|
TenantContext.doIsolatedWork(() -> { |
|
ClusterLock lock = ClusterBridge.getLockFactory().get(SchedulerCoreComponent.class); |
|
// 多节点同时启动quartz模块可能会产生脏数据,导致报错,使用集群锁控制一下 |
|
DBSession dbSession = null; |
|
try { |
|
lock.lock(); |
|
final DBContextProvider context = BaseDBEnv.getDBContext(); |
|
if (context == null) { |
|
throw new IllegalArgumentException("ConfigDBActivator must start before SchedulerActivator"); |
|
} |
|
dbSession = context.openSession(); |
|
dbSession.doWork(new AbstractWork() { |
|
|
|
@Override |
|
public void execute(Connection connection) throws SQLException { |
|
//quartz需要的数据库方言 |
|
Properties properties = context.getDBProperties(); |
|
QuartzContext.getInstance().initScheduler(properties); |
|
} |
|
}); |
|
EventDispatcher.fire(SchedulerEvent.START); |
|
} catch (Exception e) { |
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
} finally { |
|
if (dbSession != null) { |
|
dbSession.closeSession(); |
|
} |
|
lock.unlock(); |
|
} |
|
}, "default"); |
|
} |
|
} |
|
|
|
|
|
@Stop |
|
public void stop() { |
|
stopScheduler(); |
|
stopLogger(); |
|
stopFileServer(); |
|
stopConfConfig(); |
|
stopDao(); |
|
stopCorePrepare(); |
|
stopEnvPrepare(); |
|
} |
|
|
|
private void stopScheduler() { |
|
EventDispatcher.fire(SchedulerEvent.STOP); |
|
QuartzContext.getInstance().destroy(); |
|
} |
|
|
|
|
|
/** |
|
* -------------------private------------------- |
|
*/ |
|
|
|
/** |
|
* ----------kv--------- |
|
*/ |
|
private void startKv() { |
|
// KVProperties没有的话默认走内存 |
|
KVStore kvStore = KVStoreFactory.createFineKVStore(Carina.properties(KVProperties.class).getType()); |
|
KVStoreHolder.getInstance().setStore(kvStore); |
|
CarinaKV.switchTo(new CarinaKVManager()); |
|
} |
|
|
|
/** |
|
* ----------- logger -------- |
|
*/ |
|
private void startLogger() { |
|
String realPath = Carina.properties(LoggerProperties.class).getXml(); |
|
URI uri = Log4jUtils.buildUserConfigURI(realPath); |
|
FRLogger.getLogger().config(uri); |
|
// 日志配置更新的监听在FRLogger里面,fbp去掉了但是设计器本地还是需要这个监听的,初始化的时候监听一下 |
|
listenConfig(); |
|
} |
|
|
|
private void listenConfig() { |
|
ValidateConfigManger.getInstance().registerListener(new ConfigChangeListener() { |
|
|
|
@Override |
|
public boolean accept(Class<? extends Configuration> configClass) { |
|
return configClass.equals(Log4jConfig.class); |
|
} |
|
|
|
@Override |
|
public void change() { |
|
// The root logger is the topmost logger with a name of "" (the empty string). |
|
Configurator.setAllLevels("", Log4jConfig.getInstance().getRootLevel()); |
|
} |
|
}); |
|
|
|
} |
|
|
|
private void stopLogger() { |
|
FRLogger.getLogger().stop(); |
|
} |
|
|
|
/** |
|
* ----------- file-server -------- |
|
*/ |
|
private void startFileServer() throws Exception { |
|
if (WorkContext.getCurrent().isLocal()) { |
|
// 设计器远程下不需要文件系统,走PublicRepo的接口,本地下走基础的磁盘读写 |
|
LocalFileRepository.getSingleton().setWorkRoot(ServiceContext.getWebInfPath()); |
|
ResourceRepository realRepo = RepositoryFactory.getRepo(); |
|
FSProperties fsProperties = Carina.properties(FSProperties.class); |
|
FileServer.init( |
|
new ResourceRepositoryWrapper(LocalFileRepository.getSingleton(), StringUtils.EMPTY), |
|
new ResourceRepositoryWrapper(realRepo, StringUtils.EMPTY), |
|
new ResourceRepositoryWrapper(realRepo, StringUtils.EMPTY), |
|
new ResourceRepositoryWrapper(realRepo.generateTenantsSharedRepo(fsProperties.getTenantsSharedNamespace()), StringUtils.EMPTY)); |
|
|
|
ResourceIOUtils.setUnderlying(FileServer.local()); |
|
ResourceIOUtils.setIsolationMode(false); |
|
|
|
ResourcePaths.register(ProjectConstants.ASSETS_NAME, true); |
|
ResourcePaths.register(ProjectConstants.SCHEDULE_NAME, false); |
|
} else { |
|
DesignFileRepository repository = new DesignFileRepository(); |
|
FSProperties fsProperties = Carina.properties(FSProperties.class); |
|
FileServer.init(repository, repository, repository, repository.generateTenantsSharedRepo(fsProperties.getTenantsSharedNamespace())); |
|
} |
|
} |
|
|
|
private void stopFileServer() { |
|
ResourceIOUtils.setUnderlying(FileServer.local()); |
|
ResourceIOUtils.setIsolationMode(true); |
|
} |
|
|
|
/** |
|
* -----------dao--------- |
|
*/ |
|
private void startDao() { |
|
if (WorkContext.getCurrent().isLocal()) { |
|
// 类似com.fr.config.activator.BaseDBActivator.start里的逻辑 |
|
DBPropertyProvider dbPropertyProvider = FineMicroServicesDBProperties.getInstance().from(Carina.getApplicationContext().getCarinaApplicationProperties()); |
|
DBContextProvider dbContextProvider = new DBContextStarter(dbPropertyProvider).start(); |
|
|
|
|
|
ServiceContext.singleton(DBPropertyShell.class).set(dbPropertyProvider); |
|
ServiceContext.singleton(DBContextShell.class).set(dbContextProvider); |
|
|
|
|
|
// 这里等另外的模块DBPropertyComponent启动,并且注入后这里的api实例才能安排 |
|
|
|
FineLoggerFactory.getLogger().info("[StateServiceCommon] dao service common started."); |
|
} |
|
} |
|
private void stopDao() { |
|
FineMicroServicesDBProperties.getInstance().clear(); |
|
} |
|
|
|
|
|
/** |
|
* ---------- confconfig ------- |
|
*/ |
|
|
|
private void startConfConfig() { |
|
if (EnvBackupHelper.getInstance().isSwtiching()) { |
|
// 如果是切换环境触发的start,说明此时读的是新环境的配置 |
|
EnvBackupHelper.getInstance().do4Switch4Config(); |
|
} |
|
BaseDBEnv.setDBContext((DBContext) Carina.getApplicationContext().singleton(DBContextShell.class).get()); |
|
if (!WorkContext.getCurrent().isLocal()) { |
|
TransactorFactory.setTransactor(new RemoteTransactor()); |
|
//远程 |
|
DaoContext.setXmlEntityDao(new RemoteXmlEntityDao()); |
|
DaoContext.setClassHelperDao(new RemoteClassHelperDao()); |
|
DaoContext.setEntityDao(new RemoteEntityDao()); |
|
} else { |
|
//本地 |
|
TransactorFactory.setTransactor(new HibernateTransactor()); |
|
DaoContext.setClassHelperDao(new BatchSubmitClassHelperDao(new HibernateClassHelperDao())); |
|
DaoContext.setEntityDao(new BatchSubmitEntityDao(new HibernateEntityDao())); |
|
DaoContext.setXmlEntityDao(new BatchSubmitXmlEntityDao(new HibernateXmlEnityDao())); |
|
} |
|
ConfConfigProviderImpl confConfigProvider = new ConfConfigProviderImpl(); |
|
ConfigProviderFactory.getInstance().registerProvider(ConfigRealm.SERVICE, confConfigProvider); |
|
Configurations.setHelper(new FineConfigurationHelper()); |
|
EventDispatcher.fire(ConfigEvent.READY); |
|
// 固化一些配置 |
|
FinalPreferenceConfig.solidify(); |
|
InsecurityElementFactory.setConfigInsecurityElementProvider(ConfigInsecurityElementProviderImpl.INSTANCE); |
|
} |
|
|
|
|
|
private void stopConfConfig() { |
|
DaoContext.setClassHelperDao(null); |
|
DaoContext.setEntityDao(null); |
|
DaoContext.setXmlEntityDao(null); |
|
Configurations.setHelper(null); |
|
} |
|
|
|
/** |
|
* --------- core-supplemental -------- |
|
*/ |
|
|
|
|
|
private void startCorePrepare() { |
|
if (WorkContext.getCurrent().isLocal()) { |
|
EncryptionInitialization.getInstance().init(); |
|
EncryptionScaffold.setSecuritySeedProvider(new SecuritySeedProvider() { |
|
@Override |
|
public byte[] getSeed() { |
|
return LoadSeedSecurityKey.getInstance().loadSeedFile(); |
|
} |
|
|
|
@Override |
|
public void resetSeed() { |
|
LoadSeedSecurityKey.getInstance().reset(); |
|
} |
|
}); |
|
LoadSeedSecurityKey.getInstance().init(); |
|
} else { |
|
// 远程也先写死加解密,放在内存中就好,fbp那边暂时没有提供扩展,两边都是写死的,等他们提供扩展后设计器再适配 |
|
SystemEncryptionManager.getInstance().restore(); |
|
} |
|
} |
|
|
|
private void stopCorePrepare() { |
|
EncryptionScaffold.setSecuritySeedProvider(new SecuritySeedProvider() {}); |
|
LoadSeedSecurityKey.getInstance().reset(); |
|
} |
|
|
|
|
|
|
|
/** |
|
* --------- EnvPrepare --------- |
|
*/ |
|
|
|
private void stopEnvPrepare() { |
|
EnvDetectorCenter.getInstance().destroy(); |
|
} |
|
|
|
private void startEnvPrepare() { |
|
/// 环境检测、资源升级都暂不支持 |
|
//EnvDetectorCenter.getInstance().init(); |
|
if (WorkContext.getCurrent().isLocal()) { |
|
// 如果是切回本地,要初始化成本地仓库 |
|
// 如果是切回远程,会在用户创建的时候就同步初始化远程仓库 |
|
RepositoryManager.getInstance().initLocalRepository(); |
|
} |
|
} |
|
}
|
|
|