Principles:
- Read-only queries first(contains/beanNames/type/environment), avoid directly
getBean()triggering Bean initialization and causing side effects. - Strictly limit:
vmtool -lthe number of instances; avoid unconditionally outputting the completegetBeanDefinitionNames()。
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.
- The application's ClassLoader usually contains
LaunchedURLClassLoader - 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=truebutcontainsLocalBean=false: The Bean may come fromparent Context。containsBean=falseand 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@classreportsClassNotFound, it is usuallythe wrong classloader: first useclassloader(stats/instances/tree) to find the application'sclassLoaderHash, then onvmtool/ognladd--classLoader <hash>and execute again. You can also find the Class Name ofclassloader, then use the--classLoaderClassparameter.
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")'