精简加速metasfresh的Swing客户端启动
metasfresh自带的Swing客户端,启动速度非常熳,本文介绍几种优化方案。
ComponentScan优化
可以通过优化SwingUIApplication以实现加速。将如下内容替换到backend/metasfresh-dist/swingui/src/main/java/de/metas/SwingUIApplication.java文件即可:
package de.metas;
import de.metas.event.EventBusConfig;
import de.metas.util.Services;
import org.adempiere.model.tree.IPOTreeSupportFactory;
import org.adempiere.model.tree.spi.impl.MenuTreeSupport;
import org.adempiere.util.lang.IAutoCloseable;
import org.compiere.Adempiere;
import org.compiere.Adempiere.RunMode;
import org.compiere.apps.AEnv;
import org.compiere.apps.ALogin;
import org.compiere.apps.AMenu;
import org.compiere.model.I_AD_Menu;
import org.compiere.model.ModelValidationEngine;
import org.compiere.util.Env;
import org.compiere.util.Splash;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.annotation.Import;
import org.springframework.context.event.EventListener;
@Import({
de.metas.security.permissions.record_access.RecordAccessConfigService.class,
de.metas.security.permissions.record_access.RecordAccessRepository.class,
de.metas.security.permissions.record_access.RecordAccessService.class,
de.metas.user.UserGroupRepository.class,
de.metas.document.references.zoom_into.NullCustomizedWindowInfoMapRepository.class,
de.metas.monitoring.adapter.NoopPerformanceMonitoringService.class,
de.metas.StartupListener.class,
})
public class SwingUIApplication
{
public static void main(final String[] args)
{
System.setProperty("org.adempiere.client.lang", "en_US");
System.setProperty("spring.main.banner-mode", "off");
Adempiere.instance.startup(RunMode.SWING_CLIENT);
new SpringApplicationBuilder(SwingUIApplication.class)
.headless(false)
.web(WebApplicationType.NONE)
.beanNameGenerator(new MetasfreshBeanNameGenerator())
.run(args);
}
@EventListener(ApplicationReadyEvent.class)
public void showMainWindow()
{
EventBusConfig.disableDistributedEvents();
try (IAutoCloseable ac = ModelValidationEngine.postponeInit())
{
final ALogin login = new ALogin(Splash.getSplash(), Env.getCtx());
if (!login.initLogin()) {
AEnv.showCenterScreen(login);
}
}
Services.get(IPOTreeSupportFactory.class).register(I_AD_Menu.Table_Name, MenuTreeSupport.class);
new AMenu();
}
}
autoconfigure优化
以上版本虽然启动速度很快,但是因为很多服务没有加载,所有部分功能不可用,如果要提高可用性,可以使用下面的版本,注意,这一版本依赖RabbitMQ服务:
package de.metas;
import org.compiere.Adempiere;
import org.compiere.Adempiere.RunMode;
import org.compiere.apps.AEnv;
import org.compiere.apps.ALogin;
import org.compiere.apps.AMenu;
import org.compiere.util.Env;
import org.compiere.util.Splash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import org.springframework.context.event.EventListener;
@ComponentScan(basePackages = {"de.metas", "org.adempiere"})
@Import({
org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration.class,
org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration.class,
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration.class,
})
public class SwingUIApplication
{
@Autowired
private ApplicationContext applicationContext;
public static void main(final String[] args)
{
System.setProperty("org.adempiere.client.lang", "en_US");
System.setProperty("spring.main.banner-mode", "off");
Adempiere.instance.startup(RunMode.SWING_CLIENT);
new SpringApplicationBuilder(SwingUIApplication.class)
.headless(false)
.web(WebApplicationType.NONE)
.beanNameGenerator(new MetasfreshBeanNameGenerator())
.run(args);
}
@Bean(Adempiere.BEAN_NAME)
public Adempiere adempiere()
{
return Env.getSingleAdempiereInstance(applicationContext);
}
@EventListener(ApplicationReadyEvent.class)
public void showMainWindow()
{
final ALogin login = new ALogin(Splash.getSplash(), Env.getCtx());
if (!login.initLogin()) {
AEnv.showCenterScreen(login);
}
new AMenu();
}
}
Jar包优化
可以通过以下脚本生成精简版的jar包:
#!/usr/bin/env python3
import os
import zipfile
text = open('classpath.txt').read()
paths = sorted(text.strip().split(";"))
selected_paths = []
for path in paths:
relative_path = path.replace("\\", "/").replace("C:/Users/name/", "")
if path.endswith(".jar"):
if all(pattern not in relative_path for pattern in ["ant",
"apiguardian",
"assertj",
"barcode4j",
"castor",
"checker-qual",
"cron4j",
"ecj",
"elasticsearch",
"httpcomponents",
"google-maps-services",
"groovy",
"itext",
"jmx",
"jsonassert",
"junit",
"log4j",
"lucene",
"maven",
"mockito",
"netty",
"opentest4j",
"pdf-renderer",
"reactor",
"spring-boot-starter",
"spring-boot-test",
"springfox",
"spring-jdbc",
"spring-oxm",
"spring-test",
"spring-webflux",
"spring-webmvc",
"swagger",
"tomcat",
"xmlgraphics",
"xmlunit",
"zxing"]):
print(relative_path)
selected_paths.append(relative_path)
elif all(pattern not in relative_path for pattern in ["de-metas-common-externalsystem",
"de-metas-common-externalreference",
"de-metas-common-rest_api",
"de.metas.externalreference",
"de.metas.externalsystem",
"de.metas.payment",
"de.metas.serviceprovider",
"de.metas.util.web",
"de.metas.vertical.healthcare.alberta",
"elasticsearch",
"msv3",
"test"]):
print(relative_path)
selected_paths.append(relative_path.rstrip("/") + "/")
classpath = "Class-Path: " + " ".join(selected_paths)
with zipfile.ZipFile("metasfresh.jar", "w", zipfile.ZIP_DEFLATED) as f:
f.writestr("META-INF/MANIFEST.MF",
"Manifest-Version: 1.0\nMain-Class: de.metas.SwingUIApplication\n"
+ "\n ".join([classpath[i : i + 70] for i in range(0, len(classpath), 70)]) + "\n")
更新
2021-08-15
- 添加jar包精简方案;