如何从Spring获取实例化bean列表?

时间:2013-02-12 09:26:09

标签: spring junit state

我的Spring上下文中有几个bean有状态,所以我想在单元测试之前/之后重置该状态。

我的想法是向一个辅助类添加一个方法,该方法只遍历Spring上下文中的所有bean,检查用@Before@After注释的方法并调用它们。

如何从ApplicationContext获取实例化 bean列表?

注意:简单地遍历所有定义的bean的解决方案是无用的,因为我有许多懒惰的bean,其中一些不能被实例化,因为对于某些测试会失败(即我有一个需要java.sql.DataSource的bean但是测试工作是因为他们不需要那个bean。)

6 个答案:

答案 0 :(得分:21)

例如:

 public static List<Object> getInstantiatedSigletons(ApplicationContext ctx) {
            List<Object> singletons = new ArrayList<Object>();

            String[] all = ctx.getBeanDefinitionNames();

            ConfigurableListableBeanFactory clbf = ((AbstractApplicationContext) ctx).getBeanFactory();
            for (String name : all) {
                Object s = clbf.getSingleton(name);
                if (s != null)
                    singletons.add(s);
            }

            return singletons;

    }

答案 1 :(得分:3)

我不确定这是否会对您有所帮助。

您需要创建自己的注释,例如。 MyAnnot。 并将该注释放在您想要获得的类上。 然后使用以下代码,您可能会获得实例化的bean。

ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
scanner.addIncludeFilter(new AnnotationTypeFilter(MyAnnot.class));
for (BeanDefinition beanDefinition : scanner.findCandidateComponents("com.xxx.yyy")){
    System.out.println(beanDefinition.getBeanClassName());
}

通过这种方式,您可以获得具有自定义注释的所有bean。

答案 2 :(得分:3)

我必须稍微改进一下

@Resource
AbstractApplicationContext context;

@After
public void cleanup() {
    resetAllMocks();
}

private void resetAllMocks() {
    ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
    for (String name : context.getBeanDefinitionNames()) {
        Object bean = beanFactory.getSingleton(name);
        if (Mockito.mockingDetails(bean).isMock()) {
            Mockito.reset(bean);
        }
    }
}

答案 3 :(得分:1)

applicationContext.getBeanDefinitionNames()不会显示在没有 BeanDefinition实例的情况下注册的Bean。

package io.velu.core;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan
public class Core {

public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Core.class);
    String[] singletonNames = context.getDefaultListableBeanFactory().getSingletonNames();
    for (String singleton : singletonNames) {
        System.out.println(singleton);
    }       
}

}


控制台输出

environment
systemProperties
systemEnvironment
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
messageSource
applicationEventMulticaster
lifecycleProcessor

如您在输出中看到的,将使用 context.getBeanDefinitionNames()方法显示环境,systemProperties,systemEnvironment Bean。

Spring Boot

对于Spring Boot Web应用程序,可以使用以下端点列出所有bean。

@RestController
@RequestMapping("/list")
class ExportController {

@Autowired
private ApplicationContext applicationContext;

@GetMapping("/beans")
@ResponseStatus(value = HttpStatus.OK)
String[] registeredBeans() {
    return printBeans();
}

private String[] printBeans() {
    AutowireCapableBeanFactory autowireCapableBeanFactory = applicationContext.getAutowireCapableBeanFactory();
    if (autowireCapableBeanFactory instanceof SingletonBeanRegistry) {
        String[] singletonNames = ((SingletonBeanRegistry) autowireCapableBeanFactory).getSingletonNames();
        for (String singleton : singletonNames) {
            System.out.println(singleton);
        }
        return singletonNames;
    }
    return null;
}

}


  

