Creating Spring Bean dynamically in the Runtime

Nov 11, 2018 · 3 min read

After 5 years it seems that this article in my blog is the most popular one, over 9,300 page views. So, it’s time to update this article. I also added a Github example for this article.

The Example springbean-dynamic at Github

In my training someone asked me whether it is possible to create an object (a Spring Bean) dynamically so you can choose which implementation you want to have in the runtime. So at the compile time you don’t know what object actually should be created yet. The application should decide what object to be created based on a properties file.

1. We create an annotation so we can mark the method which should be able to create the object dynamically:

package your.package;

@Retention(RetentionPolicy.RUNTIME)
public @interface InjectDynamicObject {
}

2. Use the new created annotation in your method which should be able to create the object dynamically:

@Service
public class CustomerServiceImpl {
private Customer dynamicCustomerWithAspect;

@InjectDynamicObject
public Customer getDynamicCustomerWithAspect() {
return this.dynamicCustomerWithAspect;
}
}

3. Write an aspect with Pointcut and Advise which change the object returned by the method in the step 2:

@Component
@Aspect
public class DynamicObjectAspect {
// This comes from the property file
@Value("${dynamic.object.name}")
private String object;
@Autowired
private ApplicationContext applicationContext;

@Pointcut("execution(@com.lofi.springbean.dynamic.
InjectDynamicObject * *(..))")
public void beanAnnotatedWithInjectDynamicObject() {
}
@Around("beanAnnotatedWithInjectDynamicObject()")
public Object adviceBeanAnnotatedWithInjectDynamicObject(
ProceedingJoinPoint pjp) throws Throwable {
pjp.proceed();

// Create the bean or object depends on the property file
Object createdObject = applicationContext.getBean(object);
return createdObject;
}
}

4. Write your class which should be returned back from the @InjectDynamicObject. The name is configured in a properties file. In this example I wrote two different Customer implementation: CustomerOneImpl and CustomerTwoImpl:

@Component("customerOne")
public class CustomerOneImpl implements Customer {
@Override
public String getName() {
return "Customer One";
}
}
application.properties
dynamic.object.name=customerOne

5. Write your unit test to test the method:

@RunWith(SpringRunner.class)
@SpringBootTest
public class CustomerServiceImplTest {
@Autowired
private CustomerServiceImpl customerService;
@Test
public void testGetDynamicCustomerWithAspect() {
// Dynamic object creation
logger.info("Dynamic Customer with Aspect: " +
customerService.getDynamicCustomerWithAspect()
.getName());
}

OK, there is another easier way to do this 😃 Without Aspects and AspectJ, just pure Spring:

Just inject all your component implementations into a Map and get the correct implementation out of it. Just like what we have done in eXTra Client application. Please take a look at our implementation of PluginsLocatorManager as an example. Spring injects the Map with Bean name as String and the Bean itself automagically.

“… Even typed Maps can be autowired as long as the expected key type is String. The Map values will contain all beans of the expected type, and the keys will contain the corresponding bean names” (see Spring documentation for details).

@Service
public class CustomerServiceImpl {

// We inject the customer implementations into a Map
@Autowired
private Map<String, Customer> dynamicCustomerWithMap;

// This comes from the property file as a key for the Map
@Value("${dynamic.object.name}")
private String object;
public Customer getDynamicCustomerWithMap() {
return this.dynamicCustomerWithMap.get(object);
}
}

Have fun!


Originally published at lofidewanto.blogspot.com.

Dr. Lofi Dewanto

Written by

Lofi Model@Work: https://lofidewanto.blogspot.com

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade