Search code examples
springspring-bootspring-framework-beans

How to get the Bean package from ConfigurableApplicationContext


Using a interface like ConfigurableApplicationContext, it is possible to retrieve the list of Beans running in the Spring DI container, but I would like to know what Beans come from the User Space and what Beans comes from the Spring Boot / Spring Boot Starters.

@TestConfiguration
static class BeanInventoryConfiguration {

    @Autowired
    private ConfigurableApplicationContext applicationContext;

    record BeanInventory(List<String> beans) {}

    @Bean
    public BeanInventory getBeanInventory(ConfigurableApplicationContext applicationContext) {
        String[] allBeanNames = applicationContext.getBeanDefinitionNames();
        return new BeanInventory(Arrays.stream(allBeanNames).toList());
    }
}

Does exist a way to return the package where the Bean is located? If I know the package, I could filter in a easy way.

Reviewing the Javadoc from Spring, I didnt find a way: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/ConfigurableApplicationContext.html

Many thanks in advance

POC: https://github.com/jabrena/spring-boot-http-client-poc/blob/main/src/test/java/ms/info/ms/BeanInventoryTests.java


Solution

  • I found a solution for it:

    @TestConfiguration
    public class BeanInventory {
    
        @Autowired
        private ConfigurableApplicationContext applicationContext;
    
        public record BeanInfo(String name, String pkg) {}
        private final List<BeanInfo> beans = new ArrayList<>();
    
        @PostConstruct
        private void after() {
    
            final String[] beanNames = applicationContext.getBeanDefinitionNames();
            for (String beanName : beanNames) {
                final Object beanObject = applicationContext.getBean(beanName);
                Class<?> targetClass = AopUtils.getTargetClass(beanObject);
    
                if (AopUtils.isJdkDynamicProxy(beanObject)) {
                    Class<?>[] proxiedInterfaces = AopProxyUtils.proxiedUserInterfaces(beanObject);
                    Assert.isTrue(proxiedInterfaces.length == 1, "Only one proxied interface expected");
                    targetClass = proxiedInterfaces[0];
                }
    
                beans.add(new BeanInfo(beanName, targetClass.getPackageName()));
            }
        }
    
        public List<BeanInfo> getBeans() {
            return beans;
        }
    
    }
    

    Further information here: https://github.com/spring-projects/spring-framework/issues/29973#event-8527246281

    Note: Many thanks to Simon Basle