Optimizing Startup Time of an Old Dubbo Service Using JProfile and Configuration Tweaks
This article details how a legacy Dubbo service built on Spring 3.2.x with many integrated components suffered a ten‑minute startup, and how using JProfile to pinpoint costly reflection checks, disabling unnecessary Spring annotations, and fixing RabbitMQ connection issues reduced the deployment time to under two minutes.
An older Dubbo service from another team, built on Spring 3.2.x and integrating components such as RabbitMQ, Dubbo, Elasticsearch, Kafka, Zookeeper, Redis, and CAS, suffered from extremely slow local startup times—often close to ten minutes on a heavily provisioned machine.
Using JProfile for CPU profiling revealed a costly reflection check: the service repeatedly called ClassUtils.isPresent to see if org.springframework.core.annotation.AnnotatedElementUtils (introduced in Spring 4) existed. Because the service runs on Spring 3.2.x, this check was unnecessary and added significant overhead.
// through reflection determine if class exists
public static boolean isPresent(String className, ClassLoader classLoader) {
try {
forName(className, classLoader);
return true;
} catch (Throwable var3) {
return false;
}
}
/** The class name of AnnotatedElementUtils introduced since Spring Framework 4 */
public static final String ANNOTATED_ELEMENT_UTILS_CLASS_NAME = "org.springframework.core.annotation.AnnotatedElementUtils";
// check if AnnotatedElementUtils is present
ClassUtils.isPresent(ANNOTATED_ELEMENT_UTILS_CLASS_NAME, classLoader);To avoid this redundant check, the configuration was altered to disable the tryMergedAnnotation flag in the Nacos‑related bean post‑processors:
<bean id="annotationNacosInjectedBeanPostProcessor"
class="com.alibaba.nacos.spring.beans.factory.annotation.AnnotationNacosInjectedBeanPostProcessor">
<property name="tryMergedAnnotation" value="false"/>
</bean>
<bean id="nacosValueAnnotationBeanPostProcessor"
class="com.alibaba.nacos.spring.context.annotation.config.NacosValueAnnotationBeanPostProcessor">
<property name="tryMergedAnnotation" value="false"/>
</bean>After this change the deployment time dropped by roughly 40 %, but it was still far from acceptable, prompting further investigation.
Log analysis showed that the main thread was blocked waiting for a RabbitMQ listener to start. The listener failed to connect, producing a timeout exception and causing the thread to wait on a CountDownLatch :
[2022-09-28 17:15:56.913][ WARN][][SimpleAsyncTaskExecutor-1][o.s.a.r.l.SimpleMessageListenerContainer|1168]:Consumer raised exception, processing can restart if the connection factory supports it. Exception summary: org.springframework.amqp.AmqpConnectException: java.net.ConnectException: Connection timed out: connect private final CountDownLatch start = new CountDownLatch(1);
public FatalListenerStartupException getStartupException() throws TimeoutException, InterruptedException {
start.await(60000L, TimeUnit.MILLISECONDS);
return this.startupException;
}
public void run() {
SimpleMessageListenerContainer.this.redeclareElementsIfNecessary();
this.consumer.start();
this.start.countDown();
// ...
restart(this.consumer);
}The latch waited up to 60 seconds for the consumer to start, but because the RabbitMQ connection could not be established (the local environment used a private‑network address), the thread remained in a waiting state, further delaying startup.
Changing the RabbitMQ address to a reachable public endpoint resolved the connection timeout, and the final measured deployment time was about 95,078 ms (≈1.5 minutes), which is now within a reasonable range given the many integrated components.
Additional minor blocking points were identified in Zookeeper and database connections, but overall the service’s startup time became acceptable after the profiling, configuration tweaks, and network fixes.
The investigation demonstrates a practical approach: use profiling tools like JProfile to locate expensive operations, disable unnecessary framework features, and ensure external dependencies are reachable during local development.
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.