[      “ autoConfigurationReport”,      “ springApplicationArguments”,      “ springBootBanner”,      “ springBootLoggingSystem”,      “环境”,      “系统属性”,      “ systemEnvironment”,      “ org.springframework.context.annotation.internalConfigurationAnnotationProcessor”,      “ org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory”,      “ org.springframework.boot.autoconfigure.condition.BeanTypeRegistry”,      “ org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry”,      “ propertySourcesPlaceholderConfigurer”,      “ org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.store”,      “ preserveErrorControllerTargetClassPostProcessor”,      “ org.springframework.context.annotation.internalAutowiredAnnotationProcessor”,      “ org.springframework.context.annotation.internalRequiredAnnotationProcessor”,      “ org.springframework.context.annotation.internalCommonAnnotationProcessor”,      “ org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor”,      “ org.springframework.scheduling.annotation.ProxyAsyncConfiguration”,      “ org.springframework.context.annotation.internalAsyncAnnotationProcessor”,      “ methodValidationPostProcessor”,      “ embeddedServletContainerCustomizerBeanPostProcessor”,      “ errorPageRegistrarBeanPostProcessor”,      “ messageSource”,      “ applicationEventMulticaster”,      “ org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration $ EmbeddedTomcat”,      “ tomcatEmbeddedServletContainerFactory”,      “ org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration $ TomcatWebSocketConfiguration”,      “ websocketContainerCustomizer”,      “ spring.http.encoding-org.springframework.boot.autoconfigure.web.HttpEncodingProperties”,      “ org.springframework.boot.autoconfigure.web.HttpEncodingAutoConfiguration”,      “ localeCharsetMappingsCustomizer”,      “ org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration”,      “ serverProperties”,      “ duplicateServerPropertiesDetector”,      “ spring.resources-org.springframework.boot.autoconfigure.web.ResourceProperties”,      “ org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration $ DefaultErrorViewResolverConfiguration”,      “ conventionErrorViewResolver”,      “ org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration”,      “ errorPageCustomizer”,      “ servletContext”,      “ contextParameters”,      “ contextAttributes”,      “ spring.mvc-org.springframework.boot.autoconfigure.web.WebMvcProperties”,      “ spring.http.multipart-org.springframework.boot.autoconfigure.web.MultipartProperties”,      “ org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration”,      “ multipartConfigElement”,      “ org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration $ DispatcherServletRegistrationConfiguration”,      “ org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration $ DispatcherServletConfiguration”,      “ dispatcherServlet”,      “ dispatcherServletRegistration”,      “ requestContextFilter”,      “ org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration”,      “ hiddenHttpMethodFilter”,      “ httpPutFormContentFilter”,      “ characterEncodingFilter”,      “ org.springframework.context.event.internalEventListenerProcessor”,      “ org.springframework.context.event.internalEventListenerFactory”,      “ reportGeneratorApplication”,      “ exportController”,      “ exportService”,      “ org.springframework.boot.autoconfigure.AutoConfigurationPackages”,      “ org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration”,      “ org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration $ Jackson2ObjectMapperBuilderCustomizerConfiguration”,      “ spring.jackson-org.springframework.boot.autoconfigure.jackson.JacksonProperties”,      “ standardJacksonObjectMapperBuilderCustomizer”,      “ org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration $ JacksonObjectMapperBuilderConfiguration”,      “ org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration”,      “ jsonComponentModule”,      “ jacksonObjectMapperBuilder”,      “ org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration $ JacksonObjectMapperConfiguration”,      “ jacksonObjectMapper”,      “ org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration”,      “ org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration”,      “ org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration”,      “ org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration”,      “ defaultValidator”,      “ org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration $ WhitelabelErrorViewConfiguration”,      “错误”,      “ beanNameViewResolver”,      “ errorAttributes”,      “ basicErrorController”,      “ org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration $ EnableWebMvcConfiguration”,      “ org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration $ WebMvcAutoConfigurationAdapter”,      “ mvcContentNegotiationManager”,      “ org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration $ StringHttpMessageConverterConfiguration”,      “ stringHttpMessageConverter”,      “ org.springframework.boot.autoconfigure.web.JacksonHttpMessageConvertersConfiguration $ MappingJackson2HttpMessageConverterConfiguration”,      “ mappingJackson2HttpMessageConverter”,      “ org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration”,      “ messageConverters”,      “ mvcConversionService”,      “ mvcValidator”,      “ requestMappingHandlerAdapter”,      “ mvcResourceUrlProvider”,      “ requestMappingHandlerMapping”,      “ mvcPathMatcher”,      “ mvcUrlPathHelper”,      “ viewControllerHandlerMapping”,      “ beanNameHandlerMapping”,      “ resourceHandlerMapping”,      “ defaultServletHandlerMapping”,      “ mvcUriComponentsContributor”,      “ httpRequestHandlerAdapter”,      “ simpleControllerHandlerAdapter”,      “ handlerExceptionResolver”,      “ mvcViewResolver”,      “ org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration $ WebMvcAutoConfigurationAdapter $ FaviconConfiguration”,      “ faviconRequestHandler”,      “ faviconHandlerMapping”,      “ defaultViewResolver”,      “ viewResolver”,      “ welcomePageHandlerMapping”,      “ org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration”,      “ objectNamingStrategy”,      “ mbeanServer”,      “ mbeanExporter”,      “ org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration”,      “ springApplicationAdminRegistrar”,      “ org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration”,      “ org.springframework.boot.autoconfigure.web.JacksonHttpMessageConvertersConfiguration”,      “ spring.info-org.springframework.boot.autoconfigure.info.ProjectInfoProperties”,      “ org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration”,      “ multipartResolver”,      “ org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration $ RestTemplateConfiguration”,      “ restTemplateBuilder”,      “ org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration”,      “ spring.devtools-org.springframework.boot.devtools.autoconfigure.DevToolsProperties”,      “ org.springframework.boot.devtools.autoconfigure.LocalDevToolsAutoConfiguration $ RestartConfiguration”,      “ fileSystemWatcherFactory”,      “ classPathRestartStrategy”,      “ classPathFileSystemWatcher”,      “ hateoasObjenesisCacheDisabler”,      “ org.springframework.boot.devtools.autoconfigure.LocalDevToolsAutoConfiguration $ LiveReloadConfiguration $ LiveReloadServerConfiguration”,      “ org.springframework.boot.devtools.autoconfigure.LocalDevToolsAutoConfiguration $ LiveReloadConfiguration”,      “ OptionalLiveReloadServer”,      “ org.springframework.boot.devtools.autoconfigure.LocalDevToolsAutoConfiguration”,      “ lifecycleProcessor”   ]

