暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Spring框架分析之实现自己的framework(下)

Alleria Windrunner 2020-10-01
155
上一篇我们实现了自己的framework的ioc部分的文件加载部分,但是对于getbean()方法我们没有实现,本篇我们就来一起实现下。


getBean方法

首先我们来分析一下getBean()方法的步骤:
  1. 从singletonObjects里面获取指定名称的bean实例。

  2. 如果bean不为空则直接返回,如果bean为空则进行第三步。

  3. 如果bean为空则进行对象创建流程,先获取获取BeanDefinition信息,然后创建bean实例并放入singletonObjects集合中。


示例代码如下:
    @Override
    public Object getBean(String beanName) {
    // 从singletonObjects里面获取指定名称的bean实例
    Object beanInstance = singletonObjects.get(beanName);
    // 如果bean实例不为空,则直接返回
    if (beanInstance != null) {
    return beanInstance;
    }
    // 如果bean实例为空,则进行对象创建流程
    // 获取BeanDefinition信息
    BeanDefination beanDefination = beanDefinations.get(beanName);
    if (beanDefination == null) {
    return null;
    }
    beanInstance = createBean(beanDefination);
    // 将创建好的对象,放入singletonObjects集合中


    return beanInstance;
    }
    那么接下来我们看一下createBean方法的实现,也可以分为三步:
    1. 实例化:new 对象(使用反射去创建实例)

    2. 属性填充:set方法

    3. 初始化:调用初始化方法


    示例代码如下:
      private Object createBean(BeanDefination beanDefination) {
      // 创建对象,分成三步:实例化、属性填充、初始化
      // 实例化:new 对象(使用反射去创建实例)
      Object instanceObject = newObject(beanDefination, null);
      // 属性填充:set方法
      setProperties(beanDefination, instanceObject);
      // 初始化:调用初始化方法
      initObject(beanDefination, instanceObject);

      return instanceObject;
      }

      接下来是newObject,这里直接通过反射创建对象就可以了,示例代码如下:
        private Object newObject(BeanDefination beanDefination, Object[] initargs) {
        Object object = ReflectUtils.createObject(beanDefination.getBeanClassName(), initargs);


        return object;
        }


        /**
        * 反射工具类
        * @author eleven
        * @see
        * @since
        */
        public class ReflectUtils {


        public static Object createObject(String beanClassName, Object... args) {
        try {
        Class<?> clazz = Class.forName(beanClassName);
        Constructor<?> constructor = clazz.getConstructor();
        默认调用无参构造进行对象的创建
        return constructor.newInstance();
        } catch (Exception e) {
        e.printStackTrace();
        }
        return null;
        }


        public static void setProperty(Object beanInstance, String name, Object valueToUse) {
        try {
        Class<?> clazz = beanInstance.getClass();
        Field field = clazz.getDeclaredField(name);
        field.setAccessible(true);
        field.set(beanInstance, valueToUse);
        } catch (Exception e) {
        e.printStackTrace();
        }
        }


        public static Class<?> getTypeByFieldName(String beanClassName, String name) {
        try {
        Class<?> clazz = Class.forName(beanClassName);
        Field field = clazz.getDeclaredField(name);
        return field.getType();
        } catch (Exception e) {
        e.printStackTrace();
        }
        return null;
        }


        public static void invokeMethod(Object beanInstance, String initMethod) {
        try {
        Class<?> clazz = beanInstance.getClass();
        Method method = clazz.getDeclaredMethod(initMethod);
        method.setAccessible(true);
        method.invoke(beanInstance);
        } catch (Exception e) {
        e.printStackTrace();
        }
        }


        }
        可以抽取一个反射工具类出来方便使用。接下来是setProperties()方法了,示例代码如下:
          private void setProperties(BeanDefination beanDefination, Object instanceObject) {
          // 获取PropertyValue集合
          List<PropertyValue> propertyValues = beanDefination.getPropertyValues();
          // 遍历集合,每个PropertyValue进行赋值操作
          if (propertyValues != null && propertyValues.size() > 0) {
          for (PropertyValue propertyValue : propertyValues) {
          setProperty(propertyValue, instanceObject);
          }
          }


          }


          private void setProperty(PropertyValue propertyValue, Object instanceObject) {
          // 取出name和value属性,只是说value属性是Object类型的。
          String name = propertyValue.getName();
          Object value = propertyValue.getValue();
          // 但是真正的value值,包括两种:TypedStringValue、RuntimeBeanReference
          if (name == null || "".equals(name) || value == null || "".equals(value)) {
          return;
          }


          // 此值是一个进行了类型转换之后的值
          Object valueToUse = null;
          if (value instanceof TypedStringValue) {
          TypedStringValue typedStringValue = (TypedStringValue) value;
          String stringValue = typedStringValue.getValue();
          Class<?> targetType = typedStringValue.getTargetType();


          valueToUse = getConvertedValue(stringValue, targetType, valueToUse);


          } else if (value instanceof RuntimeBeanReference) {
          RuntimeBeanReference runtimeBeanReference = (RuntimeBeanReference) value;
          String ref = runtimeBeanReference.getRef();
          // 递归调用,获取依赖的对象
          valueToUse = getBean(ref);
          }
          // 利用反射进行属性的赋值操作
          ReflectUtils.setProperty(instanceObject, name, valueToUse);
          // 以上的value值,无法直接进行用来赋值操作,需要处理之后才可以使用
          // 调用反射进行赋值操作
          }
          这里需要注意的是按照我们之前的分析,bean标签中的属性可以分为两类:
          1. 字符串类型的属性

          2. ref类型的bean引用属性


          我们分别抽象为TypedStringValue和RuntimeBeanReference类型进行处理,示例代码如下:
            public class TypedStringValue {

            private String value;

            private Class<?> targetType;


            public TypedStringValue(String value) {
            this.value = value;
            }


            public String getValue() {
            return value;
            }


            public void setValue(String value) {
            this.value = value;
            }


            public Class<?> getTargetType() {
            return targetType;
            }


            public void setTargetType(Class<?> targetType) {
            this.targetType = targetType;
            }
            }


            /**
            * 引用类型属性
            * @author eleven
            * @see
            * @since
            */


            public class RuntimeBeanReference {


            private String ref;


            public String getRef() {
            return ref;
            }


            public void setRef(String ref) {
            this.ref = ref;
            }


            public RuntimeBeanReference(String ref) {
            super();
            this.ref = ref;
            }
            }
            这里关于ref引用类型的属性直接递归调用我们的getBean方法就可以了。而字符串类型的属性我们需要做类型转换,抽象出一个getConvertedValue()方法,示例代码如下:
              private Object getConvertedValue(String stringValue, Class<?> targetType, Object valueToUse) {
              if (targetType == Integer.class) {
              valueToUse = Integer.parseInt(stringValue);
              } else if (targetType == String.class) {
              valueToUse = stringValue;
              }


              return valueToUse;
              }
              这个地方的if else我们可以使用策略模式处理一下,示例代码如下:
                private Object getConvertedValue(String stringValue, Class<?> targetType, Object valueToUse) {
                // 使用策略模式去改造上面的代码
                for (TypeHandler typeHandler : typeHandlers) {
                if (typeHandler.isHandleThisType(targetType)) {
                valueToUse = typeHandler.convertValue(stringValue);
                }
                }
                return valueToUse;
                }


                /**
                * 数据类型策略Handler
                * @author eleven
                * @see
                * @since
                */




                public interface TypeHandler {


                boolean isHandleThisType(Class<?> targetType);


                Object convertValue(String stringValue);


                }


                /**
                * 整型TypeHandler
                * @author eleven
                * @see
                * @since
                */


                public class IntegerTypeHandler implements TypeHandler {


                @Override
                public boolean isHandleThisType(Class<?> targetType) {
                return targetType == Integer.class;
                }


                @Override
                public Object convertValue(String stringValue) {
                return Integer.parseInt(stringValue);
                }


                }


                /**
                * 字符串类型TypeHandler
                * @author eleven
                * @see
                * @since
                */


                public class StringTypeHandler implements TypeHandler {


                @Override
                public boolean isHandleThisType(Class<?> targetType) {
                return targetType == String.class;
                }


                @Override
                public Object convertValue(String stringValue) {
                return stringValue;
                }


                }


                private void initTypeHandlers() {
                // 此处需要使用配置文件进行动态配置。需要对配置文件进行解析
                // typeHandlers = getBeansByType(TypeHandler.class);


                typeHandlers.add(new IntegerTypeHandler());
                typeHandlers.add(new StringTypeHandler());
                }
                最后在DefaultListableBeanFactory类的构造方法中我们需要初始化TypeHandler,写的标准点的话我们可以使用配置文件进行配置,这里仅做示意初始化两个。
                好了,关于我们自己的framework就模拟这些,接下来几篇我们会一起看下Spring几个重要模块的主要源码。
                文章转载自Alleria Windrunner,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                评论