> 文档中心 > 纯手写SpringFramework-完结版(原创)

纯手写SpringFramework-完结版(原创)


个人简介

作者是一个来自河源的大三在校生,以下笔记都是作者自学之路的一些浅薄经验,如有错误请指正,将来会不断的完善笔记,帮助更多的Java爱好者入门。

文章目录

    • 个人简介
    • 纯手写SpringFramework-完结版
      • 详细介绍Spring是什么?
      • 这一代的Spring新增了什么?
      • 手写Spring的生命周期
      • 项目结构图
      • pom.xml
      • MyClassPathXmlApplicationContext底层核心
        • 细节-1
        • 细节-2
        • 细节-3
        • 细节-4
        • 细节-5
        • 细节-6
        • 细节-7
      • MyClassPathXmlApplicationContext源码
      • 使用教程
        • xml配置文件
        • 测试类

纯手写SpringFramework-完结版

详细介绍Spring是什么?

  • 再来介绍一下什么是Spring,一方面为了字数防止限流、另一方面是为了有的朋友直接看第二代手写SpringFramework而不知道什么是Spring。为了防止这种情况(之后的每一篇都要介绍一下伟大的Spring),当然这是题外话了=__=

Spring是一个开源框架,它由Rod Johnson创建。它是为了解决企业应用开发的复杂性而创建的。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。

Spring是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器框架。

轻量——从大小与开销两方面而言Spring都是轻量的。完整的Spring框架可以在一个大小只有1MB多的JAR文件里发布。并且Spring所需的处理开销也是微不足道的。此外,Spring是非侵入式的:典型地,Spring应用中的对象不依赖于Spring的特定类。

控制反转——Spring通过一种称作控制反转(IoC)的技术促进了松耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IoC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它。

面向切面——Spring提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。

容器——Spring包含并管理应用对象的配置和生命周期,在这个意义上它是一种容器,你可以配置你的每个bean如何被创建——基于一个可配置原型(prototype),你的bean可以创建一个单独的实例或者每次需要时都生成一个新的实例——以及它们是如何相互关联的。然而,Spring不应该被混同于传统的重量级的EJB容器,它们经常是庞大与笨重的,难以使用。

框架——Spring可以将简单的组件配置、组合成为复杂的应用。在Spring中,应用对象被声明式地组合,典型地是在一个XML文件里。Spring也提供了很多基础功能(事务管理、持久化框架集成等等),将应用逻辑的开发留给了你。

MVC——Spring的作用是整合,但不仅仅限于整合,Spring 框架可以被看做是一个企业解决方案级别的框架。客户端发送请求,服务器控制器(由DispatcherServlet实现的)完成请求的转发,控制器调用一个用于映射的类HandlerMapping,该类用于将请求映射到对应的处理器来处理请求。HandlerMapping 将请求映射到对应的处理器Controller(相当于Action)在Spring 当中如果写一些处理器组件,一般实现Controller 接口,在Controller 中就可以调用一些Service 或DAO 来进行数据操作 ModelAndView 用于存放从DAO 中取出的数据,还可以存放响应视图的一些数据。 如果想将处理结果返回给用户,那么在Spring 框架中还提供一个视图组件ViewResolver,该组件根据Controller 返回的标示,找到对应的视图,将响应response 返回给用户。

(以上摘选自:《百度百科》)

这一代的Spring新增了什么?

  • 1:提供了基于XML配置文件管理bean。目前实现的XML配置文件功能有:
    • 1.1:目前实现的标签有:my-beans、my-bean、my-properties、my-ref
  • 2:新增了Spring容器的另外一个实现类:MyClassPathXmlApplicationContext

手写Spring的生命周期

  • 推断构造方法(这里我全都采用无參构造)->创建bean对象->DI依赖注入->Aware回调(BeanName和BeanFactory)->初始化前->初始化->初始化后(AOP)
  • 我们的Spring并没有实现完整的生命周期,所以很多并不完善。后面应该不会继续完善这个生命周期。以上的生命周期均已实现

项目结构图

在这里插入图片描述
在这里插入图片描述

pom.xml

