什么是Spring?
Spring Framework(Spring)是一个层次化的轻量级开源JavaSE/EE应用框架,以反转控制(IOC)和面向切面编程(AOP)为内核,在展示层,持久层以及业务层上提供了众多企业级应用技术。此外,Spring能够整合开源世界里众多著名的第三方框架和类库,逐渐成为使用最多的JavaEE企业开源框架。
Spring的好处
- 方便解耦,简化开发。通过Spring提供的IOC容器,可以将对象之间的依赖关系交由Spring进行控制,避免硬编码所造成的过度程序耦合。
- AOP编程的支持。通过Spring提供的AOP功能,用户可以方便地进行面向切面编程,许多不容易用传统面向对象编程(OOP)实现的功能都可以通过AOP轻松应对。
- 声明式事务的支持。在Spring中,用户可以从单调烦闷的事务管理代码中解脱出来,通过声明式事务灵活地进行事务管理,提高开发效率和质量。
- 方便程序的测试。可以用非容器依赖的编程方式进行几乎所有的测试工作,在Spring中,测试不再是昂贵的操作,而是随手可做的事情。
- 降低JavaEE API的使用难度。Spring为很多难用的Java EE API(如JDBC,JavaMail,远程调用等)提供了一个薄薄的封装层,通过Spring的简易封装,大大降低了这些Java EE API的使用难度。
- 方便集合各种优秀的框架。Spring提供了对各种优秀框架(如Struts,Hiber,Hessi,Quartz等)的直接支持
1.Spring反转控制
Java应用程序在实现各自的业务逻辑的时候,不可避免的需要很多Java类的共同协作来完成,这些Java类之间具有依赖关系。应用程序需要使用某个目标类来完成业务逻辑时,不仅需要实例化目标类本身,还需要实例化其所依赖的类,然后通过一系列赋值或功能调用来对这些实例进行初始化,最后才能通过目标类的实例调用相应的公共接口方法实现业务逻辑功能。在普通的应用程序中这一过程往往是在应用程序中硬编码实现的,系统的复杂度会急剧增加,安全性,可靠性很难保证,同时也难于修改和维护。
控制反转(IOC)是将这种类之间依赖关系的实现和管理从应用程序中提取出来,交给容器来维护的一种机制。容器将负责目标类实例的创建,依赖类实例的创建,初始化工作等,在应用程序中只需要调用容器提供的接口就能获得可以使用的目标类实例,而无需做额外的工作,在这一执行过程中,当使用容器的接口去获得实例时,控制权就由程序代码转移到了外部容器,这种控制权得转移就是所谓得控制反转。
Spring核心模块实现了IOC的功能,它将类和类之间的依赖从代码中脱离出来,用配置的方式进行依赖关系描述,由IOC容器负责依赖类之间的创建,拼接,管理,获取等工作。
BeanFactory,ApplicationContext,WebApplicationContext是Spring框架三个核心的接口,框架中的其他大部分的类都是围绕它们展开,为它们提供支持和服务。
BeanFactory
BeanFactory被称为IOC容器,它是一个通用型的类工厂,可以创建并管理各自类的对象。在Spring中称这些对象为Bean。
BeanFactory通过一个配置文件描述Bean及Bean之间的依赖关系,利用Java语言的反射功能实例化Bean并建立Bean之间的依赖关系。同时BeanFactory还提供了Bean实例缓存,生命周期管理,Bean实例代理,事件发布,资源装载等高级服务。BeanFactory类实例的初始化和使用方式如下。
Resource resource = new ClassPathResource("beans.xml");
BeanFactory bf = new XmlBeanFactory(resource);
BeanName beanName = bf.getBean("bean",BeanName.class);
Resource 接口是Spring的资源访问接口通过该接口能够以简单透明的方式访问磁盘,类路径和网络上的资源。ClassPathResource是Resource 接口的一个实现,它能够访问类路径下的资源。XmlBeanFactory是BeanFactory接口的一个常用实现类。beans.xml是描述Bean之间关系的xml配置文件
ApplicationContext
ApplicationContext被称为应用上下文,它建立在BeanFactory的基础上,由BeanFactory派生而来,提供了更多面向实际应用的功能。BeanFactory是Spring框架的基础设施,是面向Spring本身的底层接口;ApplicationContext是面向使用Spring框架的开发者的接口,在大多数的应用场合都直接使用ApplicationContext而非底层的BeanFactory。ApplicationContext类实例的初始化和使用方式如下。
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
BeanName beanName = applicationContext.getBean("bean","BeanName.class");
WebApplicationContext
是专门针对Web应用的接口,它能够从相对于Web根目录的路径中装载配置文件,完成初始化工作。
WebApplicationContext对象将被作为属性保存在ServletContext中。Spring专门为此提供了一个根据类WebApplicationContextUtils,通过该类的静态方法getWebApplicationContext(ServletContext sc),就能从ServletContext中获得WebApplicationContext对象。WebApplicationContext的初始化与BeanFactory和ApplicationContext的初始化方式有所不同,它的初始化需要ServletContext实例,也就是说WebApplicationContext必须在拥有容器的情况习才能启动和使用。因此对于WebApplicationContext的启动一般通过在web.xml中配置Servlet自启动项或定义定义Web容器监听器的方式,让容器来完成WebApplicationContext的初始化和启动
Spring分别提供了用于启动Spring Web应用上下文的Servlet(ContetxtLoaderServlet)和Web容器监听器(ContextLoaderListener)。两者都实现了启动WebApplicationContextUtils实例的逻辑,开发者只要根据Web容器的具体情况选择两者之一,并在Web.xml中完成相应的配置即可。
使用ContextLoaderListener时,Web.xml文件配置如下。
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/daoContext.xml /WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
ContetxtLoaderServlet时,Web.xml文件配置如下。
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/daoContext.xml /WEB-INF/applicationContext.xml</param-value>
</context-param>
<servlet>
<servlet-name>SpringContextLoader</servlet-name>
<servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
WebApplicationContext类实例的初始化和使用方式如下。
ServletContext servletContext = request.getSession().getServletContext();
WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
2.Spring的依赖注入
依赖注入(DI)是指程序运行期间,由容器动态地为目标类的实例构建完成依赖关系的手段。依赖注入为控制反转的实现提供了支撑。Spring中依赖注入的方法可以采用属性注入和构造器注入两种。
2.1 属性注入
属性注入是利用Bean类的setter方法为Bean的属性注入具体值或者依赖对象。该种方式简单,直观,灵活性强,是实际应用中最常用的注入方式
Spring使用一个xml文件来对需要管理的Bean进行描述。在该文件中<beans…/>是配置文件的根元素,对所有Bean的配置都要求写在<beans…/>标签之间。Spring配置Bean的实例时使用<bean…/>标签并配置id和class两个属性。
id:属性表示Bean实例的唯一标识,程序通过id属性值来访问该Bean实例。Bean和Bean的依赖关系通过id属性进行关联。
class:表示Bean类的名字,必须为实现类,不能是接口。Spring容器会读取该值,并利用Java的反射机制来创建Bean实例
属性注入方式使用标签来对Bean类中需要依赖注入的属性进行描述。容器首先会调用Bean类的无参数的构造函数创建Bean实例,然后使用property标签中指定的值或对象作为参数调用Bean类的setter方法来完成依赖关系的注入。property的name属性指明了需要依赖注入的Bean属性的名字,对需要注入的依赖关系的指定有4类元素来完成
- value:需要将普通属性值注入属性时使用<value…/>元素,普通属性指的是基本类型的属性值及字符串类型的值
- ref:需要将Bean实例注入属性时使用<ref…/>元素。使用该元素时可以指定local或bean两个属性,local表示注入的和被注入的在同一个xml文件中配置,bean表示注入的和被注入的不在同一个xml文件中配置。
- bean:如果某个Bean不想被Spring容器直接访问,则可以使用<bean…/>元素来定义嵌套Bean,嵌套Bean只对嵌套它的外部Bean有效。Spring容器无法直接访问嵌套Bean,因此定义嵌套Bean时不需要指定id属性
- list,set,map及props:如果Bean的属性是一个集合,则可以用集合元素,<list…/>,<set…/>,<map…/>和<props…/>来分别为属性List,Set,Map,Properties类型的属性设置集合类的属性值,Spring对数组属性的处理和List一样,使用<list…/>。
2.2 构造器注入
构造器注入也叫构造函数注入,它利用带有参数的构造函数完成依赖关系的注入。这种方式在构造实例时就完成了依赖关系的初始化。这样的方式能够保证一些必要的属性在Bean实例化时就得到设置,并且确保了Bean实例在实例化后就可以使用。这种方式相比属性注入的方式虽然失去了一些灵活性,但是能够对依赖注入的顺序进行控制。当两个Bean出现循环依赖时不能对两个Bean都使用构造器注入的方式完成依赖注入需要将一方改成属性注入,否则Spring容器无法成功启动。
构造器注入的方式在配置文件中使用<constructor-arg…/>元素来对Bean类的依赖关系进行描述。每个constructor-arg指定一个构造器的参数。
<constructor-arg…/>元素还有一个type属性和一个index属性。type表示的是构造函数中参数的类型,而index(从0开始)表示与构造函数的第几个参数对应。
依赖注入的实例代码:
<beans xmlns="http://www.springframework.org/schema/beans">
<!-- 配置student_1实例,其实现类是Student-->
<bean id="student_1" class="com.yf.Servlet.pojo.Student">
<property name="studentName" value="java"/>
<property name="studentNum" value="8888"/>
<property name="courseNames">
<set>
<value>Java</value>
<value>C++</value>
<value>J2EE</value>
</set>
</property>
<property name="team" ref="team_1"/>
</bean>
<!-- 配置team_1实例,其实现类是Time-->
<bean id="team_1" class="com.yf.Servlet.pojo.Team">
<property name="teamNum" value="1213"/>
<property name="baseRoom" value="J3-404"/>
<property name="students">
<set>
<ref local ="student_1" />
</set>
</property>
</bean>
<!-- 配置javaCourse实例,其实现类是Course-->
<bean id="javaCourse" class="com.yf.Servlet.pojo.Course">
<constructor-arg index="0" type="java.lang.Integer" value="5131200"/>
<constructor-arg index="1" type="java.lang.String" value="Java"/>
<constructor-arg index="2" type="java.util.Set">
<set>
<ref local = "student_1"/>
</set>
</constructor-arg>
</bean>
</beans>
3.Spring bean的作用域
在配置文件中对Bean进行表述时,还能够指定其有效范围,即Bean的作用域。在配置文件中使用<bean…/>元素的scope属性对Bean实例的作用域进行指定。Spring支持5种作用域:singleton,prototype,request,session和global session。
<bean id="objName" class="className" scope="prototype|singleton"/>
比较常用的就是singleton和prototype两种作用域,后三种只有在Web应用中才会生效,并且必须在Web应用中增加额外的配置。
- singleton:容器以单例模式创建Bean实例,使用singleton定义的Bean在整个容器中只会产生一个实例对象,该对象的作用域是整个应用。如果不指定Bean的作用域,默认使用singleton作用域。
- prototype:原型模式,使用prototype定义的Bean类,在每次使用getBean方法获取Bean实例时,容器都生成一个新的实例对象。在这种情况下容器不会维护Bean实例的状态,当该Bean实例的所有应用都失效时,将会被垃圾回收机制所回收。
- request:针对每次HTTP请求,容器都会为使用request定义的Bean创建一个新实例,且该实例仅在当前HTTP Request内有效。当处理请求结束时,request作用域的Bean实例将被销毁。实际上通常只会将Web应用的控制器Bean指定成Request作用域
- session:针对每次HTTP Session,容器都会为使用session定义的Bean创建一个新实例,即针对每个HTTP会话存在不同的Bean实例
- global session:每个全局的HTTP Session对应一个Bean实例。典型情况下,仅在使用portlet context的时候有效
为了让request,session和global session三个作用域生效,必须将HTTP请求对象绑定到为该请求提供服务的线程上,这使得具有这三种作用域范围的Bean实例能够在后面的调用链中被访问到,可以采用Listener配置或Filter配置来实现这种绑定
<filter>
<filter-name>requestContextFilter</filter-name>
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>requestContextFilter</filter-name>
<rl-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.filter.RequestContextFilter</listener-class>
</listener>
4.Spring 自动装配
Spring能够自动装配Bean和Bean之间的依赖关系,即无需指定ref/显示指定依赖的Bean。而是由BeanFactory检查XML配置文件内容,根据某种规则自动识别判断Bean类之间的依赖关系完成依赖注入。Spring会自动搜索容器中所有的Bean,并对这些Bean进行判断,判断它们是否满足自动装配条件,如果满足,就会将该Bean实例注入到依赖属性中。自动装配可以减少配置文件的工作量,但是降低了依赖关系的透明性和清晰性。
Spring中如果为<beams…/>元素指定了default-autowire属性,那么容器将为所有的Bean进行自动装配。也可以通过指定<bean/…>元素的autowire属性将自动装配指定到单独的Bean,Spring通过这种方式使得,同一个Spring容器中可以让某些Bean使用自动装配,而另一些Bean不使用自动装配。
Spring中可以为default-autowire属性和autowire属性指定为如下5个值,令容器采用不同的规则完成自动装配。
- no:不采用自动装配。Bean依赖必须通过ref元素定义。这是默认配置,通过显示的方式指明Bean类之间的依赖关系,使得依赖关系更清晰。一般在大型的应用中一般都会采用这个默认配置。
- byName:根据属性名自动装配。该规则通过名字识别依赖关系完成注入。BeanFactory将查找容器中的全部Bean,找出其中id属性与依赖属性同名的Bean来完成注入。如果没有找到匹配的,则Spring不会进行任何注入。
- byType:根据属性类型自动装配。BeanFactory将查找容器中全部Bean,如果正好有一个与依赖属性类型相同的Bean,就自动注入这个属性:如果有多个这种的Bean。就抛出一个异常;如果没有匹配的Bean,则什么就不会发生,依赖属性不会被设置。
- constructor:与byType方式类似,只是应用于构造器注入的方式。根据构造器的参数类型来进行匹配自动完成依赖注入。BeanFactory将查找容器中全部Bean,如果正好有一个与构造器参数的类型相同,则使用这个Bean的实例作为构造器的参数进行注入。
- autodetect:BeanFactory根据Bean内部结构,决定使用constructor或byType。如果找到一个默认的构造函数,那么就会使用byType。