如果应用代码需要注册没有被spring容器管理的代码,则需要使用BeanDefinition实例来实现。spring应用可以注册BeanDefinition通过BeanDefinitionRegistry类的方法。
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
BeanDefinition描述bean实例。其有setter方法用来通过编程的方式设置spring特定字符给bean,如:BeanDefinition #setScope(String scope)
,设置其他的scope代替缺省的singleton。
是BeanDefinition 的通用实现。允许指定bean类,特性及构造器参数值和属性值。
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;
}
}
通过GenericBeanDefinition加载:
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();
}
}
输出结果:
from my bean, date: Wed Jan 17 20:20:58 CDT 2018
使用这种方式的区别是 BeanDefinitionBuilder使用构建模式。
public class MyBean {
private String str;
public void setStr (String str) {
this.str = str;
}
public void doSomething () {
System.out.println("from MyBean " + str);
}
}
通过BeanDefinitionBuilder加载:
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();
}
}
输出结果:
from MyBean myStringValue
public class MyBean {
private MyOtherBean otherBean;
public void setOtherBean (MyOtherBean otherBean) {
this.otherBean = otherBean;
}
public void doSomething () {
otherBean.doSomething();
}
}
MyOtherBean
public class MyOtherBean {
public void doSomething () {
System.out.println("from other bean ");
}
}
通过GenericBeanDefinition 加载其他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();
}
}
输出结果:
from other bean
BeanFactoryPostProcessor允许客户端代码自定义bean定义。方法BeanFactoryPostProcessor.postProcessBeanFactory
在spring启动过程所有bean定义已经成功加载之后被调用,但仍然没有bean被实例化。
@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();
}
}
输出结果:
from MyBean: my string property
这时BeanFactoryPostProcessor 的一个子接口,其允许注册bean定义。在BeanFactoryPostProcessor#postProcessBeanFactory之前它的方法postProcessBeanDefinitionRegistry 被调用。这个接口更聚焦在BeanDefinition注册,而不是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();
}
}
输出结果:
from MyBean: my string property
通过示例说明了几种动态注册bean的方法。