Add runtime generated class bean to spring boot application context

637 Views Asked by At

I am working on a project where I generate a class after the spring boot context starts and compile it to the target/classes folder. I know Spring scans the package and registers all the beans in the application context when the application starts. But here, we are generating a class with annotation @Service at runtime, and the application context is unaware of this new bean. So, other beans cannot find this runtime-generated class. This bean is also not in the bean list of Actuator -> Beans in IntelliJ IDEA

When I rerun the application, this runtime-generated bean gets registered in the application context, and other beans can find out or utilize that bean. Actuator -> Beans in IntelliJ IDEA also shows this bean. I want to register this runtime-generated bean to the application context without restarting/rerunning the application. Please let me know what I am missing here.

I tried this, but it did not work for me.

@RestController
@Scope("prototype")
@Slf4j
public class myClass {

    @Autowired
    private ApplicationContext appContext;

    @GetMapping("/beanRegistration")
    public void beanRegistration() {
        try {
            Class<?> generatedClass = Class.forName("myApp.sam.protocompiler.GrpcServerImpl");
            log.info("generatedClass : {} | Methods count: {} | Super class : {}", generatedClass.getCanonicalName(), generatedClass.getMethods().length, generatedClass.getSuperclass());

            ConfigurableListableBeanFactory beanFactory = ((ConfigurableApplicationContext) appContext).getBeanFactory();
            beanFactory.registerSingleton(generatedClass.getCanonicalName(), generatedClass);

            String[] beans = appContext.getBeanDefinitionNames();
            Arrays.sort(beans);
            for (String bean : beans) {
                if(bean.contains(generatedClass.getCanonicalName())) {
                    System.out.println("New Bean : " + bean);
                }
            }
        } catch (Exception ex) {
            log.error("Error : {}", ex.getMessage(), ex);
        }
    }
}

Also, Is it possible to Scan components after the application is started running? If we can scan runtime-generated components at runtime, we can solve this problem.

1

There are 1 best solutions below

1
egeorge On

Since you are definitely in a Web application, you might try using GenericWebApplicationContext instead.

@Autowired private GenericWebApplicationContext context;

Then,

context.registerBean(generatedClass.getCannonicalName(), generatedClass);

I don't know if this does anything different than what you have, but I think it is the more spring-approved way to do it.