SuperAPI AI Directory

arthas-springcontext-issues-resolve

Coding & development

View repository

Updated 10-16 07:42

About this skill

Spring Context / Bean Troubleshooting Guide

Principles:

  • Read-only queries first(contains/beanNames/type/environment), avoid directly getBean() triggering Bean initialization and causing side effects.
  • Strictly limit:vmtool -l the number of instances; avoid unconditionally outputting the complete getBeanDefinitionNames()。

1) Obtain and pick the correct ApplicationContext

First try to obtain the common Spring Boot Context (usually the AbstractApplicationContext subclass):

vmtool --action getInstances --className org.springframework.context.support.AbstractApplicationContext -l 5

If you cannot get a result, you can try to obtain: org.springframework.context.ApplicationContext

If multiple objects are obtained, you can determine by the Class<?> name from the object's classloader.

  1. The application's ClassLoader usually contains LaunchedURLClassLoader
  2. The application's ClassLoader is never com.taobao.pandora.service.loader.ModuleClassLoader

2) Obtain configuration item values and sources

Only look at the value (example:server.port):

vmtool --action getInstances --className org.springframework.context.support.AbstractApplicationContext -l 1 --express 'instances[0].getEnvironment().getProperty("server.port")'

Obtain the "source"

vmtool --action getInstances --className org.springframework.context.support.AbstractApplicationContext -l 1 --express '#env=instances[0].getEnvironment(), #ps=#env.getPropertySources().get("configurationProperties"), #ps.findConfigurationProperty("server.port")'

If the application has integrated spring-boot-starter-actuator, you can try

vmtool --action getInstances \
--className org.springframework.boot.actuate.env.EnvironmentEndpoint \
--express 'instances[0].environmentEntry("server.port")'

3) Verify by Bean Name whether it exists (without triggering initialization)

Assume the beanName you want to check is fooService:

vmtool --action getInstances --className org.springframework.context.support.AbstractApplicationContext -l 1 --express 'instances[0].containsBean("fooService")'
vmtool --action getInstances --className org.springframework.context.support.AbstractApplicationContext -l 1 --express 'instances[0].containsLocalBean("fooService")'
vmtool --action getInstances --className org.springframework.context.support.AbstractApplicationContext -l 1 --express 'instances[0].containsBeanDefinition("fooService")'
vmtool --action getInstances --className org.springframework.context.support.AbstractApplicationContext -l 1 --express 'instances[0].getAliases("fooService")'

Interpretation:

  • containsBean=true but containsLocalBean=false: The Bean may come fromparent Context。
  • containsBean=false and you are sure it should exist: first checkwhether the wrong Context was selected、@Profile/@Conditional, and whether the configuration item/environment variable is in effect.

4) "Search" for Beans in the Spring Context (filter by keyword, limit output)

When you only have a keyword (such as order / datasource) and do not know the exact beanName:

vmtool --action getInstances --className org.springframework.context.support.AbstractApplicationContext -l 1 --express '#ctx=instances[0], #names=@java.util.Arrays@asList(#ctx.getBeanDefinitionNames()), #m=#names.{? #this.toLowerCase().contains("order")}, #m.subList(0, @java.lang.Math@min(#m.size(), 50))'

Notes:

  • First narrow the scope with the keyword, then output at most 50 candidates; after obtaining candidate beanNames, return to step 3 to verify them one by one.

5) Find Beans by type (best for locating "which implementation was injected")

When you know the fully qualified name of the target type (interface/superclass) (example:com.foo.OrderService):

vmtool --action getInstances --className org.springframework.context.support.AbstractApplicationContext -l 1 --express 'instances[0].getBeanNamesForType(@com.foo.OrderService@class)'

If multiple candidates are returned (NoUniqueBeanDefinitionException common root cause), just look at the candidate names:

vmtool --action getInstances --className org.springframework.context.support.AbstractApplicationContext -l 1 --express 'instances[0].getBeansOfType(@com.foo.OrderService@class).keySet()'

Tips:

  • If you suspect that proxying causes a type mismatch (JDK Proxy / CGLIB), you should first query byinterface type, then decide whether you need to obtain an instance for further confirmation.
  • If @com.foo.OrderService@class reports ClassNotFound, it is usuallythe wrong classloader: first use classloader(stats/instances/tree) to find the application's classLoaderHash, then on vmtool/ognl add --classLoader <hash> and execute again. You can also find the Class Name of classloader, then use the --classLoaderClass parameter.

6) View BeanDefinition (source/factory method/scope)

When you need to confirm how the Bean was registered (@Bean factory method? XML? automatic scanning?), you can try to get BeanFactory to see BeanDefinition(precondition: the Context is AbstractApplicationContext)。

vmtool --action getInstances --className org.springframework.context.support.AbstractApplicationContext -l 1 --express '#ctx=instances[0], #bf=#ctx.getBeanFactory(), #bd=#bf.getBeanDefinition("fooService")'