资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,2019/2/1,#,第,15,章,Spring,基础,01,15.1 Spring,入门,02,03,04,05,06,07,15.2,依赖注入,15.3 Spring,容器中的,Bean,15.4,容器中,Bean,的生命周期,15.5,两种后处理器,15.6,装配,Spring Bean,15.7 Spring,的,AOP,本章导读,Spring,致力于,J2EE,应用的各层的解决方案,而不是仅仅专注于某一层的方案。可以说,Spring,是企业应用开发的“一站式”选择,并贯穿表现层、业务层及持久层。然而,Spring,并不想取代那些已有的框架,而是与它们无缝地整合。,01,15.1 Spring,入门,Spring,是于,2003,年兴起的一个,轻量级的,Java,开发框架,,由,Rod Johnson,创建。,Spring,是一个开放源代码的设计层面框架,它解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用。,15.1.1 Spring,概述,01,15.1 Spring,入门,Spring,的源码设计精妙、结构清晰、匠心独运,处处体现着大师对,Java,设计模式灵活运用以及对,Java,技术的高深造诣。,Spring,框架源码无疑是,Java,技术的最佳实践范例,。如果想在短时间内迅速提高自己的,Java,技术水平和应用开发水平,学习和研究,Spring,源码将会使你收到意想不到的效果。,15.1.1 Spring,概述,01,15.1 Spring,入门,Spring,是一个分层架构,,它包含一系列的功能要素,分为大约,20,个模块,这些模块大体分为,Core Container,、,DataAccess/Integration,、,Web,、,AOP,(,Aspect Oriented Programming,,面向切面的编程),Instrumentation,、,Messaging,和,Test,,其结构如图,15-1,所示。,15.1.1 Spring,概述,01,15.1 Spring,入门,15.1.1 Spring,概述,01,15.1 Spring,入门,组成,Spring,框架,的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。这些模块被总结为以下几部分。,15.1.1 Spring,概述,01,15.1 Spring,入门,(,1,)核心容器,核心容器由核心(,Core,)模块、,Beans,模块、上下文(,Context,)模块、和表达式语言(,SpEL,)模块组成,它们的细节如下:,15.1.1 Spring,概述,01,15.1 Spring,入门,(,2,)数据访问,/,集成,数据访问,/,集成层包括,JDBC,、,ORM,、,OXM,、,JMS,和事务处理模块,它们的细节如下:,15.1.1 Spring,概述,01,15.1 Spring,入门,(,3,),Web,Web,层由,Web,、,Web-MVC,、,Web-Socket,和,Web-Portlet,组成,它们的细节如下:,15.1.1 Spring,概述,01,15.1 Spring,入门,(,4,)其他,还有其他一些重要的模块,比如,AOP,、,Aspects,、,Instrumentation,以及测试模块,它们的细节如下:,15.1.1 Spring,概述,01,15.1 Spring,入门,(,1,),BeanFactory,可视为,Spring,的,BeanFactory,容器,它主要的功能是为依赖注入(,Dependency Injection,,简称,DI,)提供支持。这个容器接口在,org.springframework.beans.factory.BeanFactor,中被定义。,BeanFactory,是用于访问,Spring Bean,容器的根接口,是一个单纯的,Bean,工厂,也就是常说的,IOC,容器的顶层定义,,各种,IOC,容器是在其基础上为了满足不同需求而扩展的,包括经常使用的,ApplicationContext,。,15.1.2,使用,Spring,容器,01,15.1 Spring,入门,(,2,),ApplicationContext,ApplicationContext,是,BeanFactory,的子接口,使用它作为,Spring,容器更方便。它可以加载配置文件中定义的,bean,,将所有的,bean,集中在一起,当有请求的时候分配,bean,。,ApplicationContext,包含,BeanFactory,所有的功能,一般情况下,相对于,BeanFactory,,,ApplicationContext,会被推荐使用。,BeanFactory,仍然可以在轻量级应用中使用,比如移动设备或者基于,applet,的应用程序。,15.1.2,使用,Spring,容器,01,15.1 Spring,入门,最常被使用的,ApplicationContext,接口实现:,15.1.2,使用,Spring,容器,01,15.1 Spring,入门,我们一般不会使用,BeanFactory,实例作为,Spring,容器,而是使用,ApplicationContext,实例作为容器,因此也把,Spring,容器称为,Spring,上下文。须注意的是,在使用,Spring,框架的,Web,项目中,,ApplicationContext,容器的实例化工作会交由,Web,服务器来完成。,Web,服务器实例化,ApplicationContext,容器时,通常会使用基于,ContextLoaderListener,实现的方式。,15.1.2,使用,Spring,容器,01,15.1 Spring,入门,【,示例,】,Spring,入门,Spring,配置文件,applicationContext.xml,内容如下:,15.1.2,使用,Spring,容器,01,15.1 Spring,入门,测试类,TestBean.java,主要代码如下:,15.1.2,使用,Spring,容器,01,15.1 Spring,入门,在测试类,TestBean,的,main,方法中,创建并初始化,Spring,容器(通过,Spring,配置文件,applicationContext.xml,),然后通过,Spring,容器获取,Person,实例(,Java,对象),并调用,Person,实例的,say(),方法。,15.1.2,使用,Spring,容器,02,15.2,依赖注入,Spring,框架的核心功能有两个:(,1,),Spring,容器作为超级大工厂,负责创建、管理所有的,Java,对象,这些,Java,对象被称为,Bean,。(,2,),Spring,容器管理容器中,Bean,之间的依赖关系,,Spring,使用一种被称为“,依赖注入,”的方式来管理,Bean,之间的依赖关系。,02,15.2,依赖注入,当某个,Java,实例(调用者)需要另一个,Java,实例(被调用者)时,在传统的程序设计过程中,通常由调用者来创建被调用者的实例。,在依赖注入的模式下,创建被调用者的工作不再由调用者完成,因此称为,控制反转,(,Inversion of Control,,,IoC,);创建被调用者实例的工作通常由,Spring,容器来完成,然后注入调用者,因此也称为,依赖注入,(,Dependency Injection,,简称,DI,)。,02,15.2,依赖注入,依赖注入一般可以分为,3,种方式:构造器注入、,setter,注入和接口注入。,构造器注入,和,setter,注入,是主要的方式,而接口注入则意味着注入的东西来自于外界,例如在,Web,应用中,配置的数据源是在,Tomcat,服务器的,context.xml,文件中配置,然后用,JNDI,的形式通过接口将它注入,Spring IoC,容器中来。,02,15.2,依赖注入,setter,注入(,设值注入,)是指,IoC,容器通过成员变量的,setter,方法来注入被依赖对象。这种注入方式简单、直观,因而在,Spring,的依赖注入里大量使用。,利用构造器来设置依赖关系的方式,被称为,构造器注入,。通俗来说,就是驱动,Spring,在底层以反射方式执行带指定参数的构造器,当执行带参数的构造器时,就可利用构造器参数对成员变量执行初始化,这就是构造器注入的本质。,02,15.2,依赖注入,设值注入有如下优点:,(,1,)与传统的,JavaBean,的写法更相似,程序开发人员更容易理解、接受。通过,setter,方法设定依赖关系显得更加直观、自然。,(,2,)对于复杂的依赖关系,如果采用构造注入,会导致构造器过于臃肿,难以阅读。,Spring,在创建,Bean,实例时,需要同时实例化其依赖的全部实例,因而导致性能下降。而使用设值注入,则能避免这些问题。,(,3,)尤其在某些成员变量可选的情况下,多参数的构造器更加笨重。,02,15.2,依赖注入,构造注入优势如下:,(,1,)构造注入可以在构造器中决定依赖关系的注入顺序,优先依赖的优先注入。,(,2,)对于依赖关系无需变化的,Bean,,构造注入更有用处。因为没有,setter,方法,所有的依赖关系全部在构造器内设定,无须担心后续的代码对依赖关系产生破坏。,(,3,)依赖关系只能在构造器中设定,则只有组件的创建者才能改变组件的依赖关系,对组件的调用者而言,组件内部的依赖关系完全透明,更符合高内聚的原则。,03,15.3 Spring,容器中的,Bean,1,Spring Bean,定义,被称作,Bean,的对象是构成应用程序的支柱。,Bean,是一个被实例化、组装,、并通过,Spring IoC,容器所管理的对象。,对于开发者来说,使用,Spring,框架主要是做两件事:,开发,Bean,;,配置,Bean,。,对于,Spring,框架来说,它要做的就是根据配置文件来创建,Bean,实例,并调用,Bean,实例的方法完成,“,依赖注入,”,,这就是所谓,IoC,的本质,。,03,15.3 Spring,容器中的,Bean,2,Spring Bean,实例化,Spring,容器中的,Bean,实例化有三种方式:构造器实例化、静态工厂方式实例化和实例工厂方式实例化。三种方式以构造器实例化最为常见。,(,1,)使用构造器创建,Bean,实例,使用构造器来创建,Bean,实例是最常见的情况。如果不采用构造注入,,Spring,底层会调用,Bean,类的无参数构造器来创建实例,因此要求该,Bean,类提供无参数的构造器。,03,15.3 Spring,容器中的,Bean,(,1,)使用构造器创建,Bean,实例,采用默认的构造器创建,Bean,实例,,Spring,对,Bean,实例的所有属性执行默认初始化,即所有的基本类型的值初始化为,0,或,false,;所有的引用类型的值初始化为,null,。,关于使用构造器实例化的,Spring,配置文件内容,示例如下:,03,15.3 Spring,容器中的,Bean,(,2,)使用静态工厂方法创建,Bean,使用静态工厂方法创建,Bean,实例时,class,属性必须指定,但此时,class,属性并不是指定,Bean,实例的实现类而是静态工厂类,,Spring,通过该属性知道由哪个工厂类来创建,Bean,实例。,除此之外,还需要使用,factory-method,属性来指定静态工厂方法,,Spring,将调用静态工厂方法返回一个,Bean,实例,一旦获得了指定,Bean,实例。,03,15.3 Spring,容器中的,Bean,(,2,)使用静态工厂方法创建,Bean,关于使用静态工厂方式实例化的,Spring,配置文件内容,示例如下:,工厂类,StaticFactory,中须有静态方法,createBean(),,来得到相应的,Bean,对象。,03,15.3 Spring,容器中的,Bean,(,3,)调用实例工厂方法创建,Bean,实例工厂方法与静态工厂方法只有一个不同:,调用静态工厂方法只需使用工厂类即可,而调用实例工厂方法则需要,工厂实例,。,使用实例工厂方法时,配置,Bean,实例的,元素无须,class,属性,配置实例工厂方法使用,factory-bean,指定工厂实例。,03,15.3 Spring,容器中的,Bean,采用实例工厂方法创建,Bean,的,元素时需要指定如下两个属性:,factory-bean,:,该属性的值为工厂,Bean,的,id,。,factory-method,:,该属性指定实例工厂的工厂方法。,关于使用实例工厂方式实例化的,Spring,配置文件内容,示例如下:,03,15.3 Spring,容器中的,Bean,3,Spring Bean,配置依赖,Java,应用中各组件的相互调用的实质可以归纳为依赖关系,根据注入方式的不同,,Bean,的依赖注入通常表现为如下两种形式。,(,1,)属性:通过,元素配置,对应设值注入。,(,2,)构造器参数:通过,元素指定,对应构造注入。,03,15.3 Spring,容器中的,Bean,3,Spring Bean,配置依赖,不管是属性,还是构造器参数,都视为,Bean,的依赖,接受,Spring,容器管理。依赖关系的值要么是一个确定的值,要么是,Spring,容器中其他,Bean,的引用。例如,如果需要为,Bean,设置的属性值是容器中另一个,Bean,实例,则应该使用,元素。,03,15.3 Spring,容器中的,Bean,4,Spring Bean,设置属性值,元素用于指定字符串类型、基本类型的属性值,,Spring,使用,XML,解析器来解析出这些数据,然后利用,java.beans.PropertyEditor,完成类型转换:从,java.lang.String,类型转换为所需的参数值类型。如果目标类型是基本数据类型,通常都可以正确转换。,03,15.3 Spring,容器中的,Bean,5,Spring Bean,作用域,当通过,Spring,容器创建一个,Bean,实例时,不仅可以完成,Bean,实例的实例化,还可以为,Bean,指定特定的作用域。,Spring,支持如下五种作用域:,(,1,),singleton,:,单例模式,在整个,Spring IoC,容器中,,singleton,作用域的,Bean,将只生成一个实例。(默认),03,15.3 Spring,容器中的,Bean,(,2,),prototype,:,每次通过容器的,getBean(),方法获取,prototype,作用域的,Bean,时,都将产生一个新的,Bean,实例。,(,3,),request,:,对于一次,HTTP,请求,,request,作用域的,Bean,将只生成一个实例,这意味着,在同一次,HTTP,请求内,程序每次请求该,Bean,,得到的总是同一个实例。只有在,Web,应用中使用,Spring,时,该作用域才真正有效。该作用域将,bean,的定义限制为,HTTP,请求,只在,web-aware Spring ApplicationContext,的上下文中有效。,03,15.3 Spring,容器中的,Bean,(,4,),session,:,该作用域将,bean,的定义限制为,HTTP,会话,只在,web-aware Spring ApplicationContext,的上下文中有效。,(,5,),global session,:,每个全局的,HTTP Session,对应一个,Bean,实例。该作用域将,Bean,的定义限制为全局,HTTP,会话,只在,web-aware Spring ApplicationContext,的上下文中有效。,(本章将讨论前两个范围,即,singleton,作用域和,prototype,作用域),04,15.4,容器中,Bean,的生命周期,Spring,可以管理,singleton,作用域,Bean,的生命周期,,Spring,可以精确地知道该,Bean,何时被创建,何时被初始化完成,容器何时准备销毁该,Bean,实例。,对于,prototype,作用域的,Bean,,,Spring,容器仅仅负责创建。当容器创建了,Bean,实例后,,Bean,实例完全交给客户端代码管理,容器不再跟踪其生命周期。,04,15.4,容器中,Bean,的生命周期,Spring Bean,的生命周期的整个执行过程描述如下:,(,1,),Spring,对,Bean,进行实例化,默认,Bean,是单例。,(,2,),Spring,对,Bean,进行依赖注入。,(,3,)如果,Bean,实现了,BeanNameAware,接口,,Spring,将当前,Bean,的,id,传给,setBeanName(),方法。,(,4,)如果,Bean,实现了,BeanFactoryAware,接口,,Spring,将调用,setBeanFactory(),方法,将,BeanFactory,实例传进来。,04,15.4,容器中,Bean,的生命周期,(,5,)如果,Bean,实现了,ApplicationContextAware(),接口,,Spring,会将当前应用上下文(,ApplicationContext,实例)的引用传入,setApplicationContext(),方法。这时,Spring IoC,容器也必须是一个,ApplicationContext,接口的实现类。,(,6,)如果,Bean,实现了,BeanPostProcessor,接口,,Spring,将调用该接口的预初始化方法,postProcessBeforeInitialization(),对,Bean,进行加工操作。,04,15.4,容器中,Bean,的生命周期,(,7,)如果,Bean,实现了,InitializingBean,接口,,Spring,将调用它们的,afterPropertiesSet,接口方法。类似的,如果,Bean,使用了,init-method,属性声明了初始化方法,该方法也会被调用。,(,8,)如果,Bean,实现了,BeanPostProcessor,接口,,Spring,将调用该接口的初始化方法,postProcessAfterInitialization(),。,(,9,)此时,Bean,已经准备就绪,可以被应用程序使用了,他们将一直驻留在应用上下文中,直到该应用上下文被销毁。如果,Bean,的作用域是,prototype,,,Spring,不再管理该,Bean,。,04,15.4,容器中,Bean,的生命周期,(,10,)若,Bean,实现了,DisposableBean,接口,,Spring,将调用它的,d,e,stroy(),接口方法。同样,如果,Bean,使用了,destroy-method,属性声明了销毁方法,则该方法被调用。,上述生命周期的接口,大部分是针对单个,Bean,而言的,而,BeanPostProcessor,接口则是针对所有,Bean,而言的,,DisposableBean,接口则是针对,Spring IoC,容器自身。,05,15.5,两种后处理器,Spring,提供了两种常用的后处理器:,(,1,),Bean,后处理器。这种后处理器会对容器中,Bean,进行后处理,对,Bean,进行额外加强。,(,2,)容器后处理器。这种后处理器会对,IoC,容器进行后处理,用于增强容器功能。,05,15.5,两种后处理器,Bean,后处理器,是一种特殊的,Bean,,这种特殊的,Bean,并不对外提供服务,它甚至可以无须,id,属性,它主要负责对容器中的其他,Bean,执行后处理,例如为容器中的目标,Bean,生成代理等,这种,Bean,称为,Bean,后处理器。,Bean,后处理器会在,Bean,实例创建成功之后,对,Bean,实例进行进一步的增强处理。,15.5.1 Bean,后处理器,05,15.5,两种后处理器,Bean,后处理器,必须实现,BeanPostProcessor,接口,同时必须实现该接口的两个方法。,(,1,),Object postProcessBeforeInitialization(Object bean, String name) throws BeansException,: 该方法的第一个参数是系统即将进行后处理的,Bean,实例,第二个参数是该,Bean,的配置,id,。,(,2,),Object postProcessAfterinitialization(Object bean, String name) throws BeansException,:该方法的第一个参数是系统即将进行后处理的,Bean,实例,第二个参数是该,Bean,的配置,id,。,05,15.5,两种后处理器,容器中一旦注册了,Bean,后处理器,,Bean,后处理器就会自动启动,在容器中每个,Bean,创建时自动工作,,Bean,后处理器两个方法的回调时机,如图,15-5,所示。,05,15.5,两种后处理器,Bean,后处理器 负责处理容器中的所有,Bean,实例,而,容器后处理器,则负责处理容器本身。容器后处理器必须实现,BeanFactoryPostProcessor,接口,,并实现该接口的一个方法:,postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory),实现该方法的方法体就是对,Spring,容器进行的处理,这种处理可以对,Spring,容器进行自定义扩展,当然也可以对,Spring,容器不进行任何处理。,15.5.2,容器后处理器,05,15.5,两种后处理器,类似于,BeanPostProcessor,,,ApplicationContext,可自动检测到容器中的容器后处理器,并且自动注册容器后处理器。,但若使用,BeanFactory,作为,Spring,容器,则必须手动调用该容器后处理器来处理,BeanFactory,容器。,15.5.2,容器后处理器,06,15.6,装配,Spring Bean,使用,Spring,框架后,调用者无需主动获取被依赖对象,调用者只要被动接受,Spring,容器为调用者的成员变量赋值即可,由此可见使用,Spring,后,调用者获取被依赖对象的方式由原来的主动获取,变成了被动接受,所以,Rod Johnson,称之为,控制反转,。,另外,从,Spring,容器的角度来看,,Spring,容器负责将被依赖对象赋值给调用者的成员变量,相当于为调用者注入它依赖的实例,因此,Martine Fowler,称之为,依赖注入,。,Bean,的装配,可以理解为,依赖关系注入,,,Bean,的装配方式即,Bean,依赖注入的方式。,06,15.6,装配,Spring Bean,Spring,提供了两种通过,XML,配置装配,Bean,的方式:,设值注入,和,构造注入,。,前面的章节已经介绍过,在此不再赘述。,15.6.1,通过,XML,配置装配,Bean,06,15.6,装配,Spring Bean,使用注解的方式可以减少,XML,的配置,注解功能更为强大。,Spring,提供如下几个,Annotation,来标注,Spring Bean,:,Component,:,标注一个普通的,Spring Bean,类。,Controller,:,标注一个控制器组件类。,15.6.2,通过注解装配,Bean,06,15.6,装配,Spring Bean,Service,:,标注一个业务逻辑组件类。,Repository,:,标注一个,DAO,组件类。,在,Spring,配置文件中做如下配置,指定自动扫描的包:,15.6.2,通过注解装配,Bean,06,15.6,装配,Spring Bean,1,Autowired,和,Qualifier,的使用,Spring 4.0,提供了增强的自动装配和精确装配。,Spring,使用,Autowired,注解来指定自动装配,,Autowired,可以修饰,setter,方法、普通方法、实例变量和构造器等。,15.6.3,自动装配和精确装配,06,15.6,装配,Spring Bean,当使用,Autowired,标注,setter,方法时,默认采用,byType,自动装配策略。在这种策略下,符合自动装配类型的候选,Bean,实例常常有多个,这个时候就可能引起异常,为了实现精确的自动装配,,Spring,提供,了,Qualifier,注解,通过使用,Qualifier,,会将,Autowired,默认的按,Bean,类型装配修改为根据,Bean,的,id,(或实例名称)来执行自动装配,,Bean,的实例名称由,Qualifier,注解的参数指定。,15.6.3,自动装配和精确装配,06,15.6,装配,Spring Bean,15.6.3,自动装配和精确装配,2,使用自动装配注入合作者,Bean,Spring,能自动装配,Bean,与,Bean,之间的依赖关系,即无须使用,ref,显式指定依赖,Bean,,而是由,Spring,容器检查,XML,配置文件内容,根据某种规则,为调用者,Bean,注入被依赖的,Bean,。,Spring,自动装配可通过,元素的,default-autowire,属性指定,该属性对配置文件中所有的,Bean,起作用;也可通过对,元素的,autowire,属性指定,该属性只对该,Bean,起作用。,07,15.7 Spring,的,AOP,1,为什么需要,AOP,AOP,(,Aspect Orient Programming,)也就是面向切面编程,作为面向对象编程的一种补充,已经成为一种比较成熟的编程方式。,AOP,和,OOP,互为补充,面向切面编程,将程序运行过程分解成各个切面,。,AOP,专门用于处理系统中分布于各个模块(不同方法)中的交叉关注点的问题,在,Java EE,应用中,常常通过,AOP,来处理一些具有横切性质的系统级服务,如事务管理、安全检查、缓存、对象池管理等,,AOP,已经成为一种非常常用的解决方案。,07,15.7 Spring,的,AOP,2,使用,AspectJ,实现,AOP,AspectJ,是一个基于,Java,语言的,AOP,框架,提供了强大的,AOP,功能,其他很多,AOP,框架都借鉴或采纳其中的一些思想。其主要包括两个部分:一个部分定义了如何表达、定义,AOP,编程中的语法规范,通过这套语法规范,可以方便地用,AOP,来解决,J ava,语言中存在的交叉关注点的问题;另一个部分是工具部分,包括编译、调试工具等。,07,15.7 Spring,的,AOP,2,使用,AspectJ,实现,AOP,AOP,实现可分为两类:,(,1,)静态,AOP,实现。,AOP,框架在编译阶段对程序进行修改,即实现对目标类的增强,生成静态的,AOP,代理类,以,AspectJ,为代表。,(,2,)动态,AOP,实现。,AOP,框架在运行阶段动态生成,AOP,代理,以实现对目标对象的增强,以,Spring AOP,为代表。,07,15.7 Spring,的,AOP,3,AOP,的基本概念,关于面向切面编程的一些术语:,(,1,)切面(,Aspect,):切面用于组织多个,Advice,,,Advice,放在切面中定义。,(,2,)连接点(,Joinpoint,):程序执行过程中明确的点,它实际上是对象的一个操作,例如方法的调用或者异常的抛出。在,Spring AOP,中,连接点就是方法的调用。,07,15.7 Spring,的,AOP,3,AOP,的基本概念,(,3,)增强处理(,Advice,):,AOP,框架在特定的切入点执行的增强处理。即在定义好的切入点处所要执行的程序代码。,(,4,)切入点(,Pointcut,):可以插入增强处理的连接点。简而言之,当某个连接点满足指定要求时,该连接点将被添加增强处理,该连接点也就变成了切入点。,本章小结,Spring,框架,由,Rod Johnson,开发,,2004,年发布了,Spring,框架的第一版。,Spring,是一个从实际开发中抽取出来的框架,因此它完成了大量开发中的通用步骤,留给开发者的仅仅是与特定应用相关的部分,从而大大提高了企业应用的开发效率。,Spring,是低侵入式设计,代码的污染极低,独立于各种应用服务器,基于,Spring,框架的应用,可以真正实现,Write Once,,,Run Anywhere,的承诺。,Spring,的,IoC,容器降低了业务对象替换的复杂性,提高了组件之间的解耦。,本章小结,Spring,的,AOP,支持允许将一些通用任务如安全、事务、日志等进行集中式管理,从而提供了更好的复用。,Spring,的,ORM,和,DAO,提供了与第三方持久层框架的良好整合,并简化了底层的数据库访问。,Spring,的高度开放性,并不强制应用完全依赖于,Spring,,开发者可自由选用,Spring,框架的部分或全部。,
展开阅读全文