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

举报
摸鱼打酱油 发表于 2022/04/01 22:25:09 2022/04/01
【摘要】 个人简介作者是一个来自河源的大三在校生,以下笔记都是作者自学之路的一些浅薄经验,如有错误请指正,将来会不断的完善笔记,帮助更多的Java爱好者入门。@[toc] 纯手写SpringFramework-完结版 详细介绍Spring是什么?再来介绍一下什么是Spring,一方面为了字数防止限流、另一方面是为了有的朋友直接看第二代手写SpringFramework而不知道什么是Spring。为了...

个人简介

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

@[toc]

纯手写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配置文件

<?xml version="1.0" encoding="UTF-8"?>

<!-- 手写Spring基于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>
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。