Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add custom beans to Spring context

Tags:

java

spring

I have some classes, with a custom annotation, that shouldn't be instantiated (abstract class, and it's just a subcomponents for a real beans). But on top of this classes, on runtime, on context initialization phase, I want to put extra beans into application context.

So, basically I need to scan classpath, process results, and introduce new beans into curent application context.

It seems that spring-mvc, spring-tasks and spring-integration are doing this (I tried to learn it from sources - no luck)

I found that I can create my own BeanFactoryPostProcessor, scan classpath and call registerSingleton for my custom bean. But I'm not sure that it's a good way for introducing new beans (seems that it's used only for postprocess of exising beans only). And I believe there are some Spring internal tools that I may reuse to simplify process.

What is a conventional way to introduce extra beans on Spring context initialization?

like image 903
Igor Artamonov Avatar asked Mar 30 '13 16:03

Igor Artamonov


People also ask

What are the two methods of putting a bean in a context?

3.2. Beans are defined to be deployed in one of two modes: singleton or non-singleton.

How do you make custom Spring beans?

Different Methods to Create a Spring BeanCreating Bean Inside an XML Configuration File (beans. xml) Using @Component Annotation. Using @Bean Annotation.

How do I import beans into Spring boot?

An alternative way to import the bean is to use the SpringApplicationBuilder's sources method. Since we have already imported the bean, the line is commented. @Autowired private TimeService timeService; Now that the bean is registered, we can inject it into the field.


2 Answers

There are at least two ways to include custom annotated classes as bean definitions:

  • Annotate the custom annotation with @Component
  • Add a include filter with type annotation to <context:component-scan/>

for example:

<context:component-scan base-package="org.example">
        <context:include-filter type="annotation" expression="org.example.Annotation"/>
</context:component-scan>

Then you can use a BeanPostProcessor to instantiate them, for example:

public class CustomAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter


         @Override
            public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
                if (beanClass.isAnnotationPresent(org.example.Annotation.class)) {
                    Object bean  = createBeanInstance();
                    ...
                    return bean:
                }
                return null;
            } 
    }

Or use a BeanFactoryPostProcessor to process the ScannedGenericBeanDefinitions.

See AnnotationConfigUtils.registerAnnotationConfigProcessors() for sample code of internal Spring annotation postprocessors.

like image 45
Jose Luis Martin Avatar answered Oct 05 '22 13:10

Jose Luis Martin


Your observation is actually correct, BeanFactoryPostProcessor is one of the two ways Spring provides a mechanism to modify the bean definition/instances before making them available to the application(the other is using BeanPostProcessors)

You can absolutely use BeanFactoryPostProcessors to add/modify bean definitions, here is one sample from Spring Integration codebase that adds a errorChannel if not explicitly specified by a user, you can probably use a similar code for registering your new beans:

    RootBeanDefinition errorChannelDef = new RootBeanDefinition();
    errorChannelDef.setBeanClassName(IntegrationNamespaceUtils.BASE_PACKAGE
            + ".channel.PublishSubscribeChannel");
    BeanDefinitionHolder errorChannelHolder = new BeanDefinitionHolder(errorChannelDef,
            IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME);
    BeanDefinitionReaderUtils.registerBeanDefinition(errorChannelHolder, registry);
like image 125
Biju Kunjummen Avatar answered Oct 05 '22 11:10

Biju Kunjummen