Bean实例化策略
上一篇文章中,Bean在AbstractAutowireCapableFactory.doCreateBean方法中使用beanClass.newInstance()方法来实例化,这样只适用于Bena有无参构造函数的情况。
对应bean的实例化,我们可以抽象出一个实例化策略的接口,分别有两个实现类
InstantiationStrategy:实例化Bean的策略接口,两个实现类,在AbstractAutowireCapableBeanFactory中使用,通过实例化不同的实现类对象,实现不同策略实例化bean
/**
* Bean的实例化策略 接口
*
*/
public interface InstantiationStrategy {
Object instantiate(BeanDefinition beanDefinition) throws BeansException;
}
SimpleInstantiationStrategy:使用bean的无参构造函数实例化对象
public class SimpleInstantiationStrategy implements InstantiationStrategy {
/**
* 简单的bean实例化策略,根据bean的无参构造函数实例化对象
*
* @param beanDefinition
* @return
* @throws BeansException
*/
@Override
public Object instantiate(BeanDefinition beanDefinition) throws BeansException {
Class beanClass = beanDefinition.getBeanClass();
try {
Constructor constructor = beanClass.getDeclaredConstructor();
return constructor.newInstance();
} catch (Exception e) {
throw new BeansException("Failed to instantiate [" + beanClass.getName() + "]", e);
}
}
}
CglibSubclassingInstantiationStrategy:使用CGLIB动态生成子类
public class CglibSubclassingInstantiationStrategy implements InstantiationStrategy {
/**
* 使用CGLIB动态生成子类
*
* @param beanDefinition
* @return
* @throws BeansException
*/
@Override
public Object instantiate(BeanDefinition beanDefinition) throws BeansException {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(beanDefinition.getBeanClass());
enhancer.setCallback((MethodInterceptor) (obj, method, argsTemp, proxy) -> proxy.invokeSuper(obj,argsTemp));
return enhancer.create();
}
}
使用:
Bean填充属性
到现在,我们beanDefinition中只有Class信息,现在我们再往其中填充属性。
1、BeanDefinition中新增属性
private PropertyValues propertyValues;
public class PropertyValues {
private final List<PropertyValue> propertyValueList = new ArrayList<>();
public void addPropertyValue(PropertyValue pv) {
propertyValueList.add(pv);
}
public PropertyValue[] getPropertyValues() {
return this.propertyValueList.toArray(new PropertyValue[0]);
}
public PropertyValue getPropertyValue(String propertyName) {
for (int i = 0; i < this.propertyValueList.size(); i++) {
PropertyValue pv = this.propertyValueList.get(i);
if (pv.getName().equals(propertyName)) {
return pv;
}
}
return null;
}
}
/**
* bean属性信息
*
*/
public class PropertyValue {
private final String name;
private final Object value;
public PropertyValue(String name, Object value) {
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
public Object getValue() {
return value;
}
}
2、构造对应数据进行测试,BeanDefinition中存入Person的name属性和age属性
@Test
public void testPopulateBeanWithPropertyValues() throws Exception {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
PropertyValues propertyValues = new PropertyValues();
propertyValues.addPropertyValue(new PropertyValue("name", "derek"));
propertyValues.addPropertyValue(new PropertyValue("age", 18));
BeanDefinition beanDefinition = new BeanDefinition(Person.class, propertyValues);
beanFactory.registerBeanDefinition("person", beanDefinition);
Person person = (Person) beanFactory.getBean("person");
System.out.println(person);
assertThat(person.getName()).isEqualTo("derek");
assertThat(person.getAge()).isEqualTo(18);
}
3、getBean方法最终调用doCreateBean的时候,applyPropertyValues方法填充属性
protected Object doCreateBean(String beanName, BeanDefinition beanDefinition) {
Object bean = null;
try {
bean = createBeanInstance(beanDefinition);
//为bean填充属性
applyPropertyValues(beanName, bean, beanDefinition);
} catch (Exception e) {
throw new BeansException("Instantiation of bean failed", e);
}
addSingleton(beanName, bean);
return bean;
}
4、通过反射的方式填充属性
/**
* 为bean填充属性
*
* @param bean
* @param beanDefinition
*/
protected void applyPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition) {
try {
for (PropertyValue propertyValue : beanDefinition.getPropertyValues().getPropertyValues()) {
String name = propertyValue.getName();
Object value = propertyValue.getValue();
//通过反射设置属性
BeanUtil.setFieldValue(bean, name, value);
}
} catch (Exception ex) {
throw new BeansException("Error setting property values for bean: " + beanName, ex);
}
}
Bean注入Bean
上面通过反射的方式,将Bean的属性设置进去。下面实现一个Bean引用另一个Bean如何填充属性。(暂时不支持循环依赖)
首先先从测试开始。
1、新增Car对象,然后让Person对象引入Car
public class Car {
private String brand;
}
public class Person {
private String name;
private int age;
private Car car;
}
2、测试
- 首先先注册Car实例。并存储其相关属性
- Person实例依赖Car实例,将car实例引入person,并且value为BeanReference引用类型。注册Person实例
- 调用getBean()
/**
* 为bean注入bean
*
* @throws Exception
*/
@Test
public void testPopulateBeanWithBean() throws Exception {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//注册Car实例
PropertyValues propertyValuesForCar = new PropertyValues();
propertyValuesForCar.addPropertyValue(new PropertyValue("brand", "porsche"));
BeanDefinition carBeanDefinition = new BeanDefinition(Car.class, propertyValuesForCar);
beanFactory.registerBeanDefinition("car", carBeanDefinition);
//注册Person实例
PropertyValues propertyValuesForPerson = new PropertyValues();
propertyValuesForPerson.addPropertyValue(new PropertyValue("name", "derek"));
propertyValuesForPerson.addPropertyValue(new PropertyValue("age", 18));
//Person实例依赖Car实例
propertyValuesForPerson.addPropertyValue(new PropertyValue("car", new BeanReference("car")));
BeanDefinition beanDefinition = new BeanDefinition(Person.class, propertyValuesForPerson);
beanFactory.registerBeanDefinition("person", beanDefinition);
Person person = (Person) beanFactory.getBean("person");
System.out.println(person);
assertThat(person.getName()).isEqualTo("derek");
assertThat(person.getAge()).isEqualTo(18);
Car car = person.getCar();
assertThat(car).isNotNull();
assertThat(car.getBrand()).isEqualTo("porsche");
}
//一个Bean对另一个Bean的引用
public class BeanReference {
private final String beanName;
public BeanReference(String beanName) {
this.beanName = beanName;
}
public String getBeanName() {
return beanName;
}
}
3、填充属性。beanA依赖beanB
在beanA填充属性的时候判断propertyValue的类型是否是BeanReference引用类型,如果是引用类型的话,先去实例化beanB,也就是用这个引用类型去调用getBean()方法,类似于递归的调用,总之遇到引用类型,就先去实例化引用类型的属性。然后再设置。
protected void applyPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition) {
try {
for (PropertyValue propertyValue : beanDefinition.getPropertyValues().getPropertyValues()) {
String name = propertyValue.getName();
Object value = propertyValue.getValue();
if (value instanceof BeanReference) {
// beanA依赖beanB,先实例化beanB
BeanReference beanReference = (BeanReference) value;
value = getBean(beanReference.getBeanName());
}
//通过反射设置属性
BeanUtil.setFieldValue(bean, name, value);
}
} catch (Exception ex) {
throw new BeansException("Error setting property values for bean: " + beanName, ex);
}
}