Pre-processing Spring Beans of Prototype Scope
Sometimes you have a type of bean in the Spring framework which you want to create by every asking for it - in the scope prototype.
Pre-processing of those prototypes only one and in the beginning could be tricky.
Let's consider an annotation which tell you someting about the setting of the beans. For example which alternative names is your GUI box connected to. You want to create a proper bean based on its alternative name of course without featching all the beans every time and looking for the right one (of course you can do it by lazy caching, but that's still not the best solution). Or what if you want to get a list of all the alternative names of course withou the need to create the beans first?
This short article will tell you how to do it.
Consider the following annotations:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Component @Scope(value = SCOPE_PROTOTYPE) public @interface Box { }
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Component @Scope(value = SCOPE_PROTOTYPE) public @interface AlternativeNames { AlternativeName[] value(); }
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Repeatable(AlternativeNames.class) @Documented public @interface AlternativeName { String value(); }
Then you have defined the base annotation @Box
which tell the Spring framework that this class is a bean, @AlternativeNames
which allows you to put the @AlternativeName
annotation more times (Repeating Annotations).
Based on the definitions you can create a class like this:
@Box @AlternativeName("my-box") @AlternativeName("box-of-mine") public class MyBox { // ... some code goes here }
Now it's time for the pre-processor:
@Component public class BoxContextListener implements ApplicationListener<ContextRefreshedEvent> { private final ConfigurableListableBeanFactory factory; @Autowired public BoxContextListener(ConfigurableListableBeanFactory factory) { this.factory = factory; } @Override public void onApplicationEvent(ContextRefreshedEvent event) { String[] beanDefinitionNames = event.getApplicationContext().getBeanDefinitionNames(); for (String beanDefinitionName : beanDefinitionNames) { try { BeanDefinition beanDefinition = factory.getBeanDefinition(beanDefinitionName); String originalClassName = beanDefinition.getBeanClassName(); if (originalClassName != null && !originalClassName.isEmpty()) { try { final Class<?> originalClass = Class.forName(originalClassName); if (originalClass.isAnnotationPresent(Box.class)) { if (originalClass.isAnnotationPresent(AlternativeNames.class) || originalClass.isAnnotationPresent(AlternativeName.class)) { AlternativeName[] mappings = originalClass.getAnnotationsByType(AlternativeName.class); for (AlternativeName alternativeMapping : mappings) { String alternativeName = alternativeMapping.value(); // do someting with the alternative name ... } } } } catch (ClassNotFoundException e) { // ... } } } catch (BeansException e) { // ... } } } }
That's the way how to get values from the annotation of the Spring prototype beans in the pre-processing.
I hope it helped!