my-mini-spring
项目的Github地址:github仓库
Gitee地址:gitee仓库
个人博客地址:sillybaka的博客
此篇所在的分支为:bean-property-injection
该篇实现了根据beanDefinition对bean进行实例化的策略方法、以及属性注入
简单的IOC容器
1、 实例化Bean的策略模式
Bean的实例化模式可以分为两个:
- 使用jdk的反射获取类的构造函数来实例化
- 使用Cglib动态代理来生成实例对象
InstantiationStrategy(策略接口)
public interface InstantiationStrategy {
/**
* 使用某种策略实例化Bean对象
* @param beanDefinition
* @param <T>
* @return
*/
<T> T instantiation(BeanDefinition<T> beanDefinition);
}
CglibSubclassingInstantiationStrategy(Cglib实例化bean,未实现)
public class CglibSubclassingInstantiationStrategy implements InstantiationStrategy {
@Override
public <T> T instantiation(BeanDefinition<T> beanDefinition) {
return null;
}
}
SimpleInstantiationStrategy(Jdk实例化bean,只实现这个)
public class SimpleInstantiationStrategy implements InstantiationStrategy {
@Override
public <T> T instantiation(BeanDefinition<T> beanDefinition) {
Class<T> clazz = beanDefinition.getType();
T instance = null;
try {
Constructor<T> constructor = clazz.getDeclaredConstructor();
instance = constructor.newInstance();
} catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
return instance;
}
}
2、 为Bean对象注入普通属性(底层使用setter注入)
使用PropertyValue类存每一对属性(Key-Value类型) 比用Map存更灵活
使用PropertyValues存每一个对象的所有PropertyValue(相当于一个工具类)
使用 属性名 通过反射获取属性的类型然后再获取该属性的Setter方法,再反射调用Setter方法进行注入
但实际上Spring中使用的是PropertyDescritor(底层原理,将Bean类的所有属性类型、名字读取到一个hashmap里,然后就可以通过属性名字来获取某属性的setter、getter等方法)
PropertyValue(表示Bean中的一个属性)
public class PropertyValue {
/**
* 属性名字
*/
private String propertyName;
/**
* 属性值
*/
private Object propertyValue;
}
PropertyValues(表示bean的所有属性)
public class PropertyValues {
private final List<PropertyValue> propertyValueList = new ArrayList<>();
public void addPropertyValue(PropertyValue pv){
if(pv == null){
throw new IllegalArgumentException("初始化bean添加的属性不能为空");
}
for (int i = 0; i < propertyValueList.size(); i++) {
if(propertyValueList.get(i).getPropertyName().equals(pv.getPropertyName())){
// 覆盖已有的属性值
propertyValueList.set(i,pv);
return;
}
}
// 否则就添加
propertyValueList.add(pv);
}
public PropertyValue[] getPropertyValues(){
return propertyValueList.toArray(new PropertyValue[0]);
}
}
PropertyUtil(用于获取属性getter、setter的工具类)
public class PropertyUtils {
/**
* 使用Bean类获取其所有属性的PropertyDescriptor Map
*/
private static final Map<Class<?>, Map<String,PropertyDescriptor>> BEANS_PROPERTY_MAP;
/**
* 冗余项:用于获取Bean类的每种属性类型
*/
private static final Map<Class<?>, Map<String,Class<?>>> BEANS_PROPERTY_TYPE_MAP;
static {
BEANS_PROPERTY_MAP = new HashMap<>();
BEANS_PROPERTY_TYPE_MAP = new HashMap<>();
}
public static void addBeanPropertyMap(Class<?> clazz, Map<String,PropertyDescriptor> map){
BEANS_PROPERTY_MAP.putIfAbsent(clazz,map);
}
/**
* 根据指定类的clazz获取其propertyDescriptorMap
* @param clazz
* @return
*/
public static Map<String,PropertyDescriptor> getBeanPropertyMap(Class<?> clazz){
Map<String, PropertyDescriptor> descriptorMap = BEANS_PROPERTY_MAP.get(clazz);
if(descriptorMap == null){
// 懒汉式单例加载
synchronized (PropertyUtils.class){
descriptorMap = BEANS_PROPERTY_MAP.get(clazz);
if(descriptorMap == null){
addPropertyDescriptor(clazz);
}
descriptorMap = BEANS_PROPERTY_MAP.get(clazz);
}
}
return descriptorMap;
}
/**
* 根据指定类的class将其所有属性的PropertyDescriptor添加到map中 (没有内嵌Bean的才能调用)
* 生命周期开始为在XMl扫描时按需调用,只能注入基本属性
* @param clazz 指定类的class
*/
public static void addPropertyDescriptor(Class<?> clazz){
Map<String, PropertyDescriptor> descriptorMap = BEANS_PROPERTY_MAP.get(clazz);
if(descriptorMap == null){
BEANS_PROPERTY_MAP.putIfAbsent(clazz,new HashMap<>());
descriptorMap = BEANS_PROPERTY_MAP.get(clazz);
}
// 获取该类的所有属性的Descriptor
Field[] fields = clazz.getDeclaredFields();
for(Field field : fields){
String propertyName = field.getName();
try {
Class<?> propertyType = field.getType();
PropertyDescriptor pv = new PropertyDescriptor(propertyName, clazz);
descriptorMap.put(propertyName,pv);
addPropertyType(clazz, propertyName, propertyType);
} catch (IntrospectionException e) {
e.printStackTrace();
}
}
}
/**
* 根据指定类的的class和propertyName添加PropertyDescriptor到map中,可以指定property类型
* @param clazz 指定类的class
* @param propertyName 属性名
* @param anotherType 若不为空 则设置为该property的别类型
*/
public static void addPropertyDescriptor(Class<?> clazz, String propertyName, @Nullable Class<?> anotherType){
PropertyDescriptor pd;
try {
Field field = clazz.getDeclaredField(propertyName);
Class<?> propertyType = field.getType();
pd = new PropertyDescriptor(propertyName, clazz);
// 添加进map中
Map<String, PropertyDescriptor> descriptorMap = BEANS_PROPERTY_MAP.get(clazz);
if(descriptorMap == null){
BEANS_PROPERTY_MAP.putIfAbsent(clazz,new HashMap<>());
descriptorMap = BEANS_PROPERTY_MAP.get(clazz);
}
descriptorMap.put(propertyName,pd);
// 检查是否有设置另外的类型
if(anotherType != null){
addPropertyType(clazz, propertyName, anotherType);
}else {
addPropertyType(clazz,propertyName,propertyType);
}
} catch (NoSuchFieldException | IntrospectionException e) {
e.printStackTrace();
}
}
public static void addPropertyType(Class<?> clazz, String propertyName, Class<?> propertyType){
Map<String, Class<?>> propertyTypeMap = BEANS_PROPERTY_TYPE_MAP.get(clazz);
if(propertyTypeMap == null){
synchronized (PropertyUtils.class){
BEANS_PROPERTY_TYPE_MAP.putIfAbsent(clazz,new HashMap<>());
propertyTypeMap = BEANS_PROPERTY_TYPE_MAP.get(clazz);
}
}
propertyTypeMap.put(propertyName,propertyType);
}
public static Class<?> getPropertyType(Class<?> clazz, String propertyName){
Map<String, Class<?>> propertyTypeMap = BEANS_PROPERTY_TYPE_MAP.get(clazz);
if(propertyTypeMap == null){
throw new IllegalArgumentException("该Bean类型不存在");
}
Class<?> propertyType = propertyTypeMap.get(propertyName);
if(propertyType == null){
throw new IllegalArgumentException("该Bean不存在该属性名: " + propertyName);
}
return propertyType;
}
public static Map<String,Class<?>> getPropertyTypeMap(Class<?> clazz){
Map<String, Class<?>> propertyTypeMap = BEANS_PROPERTY_TYPE_MAP.get(clazz);
if(propertyTypeMap == null){
throw new IllegalArgumentException("该Bean类型不存在");
}
return propertyTypeMap;
}
}
3、 为Bean对象注入Bean属性(有循环依赖风险,后面高级篇解决)
在Spring的xml Bean配置中,是使用beanName和beanType来配置嵌套bean属性的
<bean id="xxx" class="xxx" > <property name="xxx" value="xxx"></property> // 第一种 直接注入(级联) <bean id="xxxx" class="xxxx"> </bean> // 第二种 使用引用注入 <property name="xxx" ref="refXXX"></property> </bean> <bean id="refXXX" class="xxx"> </bean>
- 若是直接注入(级联、内嵌),则相当于再定义了一个Bean,用BeanDefinition存信息,先创建这个内嵌Bean,再赋值给外层Bean**(内部Bean一般是多例的,所以要以多例模式的方式创建)**
- 若是引用注入,则使用一个BeanReference类,记录引用的信息,再获取引用的那个Bean,再复制**(要考虑循环依赖的情况)**(懒汉式,所以不用考虑引用的Bean是否已创建)
BeanReference(用于处理XML配置文件中的bean引用标签)
public class BeanReference {
/**
* bean的名字
*/
private String beanName;
/**
* bean的类型
*/
private String beanType;
}
4、注入Bean属性的实现
AbstractAutowireCapableBeanFactory(自动装配属性的bean工厂)
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory{
private static final InstantiationStrategy INSTANTIATION_STRATEGY = new SimpleInstantiationStrategy();
@Override
protected <T> T createBean( BeanDefinition<T> beanDefinition) {
return doCreateBean(beanDefinition);
}
/**
* 创建Bean实例的实际逻辑
*/
public <T> T doCreateBean(BeanDefinition<T> beanDefinition){
// if(!name.equals(beanName)){
// log.error("BeanName和BeanDefinition中的名字不对应,创建bean实例失败");
// throw new IllegalArgumentException("BeanName和BeanDefinition中的名字不对应,创建bean实例失败");
// }
T beanInstance = INSTANTIATION_STRATEGY.instantiation(beanDefinition);
autoWirePropertyValues(beanInstance,beanDefinition);
return beanInstance;
}
/**
* 为bean实例对象自动装配属性 (底层使用setter注入)
* @param bean 实例对象
* @param beanDefinition bean定义
*/
public <T> void autoWirePropertyValues(T bean, BeanDefinition<T> beanDefinition){
PropertyValues propertyValues = beanDefinition.getPropertyValues();
Class<?> clazz = bean.getClass();
//todo 获取该Bean类的所有PropertyDescriptor --> 生命周期开始为在XMl扫描时按需调用
Map<String, PropertyDescriptor> beanPropertyMap = PropertyUtils.getBeanPropertyMap(clazz);
Map<String, Class<?>> propertyTypeMap = PropertyUtils.getPropertyTypeMap(clazz);
for(PropertyValue pv : propertyValues.getPropertyValues()){
String propertyName = pv.getPropertyName();
Object propertyValue = pv.getPropertyValue();
try {
//todo xml配置中 普通属性不能配置类型 应该以其他方式获取
// Class<?> propertyType = clazz.getDeclaredField(propertyName).getType();
PropertyDescriptor pd = beanPropertyMap.get(propertyName);
// 从属性类型map中获取属性类型
Class<?> propertyType = propertyTypeMap.get(propertyName);
Method setterMethod = pd.getWriteMethod();
// 引用类型
if(propertyType == BeanReference.class){
BeanReference beanReference = (BeanReference) propertyValue;
String beanName = beanReference.getBeanName();
//todo 获取Bean实例 --> 1、有可能该Bean实例尚未创建 应该重写为阻塞等待 (不会有这种情况,因为是懒汉式的设计)
// 2、有可能会发生循环依赖,在后面再解决
Object innerBean = getBean(beanName);
setterMethod.invoke(bean,innerBean);
}else if(propertyType == BeanDefinition.class){
// Bean类型(级联定义了一个Bean)
//todo 先根据Bean定义创建Bean实例 --> 有可能破坏单例 需要保存在多例注册表中
BeanDefinition<?> innerBeanDefinition = (BeanDefinition<?>) propertyValue;
Object innerBean = createBean(innerBeanDefinition);
setterMethod.invoke(bean,innerBean);
}else {
// 普通属性 直接使用Setter方法注入
setterMethod.invoke(bean, propertyValue);
}
} catch (InvocationTargetException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
eBean(innerBeanDefinition);
setterMethod.invoke(bean,innerBean);
}else {
// 普通属性 直接使用Setter方法注入
setterMethod.invoke(bean, propertyValue);
}
} catch (InvocationTargetException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
}