Debugging Spring MVC @Service Bean Injection Issues with JMap and JHat
The article explains how a Spring MVC service bean was duplicated across root and child WebApplicationContexts, causing a null‑injected instance that triggered a NullPointerException, and shows how JMap and JHat were used to locate the two beans and resolve the issue by adjusting component‑scan filters or removing the @Service annotation.
Spring MVC is widely used in Meituan-Dianping teams. Annotations such as @Override, @Deprecated, @Controller, @Service, @Autowired, and custom annotations are scattered throughout the codebase. While annotations simplify configuration, misuse can cause subtle bugs.
Event Cause
A new HTTP interface was wrapped and deployed after passing local unit tests. During testing a NullPointerException occurred. The stack trace showed a ClientProtocolException caused by a missing target host, which was traced back to the URL property not being injected when the class was annotated with @Service.
ERROR [qtp384587033-86] 2015-12-21 16:29:00.905 com.meituan.trip.mobile.hermes.common.utils.HttpClientUtils.doRequest(HttpClientUtils.java:359) HttpClientUtils.doRequest invoke get error, url:nullmt/api/test/v1/query?id=123456
org.apache.http.client.ClientProtocolException
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:186) ~[httpclient-4.3.5.jar:4.3.5]
Caused by: org.apache.http.ProtocolException: Target host is not specifiedProblem Localization
Keeping the @Service annotation and restarting the application revealed that the bean definition for queryPartnerImpl was being overridden.
INFO [main] 2015-12-21 16:28:47.078 org.springframework.beans.factory.support.DefaultListableBeanFactory.registerBeanDefinition Overriding bean definition for bean 'queryPartnerImpl': replacing [Generic bean: class [com.meituan.trip.mobile.hermes.sal.meilv.impl.QueryPartnerImpl]; scope=singleton; ...] with [Generic bean: class [com.meituan.trip.mobile.hermes.sal.meilv.impl.QueryPartnerImpl]; scope=; ...]Spring replaces a bean when the same name is defined twice in the same WebApplicationContext. The log indicated that the XML‑defined bean from sal/service-outer.xml replaced the annotated one, but the application still failed.
Investigation with JMap
Using JMap to count live instances of QueryPartnerImpl showed two objects, contradicting the expectation of a single singleton.
$ jmap -histo:live 20881 | grep QueryPartnerImpl
1354: 2 80 com.meituan.trip.mobile.hermes.sal.meilv.impl.QueryPartnerImplA heap dump was created for deeper analysis.
$ jmap -dump:format=b,file=/tmp/heap.bin 20881
Dumping heap to /private/tmp/dump.data ...
Heap dump file createdThe dump was examined with JHat (HTTP server on port 7000) and MAT to locate the two instances and their reference graphs.
$ jhat /tmp/heap.bin
...........................................................................
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.Instance details:
QueryPartnerImpl@0x6c41b6f80 (64 bytes)
clientId : trip_trade
clientSecret : 6ee952489a93b51b1ffcadd040ca562e
url : http://test.url.meituan.com/
...
QueryPartnerImpl@0x7aeafac20 (64 bytes)
clientId : <null>
clientSecret : <null>
url : <null>
...The first instance had all properties injected correctly; the second had null values, which caused the NPE.
Root Cause Analysis
Reference tracing showed that the faulty instance was held by DispatcherServlet 's child WebApplicationContext, while the correct one was held by the root WebApplicationContext created by ContextLoaderListener. The duplication originated from both the root and child contexts loading the same package with annotation scanning, while sal/service-out.xml also defined the bean via XML, leading to replacement.
Solutions
Remove the @Service annotation (not ideal if other annotations are needed).
Isolate scanning by configuring use-default-filters and using include-filter/exclude-filter to limit which annotations are picked up.
Adjust spring-servlet.xml and applicationContext.xml accordingly (example screenshot omitted).
Key take‑aways:
Annotations are powerful but must be used consistently; property injection should also be annotation‑driven.
When enabling component scanning, carefully define the scan scope and filters.
Unit tests may pass because they load only a single configuration, hiding duplicate‑bean issues.
Follow framework best‑practice guidelines to avoid mysterious runtime problems.
Further reading includes the Spring Web MVC documentation and the Meituan-Dianping technical blog.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Meituan Technology Team
Over 10,000 engineers powering China’s leading lifestyle services e‑commerce platform. Supporting hundreds of millions of consumers, millions of merchants across 2,000+ industries. This is the public channel for the tech teams behind Meituan, Dianping, Meituan Waimai, Meituan Select, and related services.
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.
