wap手机网站制作,可以做问卷的网站,旅游网站建设受众分析,出货入货库存的软件文章目录 一、目标#xff1a;注入属性和依赖对象二、设计#xff1a;注入属性和依赖对象三、实现#xff1a;注入属性和依赖对象3.0 引入依赖3.1 工程结构3.2 注入属性和依赖对象类图3.3 定义属性值和属性集合3.3.1 定义属性值3.3.2 定义属性集合 3.4 Bean定义补全3.5 Bean… 文章目录 一、目标注入属性和依赖对象二、设计注入属性和依赖对象三、实现注入属性和依赖对象3.0 引入依赖3.1 工程结构3.2 注入属性和依赖对象类图3.3 定义属性值和属性集合3.3.1 定义属性值3.3.2 定义属性集合 3.4 Bean定义补全3.5 Bean属性填充 四、测试注入属性和依赖对象4.1 用户Bean对象4.1.1 用户Dao对象4.1.2 用户Service对象 4.2 单元测试 五、总结注入属性和依赖对象 一、目标注入属性和依赖对象 已经完成 实现一个容器、定义和注册Bean、实例化Bean、按照是否包含构造函数实现不同的实例化策略那么在创建对象实例化我们还缺少什么 其实还缺少 类中是否有属性的问题如果类中包含属性那么在实例化的时候就需要把属性信息填充上这样才是一个完整的对象创建。对于属性的填充不只是 int、Long、String还包括没有实例化的对象属性都需要在 Bean 创建时进行填充操作。
二、设计注入属性和依赖对象 技术设计注入属性和依赖对象 属性填充是在 Bean 使用 newInstance 或者 cglib 创建后开始补全属性信息那么就可以在类 AbstractAutowireCapableBeanFactory 的 createBean 方法中添加补全属性方法。 属性填充要在类实例化创建之后也就是需要在 AbstractAutowireCapableBeanFactory#createBean 方法中添加 applyPropertyValues 操作。由于需要在创建 Bean 时填充属性操作那么就需要在 bean 定义 BeanDefinition 类中添加 PropertyValues 信息。另外是填充属性信息还包括 Bean 的对象类型也就是需要再定义一个 BeanReference。 里面其实就是一个简单的 Bean 名称再具体的实例化操作时进行递归创建和填充。与 Spring 源码实现一样Spring 源码中 BeanReference 是一个接口。
三、实现注入属性和依赖对象
3.0 引入依赖 pom.xml dependencygroupIdcn.hutool/groupIdartifactIdhutool-all/artifactIdversion5.5.0/version
/dependency3.1 工程结构
spring-step-04
|-src|-main| |-java| |-com.lino.springframework| |-factory| | |-config| | | |-BeanDefinition.java| | | |-BeanReference.java| | | |-SingletonBeanRegistry.java| | |-support| | | |-AbstractAutowireCapableBeanFactory.java| | | |-AbstractBeabFactory.java| | | |-BeanDefinitionRegistry.java| | | |-CglibSubclassingInstantiationStrategy.java| | | |-DefaultListableBeanFactory.java| | | |-DefaultSingletonBeanRegistry.java| | | |-InstantiationStrategy.java| | | |-SimpleInstantiationStrategy.java| | |-BeanFactory.java| |-BeansException.java| |-PropertyValue.java| |-PropertyValues.java|-test|-java|-com.lino.springframework.test|-bean| |-UserDao.java| |-UserService.java|-ApiTest.java3.2 注入属性和依赖对象类图 新增加3个类BeanReference(类引用)、PropertyValue(属性值)、PropertyValues(属性集合)分别用于类和其他类型属性填充操作。另外改动的类主要是 AbstractAutowireCapableBeanFactory在 createBean 中补全属性填充部分。
3.3 定义属性值和属性集合
3.3.1 定义属性值 PropertyValue.java package com.lino.springframework;/*** description: 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;}
}3.3.2 定义属性集合 PropertyValues.java package com.lino.springframework;import java.util.ArrayList;
import java.util.List;/*** description: 属性值集合*/
public class PropertyValues {private final ListPropertyValue propertyValueList new ArrayList();public void addPropertyValue(PropertyValue pv) {this.propertyValueList.add(pv);}public PropertyValue[] getPropertyValues() {return this.propertyValueList.toArray(new PropertyValue[0]);}public PropertyValue getPropertyValue(String propertyName) {for (PropertyValue pv : this.propertyValueList) {if (pv.getName().equals(propertyName)) {return pv;}}return null;}
}这两个类的作用就是创建出一个用于传递类中属性信息的类因为属性可能会有很多所以还需要定义一个集合包装下。
3.4 Bean定义补全 BeanReference.java package com.lino.springframework.factory.config;/*** description: Bean 引用*/
public class BeanReference {private final String beanName;public BeanReference(String beanName) {this.beanName beanName;}public String getBeanName() {return beanName;}
}在 Bean 注册的过程中是需要传递 Bean 的信息。所以为了把属性一定交给 Bean 定义所以这里填充了 PropertyValues 属性同时把两个构造函数做了一些简单的优化避免后面 for 循环时还得判断属性填充是否为空。
3.5 Bean属性填充 AbstractAutowireCapableBeanFactory.java package com.lino.springframework.factory.support;import cn.hutool.core.bean.BeanUtil;
import com.lino.springframework.BeansException;
import com.lino.springframework.PropertyValue;
import com.lino.springframework.PropertyValues;
import com.lino.springframework.factory.config.BeanDefinition;
import com.lino.springframework.factory.config.BeanReference;
import java.lang.reflect.Constructor;/*** description: 实现默认bean创建的抽象bean工厂超类*/
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory {private InstantiationStrategy instantiationStrategy new CglibSubclassingInstantiationStrategy();Overrideprotected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) {Object bean null;try {bean createBeanInstance(beanDefinition, beanName, args);// 给bean填充属性applyPropertyValues(beanName, bean, beanDefinition);} catch (Exception e) {throw new BeansException(Instantiation of bean failed, e);}registerSingletonBean(beanName, bean);return bean;}private 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 getBean(beanReference.getBeanName());}// 属性填充BeanUtil.setFieldValue(bean, name, value);}} catch (Exception e) {throw new BeansException(Error setting property values: beanName);}}protected Object createBeanInstance(BeanDefinition beanDefinition, String beanName, Object[] args) {Constructor constructorToUse null;Class? beanClass beanDefinition.getBeanClass();Constructor?[] declaredConstructors beanClass.getDeclaredConstructors();for (Constructor ctor : declaredConstructors) {if (null ! args ctor.getParameterTypes().length args.length) {constructorToUse ctor;break;}}return getInstantiationStrategy().instantiate(beanDefinition, beanName, constructorToUse, args);}public InstantiationStrategy getInstantiationStrategy() {return instantiationStrategy;}public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy) {this.instantiationStrategy instantiationStrategy;}
}这个类主要包括三个方法createBean、createBeanInstance、applyPropertyValues这里我们主要关注 createBean 的方法中调用的 applyPropertyValues 方法。在 applyPropertyValues 中通过获取 beanDefinition.getPropertyValues() 循环进行属性填充操作。 如果遇到的是 BeanReference那么就需要递归获取 Bean 实例调用 getBean 方法。 当把依赖的 Bean 对象创建完成后会递归回现在属性填充中。
四、测试注入属性和依赖对象
4.1 用户Bean对象
4.1.1 用户Dao对象 UserDao.java package com.lino.springframework.test.bean;import java.util.HashMap;
import java.util.Map;/*** description: 模拟用户DAO类*/
public class UserDao {private static MapString, String hashMap new HashMap();static {hashMap.put(10001, 张三);hashMap.put(10002, 李四);hashMap.put(10003, 王五);}public String queryUserName(String uId) {return hashMap.get(uId);}
}4.1.2 用户Service对象 UserServce.java package com.lino.springframework.test.bean;/*** description: 模拟用户 Bean 对象*/
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;}
}在 UserService 中注入 UserDao这样就能体现出 Bean 属性的依赖。
4.2 单元测试 ApiTest.java Test
public void test_BeanFactory() {// 1.初始化 BeanFactoryDefaultListableBeanFactory beanFactory new DefaultListableBeanFactory();// 2.UserDao注册beanFactory.registerBeanDefinition(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 注入beanBeanDefinition beanDefinition new BeanDefinition(UserService.class, propertyValues);beanFactory.registerBeanDefinition(userService, beanDefinition);// 5.获取beanUserService userService (UserService) beanFactory.getBean(userService);userService.queryUserInfo();
}与直接获取 Bean 对象不同这次我们还需要先把 userDao 注入到 Bean 容器中。 beanFactory.registerBeanDefinition(userDao, new BeanDefinition(UserDao.class))。 接下来就是属性填充的操作。 一种是普通属性new PropertyValue(uId, 10001)。另外一种是对象属性new PropertyValue(userDao, new BeanReference(userDao))。 最后是正常获取 userService 对象调用方法即可。 测试结果 查询用户信息: 张三从测试结果来看属性填充已经起作用了因为只有属性填充后才能调用到 Dao 方法如userDao.queryUserName(uId)。
五、总结注入属性和依赖对象
本章对 AbstructAutowireCapableBeanFactory 类中的创建对象功能又做了扩充依赖于是否有构造函数的实例化策略完成后。 开始补充 Bean 属性信息。当遇到 Bean 属性为 Bean 对象时需要递归处理。最后在属性填充时需要用到反射操作也可以使用一些工具类处理。