《手写Spring渐进式源码实践》-第四章 注入属性和依赖对象
目的:通过模板模式细分拆解Bean对象的实例化过程,将PropertyValues引入BeanDefinition定义中,在对象实例化完成后,填充Bean对象的属性。
BeanReference是类引用
public class BeanReference {
private final String beanName;
public BeanReference(String beanName) {
this.beanName = beanName;
}
public String getBeanName() {
return beanName;
}
}
属性值类
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;
}
}
属性集合
public class PropertyValues {
private final List<PropertyValue> propertyValues = new ArrayList<>();
public void addPropertyValue(PropertyValue pv){
this.propertyValues.add(pv);
}
public PropertyValue[] getPropertyValues(){
return this.propertyValues.toArray(new PropertyValue[0]);
}
public PropertyValue getPropertyValue(String propertyName){
for (PropertyValue propertyValue : propertyValues) {
if(propertyValue.getName().equals(propertyName)){
return propertyValue;
}
}
return null;
}
}
在BeanDefinition中的构造函数中对PropertyValues属性进行了判断处理,如果值为空,则进行实例化并创建一个PropertyValue类,将其填充到BeanDefinition的propertyValues属性上。
public class BeanDefinition {
private Class bean;
private PropertyValues propertyValues;
public BeanDefinition(Class bean) {
this.bean = bean;
this.propertyValues = new PropertyValues();
}
public BeanDefinition(Class bean, PropertyValues propertyValues) {
this.bean = bean;
this.propertyValues = Objects.nonNull(propertyValues)?propertyValues: new PropertyValues();
}
public Class getBean() {
return bean;
}
public void setBean(Class bean) {
this.bean = bean;
}
public PropertyValues getPropertyValues() {
return propertyValues;
}
public void setPropertyValues(PropertyValues propertyValues) {
this.propertyValues = propertyValues;
}
}
在AbstractAutowireCapableBeanFactory中主要包括3个方法:createBean、createBeanInstance、applyPropertyValues,这里主要关注在createBean方法中调用applyPropertyValues方法。
在applyPropertyValues方法中,通过获取beanDefinition.getPropertyValues()来循环执行属性填充。如果遇到BeanReference引用类型,则需要通过递归获取Bean对象实例,调用getBean方法。
当完成Bean对象创建和依赖后,则可以通过递归调用的方式来完成属性的填充。这里需要注意,并没有处理循环依赖的问题,
BeanUtil.setFieldValue是hutool-all工具类中提供的属性信息设置方法。
public abstract class AbstractAutowireCapableBeanFactory extends AbstractoryBeanFactory {
//实例化cblib的实例化策略
InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiation();
@Override
protected Object createBean(String beanName, BeanDefinition beanDefinition,Object[] args) throws BeansException {
Object bean;
try {
bean = createBeanInstance(beanDefinition,beanName,args);
//给bean对象填充属性
applyPropertyValues(beanName,bean,beanDefinition);
} catch (Exception e) {
throw new BeansException("Instantiation of bean failed", e);
}
super.registrySingletonBean(beanName,bean);
return bean;
}
/**
* bean对象属性填充
* @param beanName
* @param bean
* @param beanDefinition
*/
protected void applyPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition){
try {
PropertyValues propertyValues = beanDefinition.getPropertyValues();
for (PropertyValue propertyValue : propertyValues.getPropertyValues()) {
String name = propertyValue.getName();
Object value = propertyValue.getValue();
if(value instanceof BeanReference){
//例如:A依赖B,获取B的实例化对象
BeanReference beanReference = (BeanReference)value;
value = super.getBean(beanReference.getBeanName());
}
//属性填充
BeanUtil.setFieldValue(bean,name,value);
}
} catch (BeansException e) {
throw new BeansException( "Error setting property values:" + beanName,e);
}
}
protected Object createBeanInstance(BeanDefinition beanDefinition,String beanName,Object[] args){
Constructor constructorToUse = null;
Class<?> beanClass = beanDefinition.getBean();
Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
if(Objects.nonNull(args) && declaredConstructor.getParameterTypes().length ==args.length){
constructorToUse = declaredConstructor;
break;
}
}
return getInstantiationStrategy().instantiate(beanDefinition,beanName,constructorToUse,args);
}
public InstantiationStrategy getInstantiationStrategy() {
return instantiationStrategy;
}
}
以下是测试代码:
public class UserDao {
private static Map<String,String> hashMap = new HashMap<>();
static {
hashMap.put("10001","小傅哥");
hashMap.put("10002","八杯水");
hashMap.put("10003","阿毛");
}
public String queryUserName(String uId){
return hashMap.get(uId);
}
}
public class UserService {
private String uId;
private UserDao userDao;
public void queryUserInfo(){
System.out.println("查询用户信息:"+userDao.queryUserName(uId));
}
public String getuId() {
return uId;
}
public void setuId(String uId) {
this.uId = uId;
}
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
@SpringBootTest(classes = MyApplication.class)
public class ApiTest {
@Test
public void test_BeanFactory(){
//1、初始化BeanFactory对象
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//2、注册UserDao
beanFactory.registryBeanDefinition("userDao", new BeanDefinition(UserDao.class));
//3、 使用UserService填充属性(uId、userDao)
PropertyValues propertyValues = new PropertyValues();
propertyValues.addPropertyValue(new PropertyValue("uId","10001"));
propertyValues.addPropertyValue(new PropertyValue("userDao",new BeanReference("userDao")));
//4、使用UserService注册Bean对象
beanFactory.registryBeanDefinition("userService",new BeanDefinition(UserService.class,propertyValues));
//5、使用UserService获取Bean对象
UserService userService = (UserService)beanFactory.getBean("userService");
userService.queryUserInfo();
}
}
源码地址:https://github.com/fuzhengwei/book-small-spring/tree/master/spring-step-04