<dependencies> <!-- https://mvnrepository.com/artifact/cglib/cglib --> <dependency>     <groupId>cglib</groupId>     <artifactId>cglib</artifactId>     <version>3.3.0</version> </dependency> <!-- https://mvnrepository.com/artifact/org.dom4j/dom4j --> <dependency>     <groupId>org.dom4j</groupId>     <artifactId>dom4j</artifactId>     <version>2.1.3</version> </dependency>    </dependencies>
  • 1:cglib:用来做动态代理。Spring的底层亦是如此
  • 2:dom4j:用来操作XML文件。dom4j也可以说是目前最好用的操作XML文件的工具了,且此项目中会大量用到。

MyClassPathXmlApplicationContext底层核心

细节-1

public class MyClassPathXmlApplicationContext implements ApplicationContext {}
  • 说明MyClassPathXmlApplicationContext是ApplicationContext的实现类,可以通过多态的方式创建对象

细节-2

    private ConcurrentHashMap<String,BeanDefinition> beanDefinitionMap;private ConcurrentHashMap<String,Object> singletonMap; private CopyOnWriteArrayList<BeanPostProcessor> beanPostProcessors;     private List<Element> elements;
  • beanDefinitionMap:bean定义Map
  • singletonObjects:单例池,也就是Spring的一级缓存
  • beanPostProcessors:beanPostProcessors集合
  • elements:root结点下一个结点的集合

细节-3

     String uri=this.getClass().getResource("/spring/"+configLocation).toURI().getPath();     String scp = uri.substring(1, uri.length());   SAXReader saxReader=new SAXReader();   Document document = saxReader.read(new File(scp));   Element rootElement = document.getRootElement();   if(!rootElement.getName().equals("my-beans")){  throw new NullPointerException("标签不正确");     }   ClassLoader classLoader = this.getClass().getClassLoader();   elements = rootElement.elements();
  • 获取扫描xml文件,只扫描resources目录下的spring目录
  • 通过SAX阅读器去加载XML配置文件,并获取该XML配置文件的root结点也就是my-beans标签
  • 然后校验标签是否正确,如果标签不正确则抛出异常
  • 通过当前对象的类去拿到类加载器(ClassLoader)
  • 获取root结点的下一级结点的集合并且赋值给全局变量elements

细节-4

