Java spring create bean in runtime

How to instantiate spring managed beans at runtime

Solution 2: i think that your concept is wrong by using you are bypassing Spring container and resorting to using regular java constructor therefore any annotations on factory method are ignored and this bean is never managed by Spring here is the solution to create multiple prototype beans in one method, not pretty looking but should work, I autowired container in RuntimeBean as proof of autowiring shown in log also you can see in log that every bean is new instance of prototype when you run this . You could try using scope — when you autowire a bean with such scope a new instance is created for each HTTP request : This will make sure that a new instance of is created for each request : Also keep in mind that instance injected into will be proxied so in this example you will be returning a proxy instance with some additional fields.

How to instantiate Spring managed beans at runtime?

Looks like I found a solution. As I am using java based configuration it is even simpler than you can imagine. Alternative way in xml would be lookup-method, however only from spring version 4.1.X as it supports passing arguments to the method.

Читайте также:  Pwpnet pl index php ru

Here is a complete working example:

public class Container < private ListruntimeBeans = new ArrayList(); private RuntimeBeanFactory runtimeBeanFactory; public void load() < // repeated several times depending on external data/environment runtimeBeans.add(createRuntimeBean("Some external info1")); runtimeBeans.add(createRuntimeBean("Some external info2")); >public RuntimeBean createRuntimeBean(String info) < // should create bean which internally can have some // spring annotations or in other words // should be managed by spring return runtimeBeanFactory.createRuntimeBean(info); >public void setRuntimeBeanFactory(RuntimeBeanFactory runtimeBeanFactory) < this.runtimeBeanFactory = runtimeBeanFactory; >> public interface RuntimeBeanFactory < RuntimeBean createRuntimeBean(String info); >//and finally @Configuration public class ApplicationConfiguration < @Bean Container container() < Container container = new Container(beanToInject()); container.setBeanRuntimeFactory(runtimeBeanFactory()); return container; >// LOOK HOW IT IS SIMPLE IN THE JAVA CONFIGURATION @Bean public BeanRuntimeFactory runtimeBeanFactory() < return new BeanRuntimeFactory() < public RuntimeBean createRuntimeBean(String beanName) < return runtimeBean(beanName); >>; > @Bean @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) RuntimeBean runtimeBean(String beanName) < return new RuntimeBean(beanName); >> class RuntimeBean

i think that your concept is wrong by using
RuntimeBean beanRuntime = createRuntimeBean();
you are bypassing Spring container and resorting to using regular java constructor therefore any annotations on factory method are ignored and this bean is never managed by Spring

here is the solution to create multiple prototype beans in one method, not pretty looking but should work, I autowired container in RuntimeBean as proof of autowiring shown in log also you can see in log that every bean is new instance of prototype when you run this .

@Configuration @ComponentScan @EnableAutoConfiguration public class Application < public static void main(String[] args) < SpringApplication.run(Application.class, args); ApplicationContext context = new AnnotationConfigApplicationContext(Application.class); Container container = (Container) context.getBean("container"); container.load(); >> @Component class Container < private ListruntimeBeans = new ArrayList(); @Autowired ApplicationContext context; @Autowired private ObjectFactory myBeanFactory; public void load() < // repeated several times depending on external data/environment for (int i = 0; i < 10; i++) < // ************************************** // COMENTED OUT THE WRONG STUFFF // RuntimeBean beanRuntime = context.getBean(RuntimeBean.class); // createRuntimeBean(); // // ************************************** RuntimeBean beanRuntime = myBeanFactory.getObject(); runtimeBeans.add(beanRuntime); System.out.println(beanRuntime + " " + beanRuntime.container); >> @Bean @Scope(BeanDefinition.SCOPE_PROTOTYPE) public RuntimeBean createRuntimeBean() < return new RuntimeBean(); >> // @Component class RuntimeBean < @Autowired Container container; >' 
@Component public class RuntimeBeanBuilder < @Autowired private ApplicationContext applicationContext; public MyObject load(String beanName, MyObject myObject) < ConfigurableApplicationContext configContext = (ConfigurableApplicationContext) applicationContext; SingletonBeanRegistry beanRegistry = configContext.getBeanFactory(); if (beanRegistry.containsSingleton(beanName)) < return beanRegistry.getSingleton(beanName); >else < beanRegistry.registerSingleton(beanName, myObject); return beanRegistry.getSingleton(beanName); >> > @Service public MyService < //inject your builder and create or load beans @Autowired private RuntimeBeanBuilder builder; //do something >

Instead of using SingletonBeanRegistry you can use this:

BeanFactory beanFactory = configContext.getBeanFactory(); 

