(造轮子)手写Spring框架-Bean实例化策略InstantiationStrategy与为bean填充属性

108 阅读3分钟

Bean实例化策略InstantiationStrategy与为bean填充属性

代码地址:github.com/WangChao-ly… 中的InstantiationStrategy-populate-bean-with-property-values分支

建议订阅博主专栏,从下到上系统手写spring源码,体会其中过程!

InstantiationStrategy策略

  1. 由于之前AbstractAutowireCapableBeanFactory中doCreateBean方法的bean是直接利用beanDefinition获取Class类,然后利用newInstance构造出来的示例对象,依赖于Class类的构造方法,不够简约,这里我们引入bean的实例化策略模式InstantiationStrategy,将生成对象具体的方法与实现解耦,更好的实现bean示例对象的创建 先编写策略接口InstantiationStrategy:
/**
 * Bean的实例化策略
 * @author WangChao
 * @version 1.0
 * @date 2023/6/15 10:37
 */
public interface InstantiationStrategy {
    /**
     * 获取bean示例对象
     * @param beanDefinition
     * @return
     * @throws BeansException
     */
    Object instantiate(BeanDefinition beanDefinition) throws BeansException;
}
  1. 再编写简单的bean实例化策略,根据bean的无参构造函数实例化对象,重点用到了beanClass.getDeclaredConstructor();方法获取到构造函数,调用newInstance方法得到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);
        }
    }
}
  1. 我们也可以提供另外使用CGLIB动态生成子类,需要借助Enhancer类,引入相关依赖即可,具体实现如下:
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();
    }
}
  1. 后在AbstractAutowireCapableBeanFactory的doCreateBean方法中更换原来的创建bean的方法,使用InstantiationStrategy策略来替换原来的newInstance方法,具体实现如下:
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory{
    private InstantiationStrategy instantiationStrategy = new SimpleInstantiationStrategy();

    @Override
    protected Object createBean(String beanName, BeanDefinition beanDefinition) throws BeansException{
        return doCreateBean(beanName,beanDefinition);
    }

    /**
     * 创建bean示例
     * @param beanName
     * @param beanDefinition
     * @return
     * @throws BeansException
     */
    protected Object doCreateBean(String beanName,BeanDefinition beanDefinition) throws BeansException{
        Object bean;
        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;
    }

    /**
     * 利用实例化策略创建对象
     * @param beanDefinition
     * @return
     */
    protected Object createBeanInstance(BeanDefinition beanDefinition){
        return getInstantiationStrategy().instantiate(beanDefinition);
    }

    /**
     * 给bean对象注入属性
     * @param beanName
     * @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 e){
            throw new BeansException("Error setting property values for bean: " + beanName, e);
        }
    }

    /**
     * 获取实例化对象
     * @return
     */
    public InstantiationStrategy getInstantiationStrategy(){
        return instantiationStrategy;
    }

    public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy){
        this.instantiationStrategy = instantiationStrategy;
    }
}

5.测试代码:

public class BeanDefinitionAndBeanDefinitionRegistryTest {
    @Test
    public void testBeanDefinition() throws Exception{
        DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
        BeanDefinition beanDefinition = new BeanDefinition(HelloService.class);
        defaultListableBeanFactory.registerBeanDefinition("helloService",beanDefinition);

        HelloService helloService = (HelloService)defaultListableBeanFactory.getBean("helloService");
        helloService.sayHello();
    }
}

bean填充属性

  1. 编写属性实体类,设置name-value对,对应xml中属性值
public class PropertyValue {
    private final String name;
    private final Object value;

    /**
     * 为bean注入属性
     * @param name
     * @param value
     */
    public PropertyValue(String name,Object value) {
        this.name = name;
        this.value = value;
    }

    public String getName(){
        return name;
    }

    public Object getValue(){
        return value;
    }
}
  1. 编写属性实体集合类PropertyValues,里面有List propertyValues = new ArrayList<>(),用来存储单个属性对,并且对外提供添加PropertyValue等方法。
public class PropertyValues {
    private final List<PropertyValue> propertyValues = new ArrayList<>();

    public void addPropertyValue(PropertyValue value) {
        propertyValues.add(value);
    }

    public PropertyValue[] getPropertyValues(){
        return this.propertyValues.toArray(new PropertyValue[0]);
    }

    public PropertyValue getPropertyValue(String propertyName){
        int size = this.propertyValues.size();
        for(int i=0;i<size;i++){
            PropertyValue pv = this.propertyValues.get(i);
            if(pv.getName().equals(propertyName)){
                return pv;
            }
        }
        return null;
    }
}
  1. 然后在创建bean方法中,同时注入property属性,通过解析beanDefinition.getPropertyValues().getPropertyValues()中的name和value,然后将解析的结果通过反射设置属性给bean对象,代码如下:
protected Object doCreateBean(String beanName,BeanDefinition beanDefinition) throws BeansException{
    Object bean;
    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;
}
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 e){
        throw new BeansException("Error setting property values for bean: " + beanName, e);
    }
}
  1. 测试代码如下,后续文章会继续更新为bean注入bean对象:
public class PopulateBeanWithPropertyValuesTest {
    @Test
    public void testPopulateBeanWithPropertyValues() throws Exception{
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        PropertyValues propertyValues = new PropertyValues();
        propertyValues.addPropertyValue(new PropertyValue("name","chao"));
        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.toString());
    }
}