Spring 是什么?
- Spring 是一个开源框架
- Spring 为简化企业级应用开发而生。使用 Spring 可以使简单的 JavaBean 实现以前之后 EJB 才能实现的功能。
- Spring 是一个 IOC(DI)和 AOP 容器框架。
- 具体描述 Spring
- 轻量级:Spring 是非侵入性的,基于 Spring 开发的应用中的对象可以不依赖 Spring 的 API
- 依赖注入(DI — dependency injection、IOC)
- 面向切面编程(AOP — aspect original programming)
- 容器:Spring 是一个容器,因为它包含并且管理应用对象的生命周期
- 框架:Spring 实现了使用简单的组件配置组合成一个复杂的应用。在 Spring 中可以使用 XML 和 Java 注解组合这些对象
- 一站式:在 IOC 和 AOP 的基础上可以整合各种企业应用的开源框架和优秀的第三方类库(实际上 Spring 自身也提供了展现层的 SpringMVC 和 持久层 的 Spring JDBC)
- Spring 的配置文件:一个典型的 Spring 项目需要创建一个或多个 Bean 配置文件,这些配置文件用于在 Spring IOC 容器里配置 Bean。 Bean 的配置文件可以放在 classpath下,也可以放在其他目录下。
- 本文及以后的文章,所使用的版本是Spring4.x
IOC & DI 概述
Spring 的核心是控制反转(IOC)和面向切面(AOP)。
- IOC(Inversion of Control):其思想是反转资源获取的方向。传统的资源查找方式要求组件向容器发起请求查找资源,作为回应,容器适时的返回资源。而应用了 IOC 之后,则是**容器主动的将资源推送给它所管理的组件,组件所要做的是选择一种合适的方式来接受资源。**这种行为也被称为查找的被动形式
- DI(dependency Injection)–IOC 的另一种表述方式:即**组件以一些预定好的方式(例如setter方法)接受来自如容器的资源注入。**相对于 IOC 而言,这种表述更为直接
IOC即Inversion of Control,翻译过来就是控制反转。啥是控制反转啊?控制反转指的就是将对象的创建权反转给(交给)了Spring,其作用是实现了程序的解耦合。也可以说是获取对象的方式变了,对象创建的控制权不是"使用者",而是容器。这种方式不类似于以前写程序主动请求资源(new 对象的方式),而是我们通过配置将所需要的资源请求告诉容器,Spring 容器在创建过程中会将我们需要的资源交给我们,即依赖注入,各种资源是由容器创建并交给程序,反转了资源获取的方向,即控制反转。用更通俗的话来说,IOC就是指对象的创建,并不是在代码中用new出来的,而是通过Spring进行配置创建的。
IOC的底层原理就是工程模式+反射+XML配置文件。
AOP:即面向切面编程。Spring 后续总结中我再仔细讲,本文不会过多阐述它。
轻量级框架Spring的优点:
1、Spring的依赖注入将对象之间的依赖关系交给了框架来处理,减小了各个组件之间的耦合性;
2、AOP面向切面编程,可以将通用的任务抽取出来,复用性更高;
3、Spring对于其余主流框架都提供了很好的支持,代码的侵入性很低。
Spring 的XML配置文件一般是在 schema 约束下编写的,一般我们把配置文件创建在 src下,命名为applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
所有的配置都要在beans标签内写,这是 Spring 配置文件的根元素。
在 Spring 的 IOC 容器里配置 Bean
- 配置形式:基于 XML 文件的方式;基于注解的方式(我会在以后的文章中补充)
- 在 xml 文件中通过 bean 节点来配置 bean
- Bean 配置方式:通过全类名(反射)、通过工厂方法(静态工厂方法 & 实例工厂方法)、FactoryBean
Spirng 容器
- 在 Spring IOC 容器读取 Bean 配置创建 Bean 实例之前, 必须对它进行实例化. 只有在容器实例化后, 才可以从 IOC
容器里获取 Bean 实例并使用.
Spring 提供了两种类型的 IOC 容器实现.
-
BeanFactory: IOC 容器的基本实现.
-
ApplicationContext: 提供了更多的高级特性. 是 BeanFactory 的子接口.
-
BeanFactory 是 Spring 框架的基础设施,面向 Spring 本身;ApplicationContext 面向使用
Spring 框架的开发者,几乎所有的应用场合都直接使用 ApplicationContext 而非底层的 BeanFactory -
无论使用何种方式, 配置文件是相同的.
ApplicationContext
ApplicationContext 的主要实现类:
-
ClassPathXmlApplicationContext:从 类路径下加载配置文件
-
FileSystemXmlApplicationContext: 从文件系统中加载配置文件
-
ConfigurableApplicationContext 扩展于
ApplicationContext,新增加两个主要方法:refresh() 和 close(), 让
ApplicationContext 具有启动、刷新和关闭上下文的能力 -
ApplicationContext 在初始化上下文时就实例化所有单例的 Bean。
-
WebApplicationContext 是专门为 WEB 应用而准备的,它允许从相对于 WEB 根目录的路径中完成初始化工作
Spring 支持三种依赖注入的方式
- 属性注入
- 构造器注入
- 工厂方法注入(很少使用)
1、属性注入
属性注入即通过 setter 方法注入 Bean 的属性值或依赖的对象。
属性注入通过 <property> 元素,使用 name 属性指定 Bean 的属性名称,value 属性或 <value>节点指定属性值。
class:bean的全类名,通过反射的方式在 IOC容器中创建Bean,所以要求Bean中必须有无参数的构造器
id:标识容器中的bean,id值一定是唯一的
<bean id="helloWorld" class="com.qlgydx.spring.beans.HelloWorld">
<property name="name" value="Spring"></property>
</bean>
id:Bean 的名称。
- 在 IOC 容器中必须是唯一的
- 若 id 没有指定,Spring 自动将权限定性类名作为 Bean 的名字
- id 可以指定多个名字,名字之间可用逗号、分号、或空格分隔
2、构造器注入
构造方法注入Bean 的属性值或依赖的对象,它保证了 Bean 实例在实例化后就可以使用。
构造器注入在 <constructor-arg> 元素里声明属性。
<constructor-arg> 中没有name属性
<bean id="car" class="com.qlgydx.spring.beans.Car">
<constructor-arg value="Audi" index="0"></constructor-arg>
<constructor-arg value="Shanghai" index="1"></constructor-arg>
<constructor-arg value="300000" type="double"></constructor-arg>
</bean>
注意:有两种形式入参,一种是按照索引匹配入参,另一种是按照类型匹配入参
<!-- 使用构造器注入属性值可以指定参数的位置和参数的类型! 以区分重载的构造器! -->
<bean id="car2" class="com.qlgydx.spring.beans.Car">
<constructor-arg value="Baoma" type="java.lang.String"></constructor-arg>
<!-- 如果字面值包含特殊字符可以使用 <![CDATA[]]> 包裹起来 -->
<!-- 属性值也可以使用value子节点进行配置 -->
<constructor-arg type="java.lang.String">
<value><![CDATA[<ShangHai^>]]></value>
</constructor-arg>
<constructor-arg type="int">
<value>250</value>
</constructor-arg>
</bean>
注入属性的时候牵扯到一些注入方式的区别,稍微解释一下。
字面值:可用字符串表示的值,可以通过 < value> 元素标签或者value属性进行注入
基本数据类型及其封装类、String等类型都可以采取字面值注入的方式。
字面值中包含特殊字符,可以使用<![CDATA[]]>把字面值包裹起来。
Bean的引用
-
组成应用程序的Bean经常需要相互协作以完成应用程序的功能。要使 Bean 能够相互访问,就必须在 Bean 配置文件中指定对 Bean 的引用。
-
在 Bean 的配置文件中,可以通过< ref >元素或 ref 属性为 Bean 的属性或构造器参数指定对 Bean 的引用。
-
也可以在属性或构造器里包含对 Bean 的声明,这样的 Bean 称为内部 Bean。
当 Bean 实例仅仅给一个特定的属性使用时,可以将其声明为内部 Bean。内部 Bean 声明直接包含在 < property > 或 < constructor-arg >元素里,不需要设置任何 id 或 name 属性
注意:内部 Bean 不能使用在任何地方
<bean id="person" class="com.qlgydx.spring.beans.Person">
<property name="name" value="Tom"></property>
<property name="age" value="24"></property>
<!-- 可以使用property 的 ref 属性建立bean之间的引用关系 -->
<!--
<property name="car" ref="car2"></property>
-->
<!--
<property name="car">
<ref bean="car2"/>
</property>
-->
<!-- 内部bean,不能被外部引用,只能在内部使用 -->
<property name="car" >
<bean class="com.qlgydx.spring.beans.Car">
<constructor-arg value="Ford"></constructor-arg>
<constructor-arg value="Changan"></constructor-arg>
<constructor-arg value="2000000" type="double"></constructor-arg>
</bean>
</property>
</bean>
注入参数详解:null值和级联属性
- 可以使用专用的 < null/ >元素标签为 Bean 的字符串或其他对象类型的属性注入 null 值
<bean id="person2" class="com.qlgydx.spring.beans.Person">
<constructor-arg value="Jerry"></constructor-arg>
<constructor-arg value="25"></constructor-arg>
<constructor-arg><null/></constructor-arg>
</bean>
- 和 Structs、Hibernate 等框架一样,Spring 支持级联属性的配置
<bean id="person2" class="com.qlgydx.spring.beans.Person">
<constructor-arg value="Jerry"></constructor-arg>
<constructor-arg value="25"></constructor-arg>
<!-- 为级联属性赋值,注意: 属性需要先初始化后才可以为级联属性赋值,否则会有异常 ,和struts2不同 -->
<constructor-arg ref="car"></constructor-arg>
<property name="car.maxSpeed" value="250"></property>
</bean>
集合属性的注入
- 在 Spring 中可以通过一组内置的 xml 标签(例如:< list >,< set > 或 < map >)来配置集合属性。
- 配置 Java.util.List 类型的属性,需要指定< list >标签,在标签里包含一些元素。这些标签可以通过 < value >指定简单的常量值,通过 < ref >指定对其他 Bean 的引用。通过 < bean >指定内置 Bean 定义。通过 < null/ > 指定空元素。甚至可以内嵌其他集合。
<bean id="person3" class="com.qlgydx.spring.beans.collection.Person">
<property name="name" value="Mike"></property>
<property name="age" value="27"></property>
<property name="cars">
<!-- 使用 list 节点为 List 类型的属性赋值 -->
<list>
<ref bean="car"/>
<ref bean="car2"/>
<bean class="com.qlgydx.spring.beans.Car">
<constructor-arg value="Ford"></constructor-arg>
<constructor-arg value="Changan"></constructor-arg>
<constructor-arg value="2000000" type="double"></constructor-arg>
</bean>
</list>
</property>
</bean>
- 数组的定义和 List 一样,都使用 < list >
- 配置 Java.util.Set 需要使用 < set >标签,定义元素的方法与 List 一样。
- Java.util.Map 通过 < map > 标签定义, < map > 标签里可以使用多个 < entry > 作为子标签.
每个条目包含一个键和一个值. - 必须在 < key > 标签里定义键
- 因为键和值的类型没有限制, 所以可以自由地为它们指定 < value >, < ref >, < bean > 或 < null >元素.
- 可以将 Map 的键和值作为 < entry > 的属性定义: 简单常量使用 key 和 value 来定义; Bean 引用通过 key-ref 和 value-ref 属性定义
<!-- 配置Map属性值 -->
<bean id="newPerson" class="com.qlgydx.spring.beans.collection.NewPerson">
<property name="name" value="Rose"></property>
<property name="age" value="28"></property>
<property name="cars">
<!-- 使用 map 节点及 map 的 entry 子节点配置Map类型的成员变量-->
<map>
<entry key="AA" value-ref="car"></entry>
<entry key="BB" value-ref="car2"></entry>
</map>
</property>
</bean>
- 使用 < props > 定义 java.util.Properties, 该标签使用多个 < prop > 作为子标签. 每个 <
prop > 标签必须定义 key 属性.
<!-- 配置 Propertis 属性值 -->
<bean id="dataSourse" class="com.qlgydx.spring.beans.collection.DataSourse">
<property name="properties">
<!-- 通过 props 和 prop 子节点来为Properties 属性赋值 -->
<props>
<prop key="user">root</prop>
<prop key="password">1234</prop>
<prop key="jdbcUrl">jdbc:mysql///test</prop>
<prop key="driverClass">com.mysql.jdbc.Driver</prop>
</props>
</property>
</bean>
集合的注入
- 使用基本的集合标签定义集合时, 不能将集合作为独立的 Bean 定义, 导致其他 Bean 无法引用该集合, 所以无法在不同 Bean 之间共享集合.
- 可以使用 util schema 里的集合标签定义独立的集合 Bean. 需要注意的是, 必须在 根元素里添加 util schema 定义
<!-- 配置独立的集合 bean ,以供多个 bean 进行引用, 需要导入 util 命名空间-->
<util:list id="cars" >
<ref bean="car"/>
<ref bean="car2"/>
</util:list>
使用 p 命名空间
- 为了简化 XML 文件的配置,越来越多的 XML 文件采用属性而非子元素配置信息。
- Spring 从 2.5 版本开始引入了一个新的 p 命名空间,可以通过 元素属性的方式配置 Bean 的属性。
- 使用 p 命名空间后,基于 XML 的配置方式将进一步简化
<!-- 通过 p 命名空间对 bean 的属性赋值,需要先导入 p 命名空间 ,相对于传统的方式更加简洁-->
<bean id="person5" class="com.qlgydx.spring.beans.collection.Person" p:age="30"
p:name="Queen" p:cars-ref="cars"></bean>