If client code needs to register objects which are not managed by Spring container, then we will need to work with an instance of BeanDefinition .
A Spring application can register a BeanDefinition by using the following method of BeanDefinitionRegistry:
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
BeanDefinition
|
BeanDefinition describes a bean instance. It has setter methods which can be used to programmatically set the Spring specific characteristics to a bean, for example BeanDefinition #setScope(String scope) can be used to set a scope other than default singleton. |
GenericBeanDefinition
|
This is the commonly used BeanDefinition implementation. It allows to specify the bean class, bean characteristics plus constructor argument values and property values. |
Using GenericBeanDefinition
public class MyBean {
private Date date;
public void doSomething () {
System.out.println("from my bean, date: " + date);
}
public void setDate (Date date) {
this.date = date;
}
}
public class GenericBeanDefinitionExample {
public static void main (String[] args) {
DefaultListableBeanFactory context =
new DefaultListableBeanFactory();
GenericBeanDefinition gbd = new GenericBeanDefinition();
gbd.setBeanClass(MyBean.class);
MutablePropertyValues mpv = new MutablePropertyValues();
mpv.add("date", new Date());
//alternatively we can use:
// gbd.getPropertyValues().addPropertyValue("date", new Date());
gbd.setPropertyValues(mpv);
context.registerBeanDefinition("myBeanName", gbd);
MyBean bean = context.getBean(MyBean.class);
bean.doSomething();
}
} Outputfrom my bean, date: Wed May 17 12:20:58 CDT 2017
Using BeanDefinitionBuilder
Only difference here is, BeanDefinitionBuilder uses builder pattern.
public class MyBean {
private String str;
public void setStr (String str) {
this.str = str;
}
public void doSomething () {
System.out.println("from MyBean " + str);
}
}
public class BeanDefinitionBuilderExample {
public static void main (String[] args) {
DefaultListableBeanFactory beanFactory =
new DefaultListableBeanFactory();
BeanDefinitionBuilder b =
BeanDefinitionBuilder.rootBeanDefinition(MyBean.class)
.addPropertyValue("str", "myStringValue");
beanFactory.registerBeanDefinition("myBean", b.getBeanDefinition());
MyBean bean = beanFactory.getBean(MyBean.class);
bean.doSomething();
}
} Outputfrom MyBean myStringValue
Injecting other bean references
public class MyBean {
private MyOtherBean otherBean;
public void setOtherBean (MyOtherBean otherBean) {
this.otherBean = otherBean;
}
public void doSomething () {
otherBean.doSomething();
}
}
public class MyOtherBean {
public void doSomething () {
System.out.println("from other bean ");
}
}
public class InjectingOtherBeans {
public static void main (String[] args) {
DefaultListableBeanFactory context =
new DefaultListableBeanFactory();
//define and register MyOtherBean
GenericBeanDefinition beanOtherDef = new GenericBeanDefinition();
beanOtherDef.setBeanClass(MyOtherBean.class);
context.registerBeanDefinition("other", beanOtherDef);
//definine and register myBean
GenericBeanDefinition beanDef = new GenericBeanDefinition();
beanDef.setBeanClass(MyBean.class);
MutablePropertyValues mpv = new MutablePropertyValues();
mpv.addPropertyValue("otherBean", context.getBean("other"));
beanDef.setPropertyValues(mpv);
context.registerBeanDefinition("myBean", beanDef);
//using MyBean instance
MyBean bean = context.getBean(MyBean.class);
bean.doSomething();
}
} Outputfrom other bean
Using BeanFactoryPostProcessor
BeanFactoryPostProcessor allows client code to customize bean definitions. The method BeanFactoryPostProcessor.postProcessBeanFactory is called by Spring startup process just after all bean definitions have been loaded, but no beans have been instantiated yet.
@Configuration
public class MyConfig {
@Bean
MyConfigBean myConfigBean () {
return new MyConfigBean();
}
}
public class MyConfigBean implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory (
ConfigurableListableBeanFactory beanFactory)
throws BeansException {
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setBeanClass(MyBean.class);
bd.getPropertyValues().add("strProp", "my string property");
((DefaultListableBeanFactory) beanFactory)
.registerBeanDefinition("myBeanName", bd);
}
}
public class MyBean {
private String strProp;
public void setStrProp (String strProp) {
this.strProp = strProp;
}
public void doSomething () {
System.out.println("from MyBean: " + strProp);
}
}
public class BeanFactoryPostProcessorExample {
public static void main (String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(MyConfig.class);
MyBean bean = context.getBean(MyBean.class);
bean.doSomething();
}
} Outputfrom MyBean: my string property WARNING: @Bean method MyConfig.myConfigBean is non-static and returns an object assignable to Spring's BeanFactoryPostProcessor interface. This will result in a failure to process annotations such as @Autowired, @Resource and @PostConstruct within the method's declaring @Configuration class. Add the 'static' modifier to this method to avoid these container lifecycle issues; see @Bean javadoc for complete details.
Using BeanDefinitionRegistryPostProcessor
This is a sub-interface of BeanFactoryPostProcessor (last example). It allows for the registration of bean definitions. It's method postProcessBeanDefinitionRegistry is called before BeanFactoryPostProcessor#postProcessBeanFactory. This interface is more focused on the BeanDefinition registration rather than general purpose BeanFactoryPostProcessor.
@Configuration
public class MyConfig {
@Bean
MyConfigBean myConfigBean () {
return new MyConfigBean();
}
}
public class MyConfigBean
implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry (BeanDefinitionRegistry registry)
throws BeansException {
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setBeanClass(MyBean.class);
bd.getPropertyValues().add("strProp", "my string property");
registry.registerBeanDefinition("myBeanName", bd);
}
@Override
public void postProcessBeanFactory (ConfigurableListableBeanFactory beanFactory)
throws BeansException {
//no op
}
}
public class MyBean {
private String strProp;
public void setStrProp (String strProp) {
this.strProp = strProp;
}
public void doSomething () {
System.out.println("from MyBean: " + strProp);
}
}
public class BeanDefinitionRegistryPostProcessorExample {
public static void main (String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(MyConfig.class);
MyBean bean = (MyBean) context.getBean("myBeanName");
bean.doSomething();
}
} Outputfrom MyBean: my string property WARNING: Cannot enhance @Configuration bean definition 'beanDefinitionRegistryPostProcessorExample.MyConfig' since its singleton instance has been created too early. The typical cause is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor return type: Consider declaring such methods as 'static'.
Example ProjectDependencies and Technologies Used: - Spring Context 4.3.4.RELEASE: Spring Context.
- JDK 1.8
- Maven 3.3.9
|