答案 4 :(得分:0)

我创建了gist ApplicationContextAwareTestBase

这个助手类做了两件事:

  1. 它将所有内部字段设置为null。这允许Java释放不再使用的内存。尽管如此,它对Spring的用处不大(Spring上下文仍保留对所有bean的引用)。

  2. 它尝试查找上下文中所有bean中使用@After注释的所有方法,并在测试后调用它们。

  3. 这样,您可以轻松地重置单身/模拟的状态,而不必破坏/刷新上下文。

    示例:您有一个模拟DAO:

    public void MockDao implements IDao {
    
        private Map<Long, Foo> database = Maps.newHashMap();
    
        @Override
        public Foo byId( Long id ) { return database.get( id ) );
    
        @Override
        public void save( Foo foo ) { database.put( foo.getId(), foo ); }
    
        @After
        public void reset() { database.clear(); }
    }
    

    注释将确保在每次单元测试后调用reset()以清理内部状态。

答案 5 :(得分:0)

使用之前的答案,我已将此更新为使用Java 8 Streams API:

@Inject
private ApplicationContext applicationContext;

@Before
public void resetMocks() {
    ConfigurableListableBeanFactory beanFactory = ((AbstractApplicationContext) applicationContext).getBeanFactory();
    Stream.of(applicationContext.getBeanDefinitionNames())
            .map(n -> beanFactory.getSingleton(n))
            // My ConfigurableListableBeanFactory isn't compiled for 1.8 so can't use method reference. If yours is, you can say
            // .map(ConfigurableListableBeanFactory::getSingleton)
            .filter(b -> Mockito.mockingDetails(b).isMock())
            .forEach(Mockito::reset);
}