for (Element element : elements) {    if(!element.getName().equals("my-bean")){      throw new NullPointerException("标签不正确");  }  //beanName  String beanName=null;  //定义一个BeanDefinition  BeanDefinition beanDefinition = new BeanDefinition();    List<Attribute> attributes = element.attributes();    for (Attribute attribute : attributes) {    if(attribute.getName().equals("id")){   beanName=attribute.getValue();      }else if(attribute.getName().equals("class")){   Class<?> aClass = classLoader.loadClass(attribute.getValue());      if (BeanPostProcessor.class.isAssignableFrom(aClass)) {BeanPostProcessor obj = (BeanPostProcessor) aClass.getConstructor().newInstance();beanPostProcessors.add(obj);   }   beanDefinition.setType(aClass);      }else if(attribute.getName().equals("scope")){   beanDefinition.setScope(attribute.getValue());      }else {   throw new NullPointerException("属性不正确");      }  }  beanDefinitionMap.put(beanName,beanDefinition);     }
  • 遍历root结点的下一级结点,这个结点其实就是我们定义的一个个bean
  • 校验标签的正确性,不正确则抛出异常
  • 定义局部变量beanName和BeanDefinition(存储bean所属类、单例还是多例)
  • 获取root结点的下一级结点的属性,并进行遍历
  • 通过attribute.getValue()给beanName赋值、classLoader.loadClass(attribute.getValue())给BeanDefinition的type赋值、和beanDefinition.setScope(attribute.getValue())
  • 并且判断这个类是否实现BeanPostProcessor接口,如果有则单独创建一个对象放到beanPostProcessors集合中。
  • 扫描到此结束

细节-5

ConcurrentHashMap.KeySetView<String, BeanDefinition> keySet = beanDefinitionMap.keySet();     //加载入单例池     for (String beanName : keySet) {  BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);  String scope = beanDefinition.getScope();  if(scope!=null&&scope.equals(ScopeType.PROTOTYPE)){      //不做任何事  }else {      if(!singletonObjects.containsKey(beanName)){   Object obj = createBean(beanName);   singletonObjects.put(beanName,obj);      }  }     }
  • 遍历beanDefinitionMap,找出所有单例的BeanDefinition对象,然后将其加载入单例池。

细节-6

for (Element element : elements) {    String curBeanName = element.attributeValue("id");    xxx}
  • 遍历elements集合(二级标签),获取当前beanName,通过判断beanName(也就是需要创建bean的bean名)和curBeanName(当前遍历到的bean名相比较)找出需要创建的bean。

细节-7

   List<Element> els = element.elements();   for (Element el : els) {      if(el.getName().equals("my-properties")){ if(el.element("my-ref")!=null){ String fieldName = el.attributeValue("name"); String bn = el.element("my-ref").attributeValue("bean"); Field field = aClass.getDeclaredField(fieldName); field.setAccessible(true);  if(singletonObjects.containsKey(bn)){  Object beanObj = singletonObjects.get(bn);     field.set(obj,beanObj); } else{  Object createBean = createBean(bn);     field.set(obj,createBean); }    }else{ List<Attribute> attributes = el.attributes(); //用于保存注入的字段 String field=null; //用于保存注入的值 String val=null; for (Attribute attribute : attributes) {     if(attribute.getName().equals("name")){  field=attribute.getValue();     }else if(attribute.getName().equals("value")){  val=attribute.getValue();     }else {  throw new NullPointerException("请检查定义bean的属性");     } }  Field fd = aClass.getDeclaredField(field); fd.setAccessible(true);  String type = fd.getType().getName().toLowerCase(); if(type.equals("byte")||type.equals("java.lang.byte")){     fd.set(obj,Byte.parseByte(val)); }else if(type.equals("short")||type.equals("java.lang.short")){     fd.set(obj,Short.parseShort(val)); }else if(type.equals("int")||type.equals("java.lang.integer")){     fd.set(obj,Integer.parseInt(val)); }else if(type.equals("long")||type.equals("java.lang.long")){     fd.set(obj,Long.parseLong(val)); }else if(type.equals("double")||type.equals("java.lang.double")){     fd.set(obj,Double.parseDouble(val)); }else if(type.equals("float")||type.equals("java.lang.float")){     fd.set(obj,Float.parseFloat(val)); }else if(type.equals("char")){     fd.set(obj,val.charAt(0)); }else if(type.equals("boolean")||type.equals("java.lang.boolean")){     if(val.equals("true")){  fd.set(obj,true);     }else{  fd.set(obj,false);     } }else if(type.equals("java.lang.string")){     fd.set(obj,val); } else{     throw new NullPointerException("暂不支持这个字段类型"); }    }}else {    throw new NullPointerException("请检查注入属性的标签");}   }
  • 获取当前二级标签(my-bean)的第三级标签(my-properties)集合
  • 遍历这个三级标签集合,判断这个标签的子标签是否是my-ref标签
  • 如果含有my-ref标签的话,则通过bn去单例池里面找是否有这个对象,单例池如果有的话则用单例池的;
  • 单例池如果没有则直接调用createBean方法创建对象并赋值
  • 如果没有my-ref标签的话,就拿出他的name和value属性,通过这个name匹配它的实体类中字段名为这个name的字段。
  • 为了防止注入报错,我们对注入的所有基本数据类型+String进行判断(变小写再判断)
  • 然后接下来就是Aware回调和初始化前、初始化、初始化后、如果是单例则放入单例池的操作,这里省略了不写了。

MyClassPathXmlApplicationContext源码

package com.springframework.core.context;import com.springframework.core.constant.ScopeType;import org.dom4j.Attribute;import org.dom4j.Document;import org.dom4j.DocumentException;import org.dom4j.Element;import org.dom4j.io.SAXReader;import java.io.File;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.net.URISyntaxException;import java.net.URL;import java.util.Arrays;import java.util.List;import java.util.Objects;import java.util.Optional;import java.util.concurrent.ConcurrentHashMap;import java.util.concurrent.CopyOnWriteArrayList;import java.util.stream.Stream;/** * 纯手写ClassPathXmlApplicationContext * @author 游政杰 * TODO: 2022/3/22 *///说明MyClassPathXmlApplicationContext是ApplicationContext的实现类,可以通过多态的方式创建对象public class MyClassPathXmlApplicationContext implements ApplicationContext {    //bean定义Map    private ConcurrentHashMap<String,BeanDefinition> beanDefinitionMap;    //单例池,也就是Spring的一级缓存    private ConcurrentHashMap<String,Object> singletonObjects;    //beanPostProcessors集合    private CopyOnWriteArrayList<BeanPostProcessor> beanPostProcessors;    //root结点下一个结点的集合    private List<Element> elements;    //私有化构造器    private MyClassPathXmlApplicationContext(){    }    public MyClassPathXmlApplicationContext(String configLocation){ this.beanDefinitionMap=new ConcurrentHashMap<>(); this.singletonObjects=new ConcurrentHashMap<>(); this.beanPostProcessors=new CopyOnWriteArrayList<>(); try {     //获取扫描xml文件,只扫描resources目录下的spring目录     String uri=this.getClass().getResource("/spring/"+configLocation).toURI().getPath();     String scp = uri.substring(1, uri.length());     //通过SAX阅读器去加载XML配置文件,并获取该XML配置文件的root结点也就是my-beans标签     //然后校验标签是否正确,如果标签不正确则抛出异常     //通过当前对象的类去拿到类加载器(ClassLoader)     //获取root结点的下一级结点的集合并且赋值给全局变量elements     //创建SAX阅读器     SAXReader saxReader=new SAXReader();     //加载XML文件     Document document = saxReader.read(new File(scp));     //获取root结点     Element rootElement = document.getRootElement();     //校验标签的正确性     if(!rootElement.getName().equals("my-beans")){  throw new NullPointerException("标签不正确");     }     //获取类加载器     ClassLoader classLoader = this.getClass().getClassLoader();     //获取root结点的下一级结点的集合     elements = rootElement.elements();     //遍历root结点的下一级结点,这个结点就是我们定义的一个个bean     for (Element element : elements) {  //校验标签的正确性  if(!element.getName().equals("my-bean")){      throw new NullPointerException("标签不正确");  }  //beanName  String beanName=null;  //定义一个BeanDefinition  BeanDefinition beanDefinition = new BeanDefinition();  //获取root结点的下一级结点的属性  List<Attribute> attributes = element.attributes();  //root结点的下一级结点的属性的值  for (Attribute attribute : attributes) {      //分别找出id、class、scope属性      if(attribute.getName().equals("id")){   beanName=attribute.getValue();      }else if(attribute.getName().equals("class")){   Class<?> aClass = classLoader.loadClass(attribute.getValue());   //判断这个类是否实现BeanPostProcessor   if (BeanPostProcessor.class.isAssignableFrom(aClass)) {BeanPostProcessor obj = (BeanPostProcessor) aClass.getConstructor().newInstance();beanPostProcessors.add(obj);   }   beanDefinition.setType(aClass);      }else if(attribute.getName().equals("scope")){   beanDefinition.setScope(attribute.getValue());      }else {   throw new NullPointerException("属性不正确");      }  }  beanDefinitionMap.put(beanName,beanDefinition);     }     //扫描结束     ConcurrentHashMap.KeySetView<String, BeanDefinition> keySet = beanDefinitionMap.keySet();     //加载入单例池     for (String beanName : keySet) {  BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);  String scope = beanDefinition.getScope();  if(scope!=null&&scope.equals(ScopeType.PROTOTYPE)){      //不做任何事  }else {      if(!singletonObjects.containsKey(beanName)){   Object obj = createBean(beanName);   singletonObjects.put(beanName,obj);      }  }     } } catch (URISyntaxException e) {     e.printStackTrace(); } catch (DocumentException e) {     e.printStackTrace(); } catch (ClassNotFoundException e) {     e.printStackTrace(); } catch (InvocationTargetException e) {     e.printStackTrace(); } catch (InstantiationException e) {     e.printStackTrace(); } catch (IllegalAccessException e) {     e.printStackTrace(); } catch (NoSuchMethodException e) {     e.printStackTrace(); }    }    @Override    public Object getBean(String beanName) { BeanDefinition beanDefinition = beanDefinitionMap.get(beanName); if(beanDefinition==null){     return null; }else {     String scope = beanDefinition.getScope();     //如果是多例     if(scope!=null&&scope.equals(ScopeType.PROTOTYPE)){  return createBean(beanName);     }else {//如果是单例的话先去单例池中找  Object obj = singletonObjects.get(beanName);  //如果单例池没有  if(obj==null){      obj=createBean(beanName);  }else {//单例池有的话直接返回obj      return obj;  }     } } return null;    }    private Object createBean(String beanName) { BeanDefinition beanDefinition = beanDefinitionMap.get(beanName); if(beanDefinition==null){     throw new NullPointerException("创建bean失败");//     return null; }else {     try {  //依赖注入,二级标签,这既是一个个bean  for (Element element : elements) {      //遍历获取当前beanName      String curBeanName = element.attributeValue("id");      if(curBeanName.equals(beanName)){   Class<?> aClass = beanDefinition.getType();   //反射创建对象   Object obj = aClass.getConstructor().newInstance();   //注入的属性集,也就是第三级标签   List<Element> els = element.elements();   for (Element el : els) {//只有这种情况才合法,因为我们目前只支持my-properties标签注入if(el.getName().equals("my-properties")){    //判断这个标签的子标签是否是my-ref标签    if(el.element("my-ref")!=null){ String fieldName = el.attributeValue("name"); String bn = el.element("my-ref").attributeValue("bean"); Field field = aClass.getDeclaredField(fieldName); field.setAccessible(true); //通过bn去单例池里面找是否有 if(singletonObjects.containsKey(bn)){     //单例池如果有则用单例池的     Object beanObj = singletonObjects.get(bn);     field.set(obj,beanObj); } else{     //直接调用createBean方法创建对象并赋值     Object createBean = createBean(bn);     field.set(obj,createBean); }    }else{ List<Attribute> attributes = el.attributes(); //用于保存注入的字段 String field=null; //用于保存注入的值 String val=null; for (Attribute attribute : attributes) {     if(attribute.getName().equals("name")){  field=attribute.getValue();     }else if(attribute.getName().equals("value")){  val=attribute.getValue();     }else {  throw new NullPointerException("请检查定义bean的属性");     } } //此时进行依赖注入,必须要是getDeclaredField方法 Field fd = aClass.getDeclaredField(field); fd.setAccessible(true); //为了防止注入报错,我们对注入的所有基本数据类型+String进行判断(变小写再判断) String type = fd.getType().getName().toLowerCase(); if(type.equals("byte")||type.equals("java.lang.byte")){     fd.set(obj,Byte.parseByte(val)); }else if(type.equals("short")||type.equals("java.lang.short")){     fd.set(obj,Short.parseShort(val)); }else if(type.equals("int")||type.equals("java.lang.integer")){     fd.set(obj,Integer.parseInt(val)); }else if(type.equals("long")||type.equals("java.lang.long")){     fd.set(obj,Long.parseLong(val)); }else if(type.equals("double")||type.equals("java.lang.double")){     fd.set(obj,Double.parseDouble(val)); }else if(type.equals("float")||type.equals("java.lang.float")){     fd.set(obj,Float.parseFloat(val)); }else if(type.equals("char")){     fd.set(obj,val.charAt(0)); }else if(type.equals("boolean")||type.equals("java.lang.boolean")){     if(val.equals("true")){  fd.set(obj,true);     }else{  fd.set(obj,false);     } }else if(type.equals("java.lang.string")){     fd.set(obj,val); } else{     throw new NullPointerException("暂不支持这个字段类型"); }    }}else {    throw new NullPointerException("请检查注入属性的标签");}   }   //依赖注入完成之后   //判断对象是否需要Aware回调   if(obj instanceof Aware){//再具体判断是什么回调if(obj instanceof BeanNameAware){    ((BeanNameAware) obj).setBeanName(beanName);}   }   //初始化前   for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {beanPostProcessor.postProcessorBeforeInitialization(obj,beanName);   }   //初始化   if(obj instanceof InitializingBean){((InitializingBean) obj).afterPropertiesSet();   }   //初始化后   for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {beanPostProcessor.postProcessorAfterInitialization(obj,beanName);   }   //如果是单例就放入单例池   if(beanDefinition.getScope()==null||beanDefinition.getScope().equals(ScopeType.SINGLETON)){singletonObjects.put(beanName,obj);   }   return obj;      }      }     } catch (InstantiationException e) {  e.printStackTrace();     } catch (IllegalAccessException e) {  e.printStackTrace();     } catch (InvocationTargetException e) {  e.printStackTrace();     } catch (NoSuchMethodException e) {  e.printStackTrace();     } catch (NoSuchFieldException e) {  e.printStackTrace();     }     //如果找不到就会返回null     return null; }    }}

使用教程

xml配置文件

<my-beans>    <my-bean id="orderBean1" class="com.springframework.core.service.impl.OrderServiceImpl" > <my-properties name="aByte" value="111"/> <my-properties name="aShort" value="222"/> <my-properties name="aInt" value="333"/> <my-properties name="aLong" value="6666"/> <my-properties name="aDouble" value="123.123"/> <my-properties name="aFloat" value="233.567"/> <my-properties name="aChar" value="c"/> <my-properties name="aBoolean" value="true"/> <my-properties name="aString" value="8大基本数据类型与String的注入测试"/>    </my-bean>    <my-bean id="orderBean2" class="com.springframework.core.service.impl.OrderServiceImpl" scope="prototype"> <my-properties name="aByte" value="111"/> <my-properties name="aShort" value="222"/> <my-properties name="aInt" value="333"/> <my-properties name="aLong" value="6666"/> <my-properties name="aDouble" value="123.123"/> <my-properties name="aFloat" value="233.567"/> <my-properties name="aChar" value="c"/> <my-properties name="aBoolean" value="true"/> <my-properties name="aString" value="8大基本数据类型与String的注入测试---prototype"/>    </my-bean>    <my-bean id="userBean1" class="com.springframework.core.service.impl.UserServiceImpl" scope="singleton"> <my-properties name="orderServiceImpl">     <my-ref bean="orderBean2"/> </my-properties>    </my-bean>    <my-bean id="myBeanPostProcess" class="com.springframework.core.service.impl.MyBeanPostProcess" scope="singleton">    </my-bean></my-beans>

测试类

ApplicationContext applicationContext=new MyClassPathXmlApplicationContext("spring-service.xml"); OrderService orderBean1 = (OrderService) applicationContext.getBean("orderBean1"); System.out.println(orderBean1); System.out.println(orderBean1.hashCode()); OrderService orderBean2 = (OrderService) applicationContext.getBean("orderBean2"); System.out.println(orderBean2); System.out.println(orderBean2.hashCode()); UserService userBean1 = (UserService) applicationContext.getBean("userBean1"); System.out.println(userBean1);//      singleton System.out.println(applicationContext.getBean("orderBean1").hashCode()); System.out.println(applicationContext.getBean("orderBean1").hashCode()); System.out.println(applicationContext.getBean("orderBean1").hashCode()); System.out.println("----多例---"); //prototype System.out.println(applicationContext.getBean("orderBean2").hashCode()); System.out.println(applicationContext.getBean("orderBean2").hashCode()); System.out.println(applicationContext.getBean("orderBean2").hashCode());

输出结果

postProcessorBeforeInitializationpostProcessorAfterInitializationpostProcessorBeforeInitializationpostProcessorAfterInitializationpostProcessorBeforeInitialization初始化Bean...postProcessorAfterInitializationpostProcessorBeforeInitialization初始化beanpostProcessorAfterInitializationOrderServiceImpl{aByte=111, aShort=222, aInt=333, aLong=6666, aDouble=123.123, aFloat=233.567, aChar=c, aBoolean=true, aString='8大基本数据类型与String的注入测试'}1136497418postProcessorBeforeInitializationpostProcessorAfterInitializationOrderServiceImpl{aByte=111, aShort=222, aInt=333, aLong=6666, aDouble=123.123, aFloat=233.567, aChar=c, aBoolean=true, aString='8大基本数据类型与String的注入测试---prototype'}863125040UserServiceImpl{orderServiceImpl=OrderServiceImpl{aByte=111, aShort=222, aInt=333, aLong=6666, aDouble=123.123, aFloat=233.567, aChar=c, aBoolean=true, aString='8大基本数据类型与String的注入测试---prototype'}, beanName='userBean1'}113649741811364974181136497418----多例---postProcessorBeforeInitializationpostProcessorAfterInitialization949057310postProcessorBeforeInitializationpostProcessorAfterInitialization2024542466postProcessorBeforeInitializationpostProcessorAfterInitialization770189387