前面说的只是根据有参构造方法的Bean创建, 今天则是来进行属性注入和依赖注入.
比如常见的@Vale属性注入和@Resource依赖注入,不过我们还没那么快跳到注解,而是先讲一下基本的注入.
之前就曾说过, BeanDefinition 没有那么简单,上次改成了Class,这次加入属性.
主要是用于记录Bean需要的属性名,和属性值.
PropertyValue
所以建立一个PropertyValue对象.
@Data
public class PropertyValue {
private final String name;
private final Object value;
public PropertyValue(String name, Object value) {
this.name = name;
this.value = value;
}
}
PropertyValues
当然一个类不止一个属性,所以需要一个集合来填入,这里简单封装一下.
public class PropertyValues {
private final List<PropertyValue> propertyValueList = new ArrayList<>();
public void addPropertyValue(PropertyValue value){
propertyValueList.add(value);
}
public PropertyValue[] getPropertyValues() {
return propertyValueList.toArray(new PropertyValue[0]);
}
public PropertyValue getPropertyValue(String propertyName){
for (PropertyValue propertyValue : propertyValueList) {
if (propertyValue.getName().equals(propertyName)){
return propertyValue;
}
}
return null;
}
}
BeanDefinition
然后就可以改造BeanDefinition
@Data
public class BeanDefinition {
private Class beanClass;
//补充属性
private PropertyValues propertyValues;
//这里升级为只传类型,而不是实例 在需要的时候才去实例化
public BeanDefinition(Class beanClass){
this.beanClass=beanClass;
//如果没有就传个空的 避免后去捞的时候空指针异常
this.propertyValues=new PropertyValues();
}
public BeanDefinition(Class beanClass, PropertyValues propertyValues) {
this.beanClass = beanClass;
this.propertyValues = propertyValues;
}
}
AbstractAutowireCapableBeanFactory
在原本的实例化bean中注入属性
@Getter
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory{
private InstantiationStrategy instantiationStrategy =new CglibSubclassingInstantiationStrategy();
@Override
protected Object createBean(String name, BeanDefinition beanDefinition,Object[] args) throws BeansException {
Object bean;
bean = createBeanInstance(beanDefinition,args);
//补充属性
applyPropertyValues(bean,beanDefinition);
addSingletonBean(name,bean);
return bean;
}
protected Object createBeanInstance( BeanDefinition beanDefinition,Object[] args){
Constructor constructor =null;
Class beanClass = beanDefinition.getBeanClass();
//获取所有的构造方法
Constructor[] declaredConstructors = beanClass.getDeclaredConstructors();
//简单对比 spring还会对比类型
for (Constructor ctor : declaredConstructors) {
if (null!=args && ctor.getParameterTypes().length ==args.length){
constructor=ctor;
break;
}
}
//创建
return getInstantiationStrategy().instantiate(beanDefinition,constructor,args);
}
//手撸05新增
protected void applyPropertyValues(Object bean, BeanDefinition beanDefinition){
//取出填入的属性
PropertyValues propertyValues = beanDefinition.getPropertyValues();
for (PropertyValue propertyValue : propertyValues.getPropertyValues()) {
String name = propertyValue.getName();
Object value = propertyValue.getValue();
//如果是个实例对象
if (value instanceof BeanReference){
BeanReference beanReference=(BeanReference)value;
//通过bean名去获取bean 跳过循环依赖 后面再补充
value = getBean(beanReference.getBeanName());
}
//通过名称注入属性
BeanUtil.setFieldValue(bean,name,value);
}
}
}
然后是业务类 在service中加了个dao
public class UserService {
private String uId;
private UserDao userDao;
public void queryUserInfo(){
System.out.println("查询用户信息:"+userDao.queryUserName(uId));
}
}
在UserDao中简单模拟一下
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);
}
}
然后模拟一下属性注入,以后这些事会用注解来做
@Test
public void applyProperty(){
//初始化 beanFactory
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//注册 Bean
beanFactory.registerBeanDefinition("userDao",new BeanDefinition(UserDao.class));
//模拟属性注入
PropertyValues properties = new PropertyValues();
properties.addPropertyValue(new PropertyValue("uId","10001"));
properties.addPropertyValue(new PropertyValue("userDao", (BeanReference) () -> "userDao"));
BeanDefinition beanDefinition = new BeanDefinition(UserService.class,properties);
beanFactory.registerBeanDefinition("userService",beanDefinition);
UserService userService = (UserService) beanFactory.getBean("userService");
userService.queryUserInfo();
}