Bean实例化策略InstantiationStrategy与为bean填充属性
代码地址:github.com/WangChao-ly… 中的InstantiationStrategy-populate-bean-with-property-values分支
建议订阅博主专栏,从下到上系统手写spring源码,体会其中过程!
InstantiationStrategy策略
- 由于之前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;
}
- 再编写简单的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);
}
}
}
- 我们也可以提供另外使用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();
}
}
- 后在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填充属性
- 编写属性实体类,设置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;
}
}
- 编写属性实体集合类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;
}
}
- 然后在创建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);
}
}
- 测试代码如下,后续文章会继续更新为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());
}
}