Anyway SingletonBeanBuilder extends HierarchicalBeanFactory and HierarchicalBeanFactory extends BeanFactory

Читайте также:  Android room kotlin flow

Creating Spring beans dynamically runtime using method, I have to use company’s custom made libraries with Spring Boot and wondering if I’m able to create bean like this in runtime and add it to

How to generate new managed bean programmatically in Spring

It seems you need a managed new object when a request came. To achieve this you could mark your Bean with @Scope(«prototype») that will solve your problem.

A bean with prototype scope will return a different instance every time it is requested from the container.

To know more, how prototype works have a look at this page:

It all depends on what is the changing thing. You could either use protoype scope as shown in ruhul’s answer. However the problem here would be that the prototype instance would be injected only once when the InfoRestController bean is created.

You could try using request scope — when you autowire a bean with such scope a new instance is created for each HTTP request :

@Component @Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS) public class Info < private final String activeProfile; private final Instant timestamp; public Info(@Value("$") String activeProfile) < this.activeProfile = activeProfile; this.timestamp = Instant.now(); >> 

This will make sure that a new instance of Info is created for each request :

@RestController public class InfoRestController < private Info info; @Autowired public InfoRestController(Info info) < this.info = info; >@GetMapping("/test") public Info get() < return info; >> 

Also keep in mind that Info instance injected into InfoRestController will be proxied so in this example you will be returning a proxy instance with some additional fields. To overcome this we could just make a copy of values from injected bean :

@RestController public class InfoRestController < private Info info; @Autowired public InfoRestController(Info info) < this.info = info; >@GetMapping("/test") public Info get() < return Info.of(info.getActiveProfile(), info.getTimestamp()); // create a copy >> @Component @Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS) public class Info < private final String activeProfile; private final Instant timestamp; @Autowired // this constructor should be used by spring public Info(@Value("$") String activeProfile) < this.activeProfile = activeProfile; this.timestamp = Instant.now(); >private Info(String activeProfile, Instant timestamp) < // private constructor this.activeProfile = activeProfile; this.timestamp = timestamp; >public static Info of(String activeProfile, Instant instant) < //static factory method return new Info(activeProfile, instant); >// getters > 

The missing piece of the puzzle was javax.inject.Provider . I didn’t know about it but it had exactly the interface that I was looking for. The final solution was to indeed let Spring manage the bean ( Info ) and use a Provider in the rest controller. This is the bean, almost exactly like in the OP

@Component @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class Info < private final String activeProfile; private final Instant timestamp; public Info(@Value("$") String activeProfile) < this.activeProfile = activeProfile; this.timestamp = Instant.now(); >> 

The bean has the Prototype scope as suggested by ruhul. I had tried that before but without the Provider I was still stuck. This is how to return it in the controller

@RestController public class InfoRestController < @Autowire private ProviderinfoProvider; @GetMapping public Info getInfo() < return infoProvider.get(); >> 

For the sake of completeness, I found another, uglier way of doing it by injecting the spring ApplicationContext and then using context.getBean(«info») but the dependency on the spring context and the string name were a smell. The solution with Provider is much more focused

How to Get All Spring-Managed Beans?, We can get a list of all beans within this container in two ways: Using a ListableBeanFactory interface. Using a Spring Boot Actuator.

Creating Spring beans dynamically runtime using method

Could be something like this

DefaultListableBeanFactory beanFactory = //get and store the factory somewhere MyBean newBean = new MyBean(); beanFactory.initializeBean(newBean,"TheBeanName"); //could be class' canonical name beanFactory.autowireBeanProperties(newBean, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true); beanFactory.registerSingleton("TheBeanName", newBean); 

How to autowire spring beans from a non-bean object created at, Use constructor injection instead of field injection; this is a best practice all the time anyway. Then it’s trivial to inject your A into the

Источник

Spring register bean at runtime

Spring register bean at runtime

In this article, we will learn to register the Spring bean at runtime. Sometimes, you want to register the beans programmatically based on some condition or dynamically.

If you are not familiar with Spring bean instantiation, see this article.

2. Spring register bean -BeanDefinitionRegistryPostProcessor

One way to do this is by using the BeanDefinitionRegistryPostProcessor .

The ApplicationContext auto-detects BeanFactoryPostProcessor beans in its bean definitions and apply them before any other beans get created. This BeanFactoryPostProcessor is an extension point to customize the bean definitions or configuration metadata of the bean before the creation of the beans.

The BeanDefinitionRegistryPostProcessor allows the registration of further bean definitions before regular BeanFactoryPostProcessor detection kicks in.

2.1. Implement BeanDefinitionRegistryPostProcessor

To add a new bean definition, you can create an implementation of the BeanDefinitionRegistryPostProcessor and override the method postProcessBeanDefinitionRegistry .

In this postProcessBeanDefinitionRegistry method, you can change the application context’s internal bean definition registry after its standard initialization. Though all regular bean definitions are loaded, no beans have been instantiated yet.

This allows space for adding further bean definitions.

Note that we annotated this class with @Component to allow the Spring application to scan this class.

@Component public static class BeanRegistration implements BeanDefinitionRegistryPostProcessor < @Override public void postProcessBeanDefinitionRegistry( BeanDefinitionRegistry bdr) throws BeansException < >@Override public void postProcessBeanFactory( ConfigurableListableBeanFactory clbf) throws BeansException < >>

2.2. Register bean programmatically

The postProcessBeanDefinitionRegistry method is invoked with the bean definition registry used by the application context.

You must call registerBeanDefinition on the bean definition registry to register a new bean definition. This registerBeanDefinition takes the bean name and definition as input.

You can use the BeanDefinitionBuilder to create a BeanDefinition programmatically (introduced in Spring 2.0).

bdr.registerBeanDefinition("customBean", BeanDefinitionBuilder.genericBeanDefinition(CustomBean.class, () -> new CustomBean("Custom Bean Constructor Argument")).getBeanDefinition());

In the below code, we are using the genericBeanDefinition builder method to create a new Bean definition.

public static BeanDefinitionBuilder genericBeanDefinition(Class beanClass, Supplier instanceSupplier) 
@Override public void postProcessBeanDefinitionRegistry( BeanDefinitionRegistry bdr) throws BeansException < bdr.registerBeanDefinition("customBean", BeanDefinitionBuilder.genericBeanDefinition(CustomBean.class, () ->new CustomBean("Custom Bean Constructor Argument")).getBeanDefinition()); >

3. Spring register bean using ApplicationContextInitializer

You can implement the ApplicationContextInitializer to register the bean programmatically. It is essentially code that gets executed before the Spring application context gets completely created.

In this class, you can call registerBean and register the bean programmatically.

public class ProgrammaticApplicationContextInitializer implements ApplicationContextInitializer  < @Override public void initialize(GenericApplicationContext applicationContext) < applicationContext.registerBean(CustomBean.class, "Custom Bean initialization"); >>

If you are not using the Spring boot, then you can register the application context as below:

public static void main(String[] args)

If you are using Spring Boot, you can register it straightforwardly:

@Configuration @EnableAutoConfiguration @ComponentScan public class BeanfactoryApplication < public static void main(String[] args) < new SpringApplicationBuilder(BeanfactoryApplication.class) .initializers(new ProgrammaticApplicationContextInitializer()) .run(args); application.addInitializers(ProgrammaticApplicationContextInitializer.class); application.run(args); >>

You can register them in META-INF/spring.factories

org.springframework.context.ApplicationContextInitializer=\ com.tedblob.ProgrammaticApplicationContextInitializer

You can add it to the web.xml for a Spring web application:

 contextInitializerClasses com.tedblob.ProgrammaticApplicationContextInitializer  org.springframework.web.context.ContextLoaderListener 

You can also add it to the application properties file or external properties:

context.initializer.classes=com.tedblob.ProgrammaticApplicationContextInitializer

4. Register bean at runtime using BeanFactory

Alternatively, you can use the BeanFactory or ApplicationContext to register a bean by invoking the registerBean method. However, bean definitions do not exist for this type of registration.

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanfactoryApplication.class); reader.loadBeanDefinitions(new ClassPathResource("config.xml")); applicationContext.registerBean(CustomBean.class, "custom bean"); CustomBean customBean = applicationContext.getBean(CustomBean.class); System.out.println(customBean.getValue() + "");

5. Register runtime using BeanDefinitionRegistry

The BeanDefinitionRegistry is the only interface in Spring’s bean factory packages that encapsulates the registration of bean definitions. You can use this registry to remove or register the beans dynamically.

To register a new bean definition, use registerBeanDefinition .

registry.registerBeanDefinition(beanId, newBeanObj);

To remove an existing bean definition, use removeBeanDefinition .

registry.removeBeanDefinition(beanId);

You can remove and add a new bean definition at runtime by using the following code:

AutowireCapableBeanFactory factory = applicationContext.getAutowireCapableBeanFactory(); BeanDefinitionRegistry registry = (BeanDefinitionRegistry) factory; registry.removeBeanDefinition(beanId); registry.registerBeanDefinition(beanId, newBeanObj);

6. Conclusion

To sum up, we have learned to register a bean at runtime in a Spring application. You can find code samples of this article in our GitHub repository.

Источник

Оцените статью