1

I want to add @Component classes to spring container after ApplicationContext load. But I cannot use BeanFactory. Because I'm using BeanFactory I have to define beans for these classes. But I cannot defined it(If I am not use reflection). Because these classes will load at runtime by ClassLoader.

For example

@Component
public class Service {

    private final CustomerService customerService;
    private final OrderService orderService;
    private final PaymentService paymentService;

    @Autowired
    public Service(CustomerService customerService, OrderService orderService, PaymentService paymentService) {
        this.customerService = customerService;
        this.orderService = orderService;
        this.paymentService = paymentService;
    }
}

In this example Spring create bean for this class while application invoking. There is no need to define bean with @Bean. But what I want is compile spring projects and load those clasess from another project and add to Spring ApplicationContext. So i can autowire these. Otherwise I have to create bean with reflection at runtime. And if I use reflection, I have invoke all dependent class recursively.

Is there any way do it without create beans using reflection at runtime.

2 Answers2

2

If I understand things correctly: you have some classes that are marked with @Component and you want Spring to manage their lifecycle?

Does this help: https://springframework.guru/spring-component-scan/ ? @ComponentScan specifically or in XML config something like:

 <context:component-scan base-package="org.example"/>
Not a JD
  • 1,864
  • 6
  • 14
  • "Spring needs the information to locate and register all the Spring components with the application context when the application starts", At your link. You are right but I need to register Spring components at runtime. In other word, after application context start. I should tell to spring re-scan components after application start for loaded class at runtime – Burak Helvacı Mar 08 '19 at 23:09
  • My bad - this might be useful: https://stackoverflow.com/questions/4540713/add-bean-programmatically-to-spring-web-app-context – Not a JD Mar 10 '19 at 01:39
2

I found a solution.

    ConfigurableApplicationContext context = SpringApplication.run(EventServiceApplication.class, args);
    // Load class ...
    context.start();

If we run context.start() method after load class, spring create @Component like class beans and put to spring container.

Another solution (This is exact solution):

ConfigurableApplicationContext context = SpringApplication.run(EventServiceApplication.class, args);

List<Class<?>> classes = // load classes

classes
.stream()
.filter(clazz -> clazz.isAnnotationPresent(Component.class) || Arrays.stream(clazz.getAnnotations()).anyMatch(annotation -> annotation.annotationType().isAnnotationPresent(Component.class)))
.forEach(applicationContext::register);

After register the classes, maybe one of your loaded class annoteded with @Configuration and it contains @Bean annotated methods. For register those @Bean methods. You should use

ConfigurationClassPostProcessor configurationClassPostProcessor; // This class is autowireable. Spring has bean for this class at spring bean container.
configurationClassPostProcessor.processConfigBeanDefinitions(applicationContext.getDefaultListableBeanFactory())

I found this solution at Spring Framework source code