如何从Spring获取实例化bean的列表?
我的Spring上下文中有几个bean具有状态,所以我想在单元测试之前/之后重置该状态 我的想法是向助手类中添加一个方法,该类只需遍历Spring上下文中的所有bean,检查在如何从Spring获取实例化bean的列表?,spring,junit,state,Spring,Junit,State,我的Spring上下文中有几个bean具有状态,所以我想在单元测试之前/之后重置该状态 我的想法是向助手类中添加一个方法,该类只需遍历Spring上下文中的所有bean,检查在@之前或@之后注释的方法并调用它们 如何从ApplicationContext获取实例化的bean列表 注意:简单地迭代所有已定义bean的解决方案是无用的,因为我有许多惰性bean,其中一些不能实例化,因为这会导致某些测试失败(例如,我有一个bean需要java.sql.DataSource,但测试可以工作,因为它们不需
@之前或@之后注释的方法并调用它们
如何从ApplicationContext
获取实例化的bean列表
注意:简单地迭代所有已定义bean的解决方案是无用的,因为我有许多惰性bean,其中一些不能实例化,因为这会导致某些测试失败(例如,我有一个bean需要java.sql.DataSource
,但测试可以工作,因为它们不需要该bean).我不确定这对你是否有帮助
您需要创建自己的注释,例如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。例如:
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;
}
公共静态列表GetInstancedSigleton(ApplicationContext ctx){
List singleton=new ArrayList();
字符串[]all=ctx.getBeanDefinitionNames();
ConfigurableListableBeanFactory clbf=((AbstractApplicationContext)ctx).getBeanFactory();
for(字符串名称:all){
对象s=clbf.getSingleton(名称);
如果(s!=null)
单身人士;
}
返回单身人士;
}
我已经创建了一个
这个helper类做两件事:
它将所有内部字段设置为空。这允许Java释放不再使用的内存。但是,它对Spring不太有用(Spring上下文仍然保留对所有bean的引用)
它试图在上下文中的所有bean中找到用@After
注释的所有方法,并在测试后调用它们
这样,您就可以轻松地重置单例/模拟的状态,而无需销毁/刷新上下文
示例:您有一个模拟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(); }
}
public void MockDao实现IDao{
私有地图数据库=Maps.newHashMap();
@凌驾
publicfoobyid(长id){returndatabase.get(id));
@凌驾
public void save(Foo-Foo){database.put(Foo.getId(),Foo);}
@之后
public void reset(){database.clear();}
}
注释将确保在每次单元测试后调用reset()
,以清除内部状态。我不得不对其进行一些改进
@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);
}
}
}
使用前面的答案,我已将其更新为使用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);
}
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);
}
}
}
控制台输出
正如您在输出中看到的,环境、systemProperties、systemEnvironmentbean将使用上下文.getBeanDefinitionNames()方法显示
弹簧靴
对于SpringBootWeb应用程序,可以使用以下端点列出所有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;
}
}
[
“自动配置报告”,
“springApplicationArguments”,
“斯普林布特班纳”,
“springBootLoggingSystem”,
“环境”,
“系统属性”,
“系统环境”,
“org.springframework.context.annotation.internalConfigurationAnnotationProcessor”,
“org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory”,
“org.springframework.boot.autoconfigure.condition.beantypergistry”,
“org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry”,
“属性资源占位符配置器”,
“org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.store”,
“保留ErrorControllerTargetClassPostProcessor”,
“org.springframework.context.annotation.InternalAutowiredNotationProcessor”,
“org.springframework.context.annotation.internalRequiredAnnotationProcessor”,
“org.springframework.context.annotation.internalCommonAnnotationProcessor”,
“org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor”,
“org.springframework.scheduling.annotation.ProxySyncConfiguration”,
“org.springframework.context.annotation.internalAsyncAnnotationProcessor”,
“methodValidationPostProcessor”,
“embeddedServletContainerCustomizerBeanPostProcessor”,
“errorPageRegistrarBeanPostProcessor”,
“消息源”,
“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”,
“服务器属性”,
“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”,
“上下文参数”,
“contextAttributes”,
“spring.mvc org.springframework.boot.autoconfigure.web.WebMvcProperties”,
“spring.http.multipart org.springframework.boot.autoconfigure.w
@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;
}