dram.me

精简加速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

    1. 添加jar包精简方案;