How to get a list of beans instances from Spring?

I have several beans in my Spring context that have state, so I would like to reset that state before / after unit tests.

My idea was to add a method to a helper class that just goes through all the beans in the Spring context, validates methods that are annotated with @Before or @After and call them.

How to get a list beans from ApplicationContext ?

Note. Solutions that just iterate over all defined beans are useless because I have a lot of lazy beans and some of them should not be created because it might be unsuccessful for some tests (i.e. I need beans a java.sql.DataSource , but tests work because they do not need this bean).

+18
spring junit state
Feb 12 '13 at 9:26
source share
5 answers

For example:

  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; } 
+21
Feb 12
source share

I'm not sure if this will help you or not.

You need to create your own annotation, for example. MyAnnot And post this annotation on the class you want to get. And then, using the following code, you can get a bean instance.

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

That way you can get all beans your custom annotations.

+3
Feb 12 '13 at 12:24
source share

I had to improve it a bit

 @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
Oct 22 '15 at 16:02
source share

I created a gist ApplicationContextAwareTestBase .

This helper class has two functions:

  • It sets all internal fields to null. This allows Java to free memory that is no longer in use. This is less useful with Spring (the Spring context still maintains references to all beans).

  • He tries to find all methods annotated with @After in all beans in context and calling them after the test.

This way you can easily reset the state of your singleton / mocks without having to destroy / update the context.

Example: you have a DAO layout:

 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(); } } 

In the annotation, make sure that reset() is called after each unit test to clear the internal state.

0
Feb 12 '13 at 15:16
source share

Using the previous answers, I updated this to use the 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); } 
0
Sep 25 '16 at 19:42
source share



All Articles