一、Spring简介

1、Spring的诞生

1.1、原因
日益复杂的Java企业应用开发

1.2、EJB之殇
JavaSE1.3引入了动态代理,使EJB采用的容器代码生成机制过时
当时AOP编程获得发展

1.3、轻量级开发框架
对容器不再有依赖

1.4、Spring横空出世
Rod Johnson《Expert One-on-One:J2EE Design and Development》

1.5、应对应用复杂性,Spring的关键策略
1) 基于POJO的轻量级和最小侵入性编程
2) 通过依赖注入DI和面向接口实现松耦合
3) 基于切面AOP和惯例进行声明式编程
4) 通过切面和模板减少样板式代码

2、POJO之美

2.1、POJO定义
POJO(Plain Old Java Objects)简单的普通的Java对象,Martin Fowler等发明的一个术语,为了避免和EJB等混淆
不具有任何特殊角色,不继承/实现任何其它Java框架的类或接口

2.2、很多框架具有侵入性,强迫开发者编写与框架绑定的大量冗余、难以预测的代码

2.3、Spring强调基于POJO的最小侵入性编程
Spring不会强迫实现特定规范的接口或继承特定类
Spring通过依赖注入赋予POJO以魔力

2.4、JavaEE中轻量级框架与重量级框架的概念
1)简单一句话: 量级主要由对容器的依赖性决定,依赖越小,越轻量
2)容器:用来管理组件行为的一个集合工具,组件的行为包括与外部环境的交互、组件的生命周期、组件之间的合作依赖关系等等
3)在Java应用开发环境中,“轻量级Java”主要是指两个东西:简化的编程模型和更具响应能力的容器。轻量级Java旨在消除与传统JavaEE API有关的不必要的复杂性和限制,同时缩短应用程序的部署时间
4)轻量级技术中,控制反转IoC(依赖注入DI)最关键。使用IoC,开发人员不需要编写复杂的代码来执行查询、处理基础架构异常或管理连接,就能够解决对象依赖性问题。这有助于简化代码、 将业务逻辑与基础架构分离,从而使应用程序更易于维护
5)轻量级Java的的另一个关键特征是,它不会强迫业务对象遵循平台特定接口。这允许开发人员在普通Java对象(POJO)中实现业务逻辑,从而提高生产率

PS:Spring如何保证基础框架和业务逻辑之间不产生依赖性,这里的依赖性是指什么?
使用依赖注入、IoC来解耦,避免耦合性
业务逻辑和框架代码分离,业务逻辑专注业务,实现业务
业务逻辑不会用基础框架的类来实现业务

3、依赖注入

3.1、“过于”复杂的软件系统
面向对象使系统的实现变得容易
当系统复杂到一定程度时,仅仅面向对象就不够了

3.2、组件化的思想:分离关注点
目的: 解耦合。实现每个组件块时只关注组件内部的事情 -> 要点:明确定义组件间的接口

3.3、依赖注入:强制将组件的构建和使用分开
组件可以单独的生产,单独的定制

3.4、实际的Java系统由多个类组成,类之间互相协作完成特定业务逻辑

3.5、以往通常每个对象负责管理与之协作的对象(即所依赖的对象)的引用,导致高耦合、难以测试

3.6、耦合具有两面性
1)耦合代码难以测试
2)一定程度的耦合不可避免

3.7、 依赖注入DI:对象的依赖关系由负责协调系统中各对象的第三方组件(通常是容器)在创建对象时设定。对象无需自行创建或管理它们的依赖关系--依赖关系将被自动注入到需要它们的对象中去

3.8、依赖注入带来的好处: 松耦合

3.9、Spring通过 应用上下文(ApplicationContext)装载Bean的定义并把它们组装起来,应用上下文负责对象的创建和组装
应用上下文是个容器,是个工厂,在工厂里装配,装配需要规则,我们用配置文件来定义

4、应用切面

4.1、横切关注点:除了主要的业务逻辑功能之外,诸如日志、事务管理和安全等系统服务通常称为横切关注点(跨越系统的多个组件)

4.2、以往通常这些横切关注点分散到多个组件中去(融入到有自身核心业务逻辑的组件中去),导致代码引入双重复杂性
1)遍布系统的关注点实现代码将重复出现在多个组件中
系统有很多的功能块,功能块有很多组件,组件应该把注意力放在实现业务逻辑上,在每个组件里都要实现日志功能的实现(重复性)
2)组件会因为那些与自身核心业务无关的代码而变得复杂混乱

4.3、AOP(面向切面编程)使这些 系统服务模块化,并以声明的方式将它们应用到需要的组件中去

4.4、AOP确保POJO保持简单

5、使用模板消除样板式代码

5.1、JDBC等使用Java API导致样板式代码
样板式代码:代码都一样,很拖沓

5.2、Spring旨在通过模板封装来消除样板式代码
例如:jdbcTemplate代替jdbc繁琐的声明

二、Bean容器

1、应用上下文

1.1、Spring应用中,对象 生存于Spring容器中
Spring里面它组件是一些POJO类,就是普通的Java对象

1.2、容器是Spring框架的核心,Spring容器使用依赖注入管理构成应用的组件,创建相互协作的组件之间的关联

1.3、Spring容器:
1)Bean工厂
  工厂是用来制造一系列bean的对象
2)应用上下文
  ApplicationContext,是必不可少的一个容器

1.4、应用上下文 基于Bean工厂而构建,并提供 面向应用的服务
Bean工厂提供最基本的DI支持
应用上下文提供面向应用的服务,从属性文件解析文本信息的能力,发布事件给感兴趣的事件监听者的能力

1.5、Spring常用应用上下文:
1)ClassPathXmlApplicationContext
  读取类路径下的XML配置文件并加载上下文定义
2)FileSystemXmlApplicationContext
  读取文件系统下的XML配置文件并加载上下文定义
2)XmlWebApplicationContext
  读取Web应用下的XML配置文件并加载上下文定义

2、Bean的生命周期

2.1、流程图:

1)Spring对Bean实例化
2)Spring将值和Bean的引用注入进bean对应的属性当中
3)如果Bean实现了BeanNameAware接口,Spring将Bean的ID传递给setBeanName()方法
4)如果Bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory()方法,将BeanFactory引用传进去
5)如果Bean实现了ApplicationContextAware接口,Spring将调用setApplicationContext()方法,将ApplicationContext引用传进去
6)如果Bean实现了BeanPostProcessors接口,Spring将调用postProcessorsBeforeInitialization()方法
7)如果Bean实现了InitializingBean接口,Spring将调用afterPropertiesSet()方法
8)如果Bean使用init-method声明了初始化方法的话,这个方法也会被调用
9)如果Bean实现了BeanPostPrecessors接口,Spring将调用postProcessorsAfterInitialization()方法
10)Bean已经准备就绪,可以被应用程序使用,将一直驻留在应用上下文内,直到上下文被销毁
---应用上下文被销毁---
11)如果Bean实现了DisposableBean接口的话,Spring将调用destory()方法
12)如果Bean使用了destory-method声明销毁方法的话,这个方法也会被调用

三、Spring框架

1、Spring模块

1.1、获取Spring发布包
Spring下载社区:SpringSource自建的下载社区
Maven中心:Maven工具默认访问的仓库
企业模块仓库:由SpringSource维护的一个企业模块仓库,类似Maven
Maven公共仓库:位于Amazon S3服务器中

1.2、Spring发布包不再附带例子项目,可以通过SVN从官方地址下载spring-samples
Spring例子项目是很有价值的,特别对于初学者来说

2、六大模块


2.1、核心Spring容器
核心容器负责Spring应用中的Bean的创建和管理
Bean工厂---提供依赖注入
应用上下文---提供配置Spring的不同方式
该模块还提供许多企业服务:邮件、JNDI访问、EJB集成、调度

2.2、Spring的AOP模块
是Spring应用开发切面的基础
AOP有助于对象解耦
AOP可将遍布应用的关注点从所应用的对象中解耦出来

2.3、数据访问与集成模块
Spring的JDBC和DAO模块封装了数据库访问的样板代码,使得代码简洁明了并有效管理异常
Spring的ORM模块建立在对DAO的支持上,并为一些ORM框架提供了构建DAO的简便方式
Spring对一些流行ORM框架进行集成
模块还包含在JMS之上构建的Spring抽象层,使用消息以异步方式与其它应用集成
模块还使用AOP为Spring应用中的对象提供事务管理服务

2.4、Web和远程调用
Spring自带一个Web框架叫Spring MVC
Spring远程调用服务集成了RMI、Hessian、Burlap、JAW-WS,还自带一个远程调用框架:HTTP invoker

2.5、测试模块
用来测试Spring的应用

3、Spring Portfolio

3.1、整个Spring Portfolio几乎为每个领域的Java开发提供Spring编程模型

3.2、Spring Web Flow

3.3、Spring Web Service

3.4、Spring Security

3.5、Spring Integration

3.6、Spring Batch

3.7、Spring Social

3.8、Spring Mobile

3.9、Spring Dynamic Modules

3.10、Spring Rich Client

四、声明Bean

IDE选用eclipse IDE for Java EE
Web应用部署、运行环境选用Tomcat7
数据库选用oracle xe 11.2

1、依赖注入

1.1、Spring Dependency Injection 依赖注入
1)Inversion of Control(IoC)控制反转
2)“Hollywood Principle”好莱坞原则
  Don't call me, I'll call you
3)容器通过注入设定实现对象,来解决组件之间的依赖关系(推模式)
4)传统的组件初始化或用服务定位模式,组件实现定位(拉模式)
5)Martin Fowler 提议术语Dependency Injection

1.2、依赖注入基本原则
应用对象不应该负责查找资源或其它依赖的协作组件。配置对象的工厂应该交给IoC容器完成,“查找资源的逻辑应该从应用代码中抽取出来,交给容器负责”
这里的IoC容器就是应用上下文

1.3、Non-IoC / Dependency Injection

传统模式下,Object A要create或者look-up Object B、Object C

1.4、IoC / Dependency Injection


 有一个DAO对象,调用DAO对象的持久化方法,持久化数据
要有set方法,让容器帮你注入对象

1.5、依赖注入的规则--配置文件

<ref bean="myDataSource"></ref>,ref引用就是组装Bean,就是把Bean myDataSource注入到myOrderDao里面

2、创建Spring配置

2.1、Spring容器提供两种配置Bean的方式
1)XML配置文件
2)基于Java注解的配置方式(Spring自动扫描标签)

2.2、Spring配置文件
根元素来源于Spring beans命名空间<beans>元素,例如名为chinese-idol.xml的Spring配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsd"><!-- Bean declarations go here --></beans>

2.3、Spring自带多种XML命名空间,通过他们可以配置Spring容器

3、声明一个简单Bean

3.1、在Spring配置chinese-idol.xml中声明
在beans里面加入:

<bean id ="小李" class="com.javaee.spring.chineseIdol.Juggler"/>

Bean的名字由id属性定义,即这个Bean被称为“小李”

3.2、当Spring容器加载该Bean时,Spring将使用默认的构造器来实例化“小李”Bean:
相当于Spring执行了这个类的默认构造方法

new com.javaee.spring.chineseIdol.Juggler();

3.3、代码加载Spring上下文

ApplicationContext ctx = new ClassPathXmlApplicationContext("com/javaee/spring/chineseIdol/chinese-idol.xml");
Performer performer = (Performer)ctx.getBean("小李");
performer.performer();

4、通过构造器注入

4.1、在Spring配置文件chinese-idol.xml中声明

<bean id ="小李" class="com.javaee.spring.chineseIdol.Juggler"><constructor-arg value="10"/>
</bean>

<constructor-arg value="10"/>构造参数,它会调用这个类的有参数的构造方法

在构造Bean时,可以使用<constructor-arg>元素来告诉Spring额外的信息,即传递给有参数构造方法的参数设置

4.2、通过构造器注入对象引用--XML配置

<bean id="bike" class="com.javaee.spring.chineseIdol.Bike"/>
<bean id="小张" class="com.javaee.spring.chineseIdol.RidableJuggler"><constructor-arg value="10"/><constructor-arg ref="bike"/>
</bean>

先注入一个整数,再注入一个引用,引用前面的bike

执行逻辑(相当于):

Ridable ridable = new Bike();
Performer 小张 = new RidableJuggler(10, ridable);

4.3、通过工厂方法创建Bean
1)有时静态工厂方法是实例化对象的唯一方法
2)Spring支持通过<bean>元素的factory-method属性来装配工厂创建的Bean

示例:考虑Idol选秀过程中参赛者展示才艺的唯一舞台---Stage类型对象,采用单例模式,单例只能通过静态工厂方法来获取引用

//采用"initialization on demand holder"技术
public class Stage{private Stage(){}private static class SingletonHolder{static Stage instance = new Stage();}public static Stage getInstance(){return SignletonHolder.instance;}
}

配置文件:

<bean id="theStage" class="com.javaee.spring.chineseIdol.Stage" factory-method="getInstance"/>

利用静态工厂方法定义的bean item,class属性不在是bean的全类名,而是静态工厂的全类名,而且还需要指定工厂里的getBean静态方法名字和参数
factory-method让spring知道这个类不是调用它的构造方法,而是调用静态工厂方法来获取实例的

5、Bean的作用域

5.1、Spring Bean默认都是单例
默认为singleton

5.2、配置Bean的 scope属性为prototype,允许Bean可以被实例化多次(每次调用创建一个实例)
singleton 只有一个实例,也即是单例模式。
prototype访问一次创建一个实例,相当于每次new

5.3、Spring的Bean作用域允许用户配置所创建的Bean属于哪种作用域,无需再Bean的实现里硬编码

6、初始化和销毁Bean

6.1、当实例化一个Bean时,可执行一些 初始化操作来确保Bean处于可用状态

6.2、当不再需要Bean时,将其从容器中移除时,可按顺序执行一些 清除工作

6.3、Spring提供Bean生命周期 钩子方法(回调方法)
  <bean>元素的 init-method属性制定在初始化Bean时要调用的方法
  <bean>元素的 destroy-method属性指定Bean从容器中移除之前要调用的方法

6.4、示例:Idol选秀表演大厅Auditorium,在表演前开灯、表演结束时关灯

public class Auditorium {public void turnOnLight() {...}public void turnOffLight() {...}
}

配置文件:

<bean id="auditorium" class="com.javaee.spring.chineseidol.Auditorium" init-method="turnOnLight" destory-method="turnOffLight"/>

6.5、默认的init-method和destory-method
使用<beans>元素的default-init-method和default-destory-method属性,为上下文中所有Bean设置共同的初始化和销毁方法,一般比较少用到

7、示例代码

例子演示: http://pan.baidu.com/s/1nvn0pMp
/*
 * 1)注入一个简单Bean,Spring调用默认的构造方法
 * 2)调用构造器,参数注入的方式
 * 3)构造器里面Bean引用的注入
 * 4)静态工厂方法注入Bean
 * 5)Bean的钩子方法的回调
 */

chinese-Idol.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"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsd"><!-- Bean declarations go here --><bean id="小李" class="com.javaee.spring.chineseIdol.Juggler"><constructor-arg value="10" /></bean><bean id="bike" class="com.javaee.spring.chineseIdol.Bike" /><bean id="小张" class="com.javaee.spring.chineseIdol.RidableJuggler"><constructor-arg value="11"/> <!-- 构造器参数注入基本类型 --><constructor-arg ref="bike"/> <!-- 构造器参数注入对象的引用 --></bean><bean id="theStage" class="com.javaee.spring.chineseIdol.Stage" factory-method="getInstance"/><bean id="auditorium"class="com.javaee.spring.chineseIdol.Auditorium"init-method="turnOnLight"destroy-method="turnOffLight"/>
</beans>

五、注入Bean属性

注入属性就是通过setter方法

1、注入简单值

1.1、一般来说JavaBean的字段是私有的,带有一组存取器方法( setXXX()和getXXX() )

1.2、Spring借住字段的set方法来配置字段的值,以实现setter方式的注入

1.3、示例:Idol秀来了一个有天赋的音乐演奏参赛者
需要有set方法

1.4、Spring中可以使用<property>元素配置Bean的属性--通过属性的setter方法来注入

<bean id="小王"class="com.javaee.spring.chineseIdol.Instrumentalist"><property name="song" value="memory"/>
</bean>

调用了song的set方法,并把value的值传进去

一旦Instrumentalist被实例化,Spring就会调用<property>元素所指定属性的setter方法为该属性注入值

1.5、<property>元素没有限制注入值的类型,value属性可以指定数值型(int、float、double等)以及boolean型

2、引用其他Bean

spring注入其他bean的引用

2.1、针对接口编程与依赖注入协作实现送耦合
上面的图片,注入了song和instrument接口

3、使用Spring的命名空间p装配属性

3.1、Spring的命名空间p提供了另一种Bean属性的装配方式

3.2、要使用命名空间p,需要在Spring的XML配置中增加一段声明:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd">

3.3、改写前面示例:

<bean id="小王" class="com.javaee.spring.chineseIdol.Instrumentalist"p:song="memory"p:instrument-ref="saxophone"/>

4、装配集合

当bean的一个字段是集合类型,怎么装配

4.1、当配置集合类型的Bean属性时,Spring提供4种类型的集合配置元素

4.2、当属性为任意的java.util.Collection类型时,<list>和<set〉在使用时可以互换

4.3、<map>和<props>分别对应java.util.Map和java.util.Properties,
<props>要求键和值都必须是String类型,<map>允许键和值是任意类型(Object对象)

示例装配List、Set

示例装配Map

5、装配空值

Spring可以为Bean的属性或构造器参数装配null值

<property name="someNonNullProperty"><null/></property>

比如某一个Bean的属性叫someNonNullProperty

理由:需要显示设为null值,或者覆盖自动装配的值

6、例子程序

<property>属性的说明
正确  <property name="song" value="memory" />
错误  <property name="song">memory</property>
错误原因:
cvc-complex-type.2.3: Element 'property' cannot have character [children], because the type's  content type is element-only.
cvc-complex-type.2.3: 元素 'property' 必须不含字符 [子级], 因为该类型的内容类型为“仅元素”。

例子演示: http://pan.baidu.com/s/1mh75O60
/*
 * 6)bean属性注入
 * 7)使用p空间方式属性注入
 * 8)装配集合
 */

chinese-Idol.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:p="http://www.springframework.org/schema/p"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsd">  <!-- 引入p空间 --><!-- Bean declarations go here --><bean id="小李" class="com.javaee.spring.chineseIdol.Juggler"><constructor-arg value="10" /></bean><bean id="bike" class="com.javaee.spring.chineseIdol.Bike" /><bean id="小张" class="com.javaee.spring.chineseIdol.RidableJuggler"><constructor-arg value="11"/> <!-- 构造器参数注入基本类型 --><constructor-arg ref="bike"/> <!-- 构造器参数注入对象的引用 --></bean><bean id="theStage" class="com.javaee.spring.chineseIdol.Stage" factory-method="getInstance"/><bean id="auditorium"class="com.javaee.spring.chineseIdol.Auditorium"init-method="turnOnLight"destroy-method="turnOffLight"/><bean id="saxophone" class="com.javaee.spring.chineseIdol.Saxophone" /><bean id="小王" class="com.javaee.spring.chineseIdol.Instrumentalist"><property name="song" value="memory" /><property name="instrument" ref="piano" /></bean><bean id="piano" class="com.javaee.spring.chineseIdol.Piano" /><bean id="小王2" class="com.javaee.spring.chineseIdol.Instrumentalist"p:song="memory"p:instrument-ref="saxophone" /><bean id="guitar" class="com.javaee.spring.chineseIdol.Guitar" /><bean id="小强" class="com.javaee.spring.chineseIdol.SuperInstrumentalist"><property name="instruments"><list><ref bean="saxophone" /><ref bean="piano" /><ref bean="guitar" /></list></property></bean>
</beans>

六、使用表达式装配

SpEL是Spring的EL表达式

0、SpEL导言

0.1、如果为属性装配的值在运行期才得到,需要使用表达式装配

0.2、Spring3引入Spring表达式语言SpEL,通过运行期执行的表达式将值装配到Bean的属性或构造器参数中

0.3、SpEL有许多特性:
  1)使用Bean的ID来引用Bean
  2)调用方法和访问对象属性
  3)对值进行算术、关系和匹配的运算
  4)正则表达式匹配
  5)集合操作

1、SpEL的基本原理

SpEL表达式的首要目标是 通过计算获得某个值

1.1、字面值

<property name="count" value="#{100}" />

格式:#{???}
#{}标记提示Spring标记里的内容是SpEL表达式

1.2、引用Bean、Properties和方法
SpEL能通过ID引用其它Bean

<property name="instrument" value="#{saxophone}">

通过Bean的引用,来注入对象
用了表达式之后,就不需要ref来注入Bean了
SpEL表达式可使用Bean的引用来获取Bean的属性

<bean id="小张" class="com.javaee.spring.chineseIdol.Instrumentalist><property name="song" value="#{小李.song}"/>
</bean>

SpEL可调用Bean的方法

<property name="song" value="#{songSelector.selectSong()}"/>

1.3、操作类
在SpEL中,使用T()运算符会访问类作用域的方法和常量(静态方法和静态常量)。T指Type,不需要实例,通过类型去访问
T(java.lang.Math) 返回一个java.lang.Math类的对象
T()运算符可以访问指定类的静态方法和常量

<property name="pi" value="#{T(java.lang.Math).PI}"/>
<property name="randomNumber" value="#{T(java.lang.Math).random()}"/>

2、在SpEL值上执行操作

SpEL提供了几种运算符,可用在表达式中的值上

2.1、访问集合成员
中括号[]运算符通过索引访问集合中的成员
中括号[]同样可以用来获取java.util.Map集合中的成员

2.2、查询集合成员
查询运算符:
.?[](查询出所有匹配项)

<property name="bigCities" value="#{cities.?[population gt 1000000]}"/>

找出城市人口大于100万的城市集合

.^[](查询出第一个匹配项)

<property name="first" value="#{cities.^[population gt 1000000]}"/>

.$[](查询出最后一个匹配项)

<property name="last" value="#{cities.$[population gt 1000000]}"/>

2.3、投影集合
从集合的每一个成员中选择特定的属性放入一个新的集合中
投影运算符.![]

<property name="cityNames" value="#{cities.![name]}"/>

3、例子程序

1) 需要引入p空间和util空间
2) 配置文件中出现的下标,数字都是int类型

例子程序: http://pan.baidu.com/s/1hsMNOS8

city.xml配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:p="http://www.springframework.org/schema/p"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:util="http://www.springframework.org/schema/util"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util.xsd"><bean id="city" class="bo.City"/><util:list id="cities"> <!-- 定义了一个集合Bean --><bean class="bo.City"><property name="name" value="上海"/><property name="state" value="上海"/><property name="population" value="20000000"/></bean><bean class="bo.City" p:name="北京" p:state="北京" p:population="10000001"/><bean class="bo.City" p:name="广州" p:state="广东" p:population="15000000"/><bean class="bo.City" p:name="南京" p:state="江苏" p:population="5000000"/><bean class="bo.City" p:name="深圳" p:state="广东" p:population="9000000"/></util:list><bean id="cityTest" class="bo.CityTest"><property name="chosenCity" value="#{cities[2]}"/><property name="bigCities" value="#{cities.?[population gt 10000000]}"/><property name="aBigCity" value="#{cities.^[population gt 5000000]}"/></bean></beans>

七、自动装配Bean属性

1、3种类型的自动装配

1.1、Spring提供几种技巧用于减少XML的配置数量
自动装配(autowiring)有助于减少甚至消除配置<property>元素和<constructor-arg>元素,让Spring自动识别如何装配Bean的依赖关系

自动监测(autodiscovery)比自动装配更进一步,让Spring能自动识别那些类需要被装配成Spring Bean,从而减少对<bean>元素的使用

2、Spring的3种自动装配策略

2.1、byName---把与Bean的属性具有相同名字或ID的其他Bean自动装配到Bean对应的属性中,若没有,该属性不被装配

2.2、byType---把与Bean的属性具有相同类型的其他Bean自动装配到Bean的对应属性中,若没有,该属性不被装配

2.3、constructor---把与Bean的构造器入参具有相同类型的其他Bean自动配到Bean构造器的对应入参中

3、byName自动装配

通过设置autowire属性为byName,为属性自动装配ID与该属性名字相同的Bean

autowire是bean元素的属性

到当前配置文件去找bean id的名字和该属性名字是否一致

4、byType自动装配

通过设置autowire属性为byType,为属性自动装配类型与该属性类型相同的Bean

限制:应用只允许存在一个Bean与需要自动装配的属性类型相匹配

使用<bean>元素的primary属性为自动装配标识一个首选Bean;为了使用primary属性,要将所有非首选Bean的primary属性设为false

通过设置<bean>元素的autowire-candidate属性为false,可以在自动装配时排除某些Bean

5、constructor自动装配

通过设置autowire属性为constructor,在构造器注入来配置Bean时,可以移除<constructor-arg>元素,由Spring在应用上下文中自动选择Bean注入到构造器入参中

和byType自动装配有相同的限制:应用只允许存在一个Bean与需要自动装配的属性类型相匹配

6、默认自动装配

如果需要为Srping应用上下文中的多数Bean配置相同的autowire属性,可以让Spring为它所创建的所有Bean应用相同的自动装配策略来简化配置

在配置文件的根元素<beans>上增加default-autowire属性

可以将default-autowire属性设置为任意一种有效的自动装配策略,将其应用于Spring配置文件中的所有Bean

可以在一个Spring应用上下文中定义多个配置文件,每个配置文件都可以有自己的默认自动装配策略

可以使用<bean>元素的autowire属性来覆盖<beans>元素所配置的默认自动装配策略

7、混合使用自动装配和显示装配

对某个Bean设置了自动装配策略后,仍然可以为任意一个属性配置<property>元素进行显示装配

混合使用自动装配和手工显示装配,可以解决使用byType自动装配策略可能产生的装配不确定性问题

8、bean的autowire属性(自动装配)和传统配置对比

autowire属性简化了<property>和<constructor-arg>

例子程序: http://pan.baidu.com/s/1c2vSvvy

传统通过配置文件来配置Bean:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsd"><!-- Bean declarations go here --><bean id="missile" class="uav.Missile"/><bean id="uav1" class="uav.Uav"><property name="missile" ref="missile"/> <!-- 通过property来配置 --></bean><bean id="uav2" class="uav.Uav"><constructor-arg ref="missile"/> <!-- 构造器方式装配 --></bean>
</beans>

自动装配:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsd"><!-- Bean declarations go here --><bean id="missile" class="uav.Missile"/><bean id="uav1" class="uav.Uav" autowire="byType"/><bean id="uav2" class="uav.Uav" autowire="constructor"/></beans>

八、使用注解装配

0、导言

0.1、从Spring2.5开始,增加了使用注解自动装配Bean属性的新方式,类似于在XML中使用autowire属性自动装配

0.2、使用注解方式允许更细粒度的自动装配,可以选择性的标注某一个属性来对其自动装配

0.3、Spring容器默认禁用注解装配,启用方式:
使用Spring的context命名空间配置中的<context:annotation-config/>元素,告知Spring开启使用基于注解的自动装配(属性、方法、构造器)

0.4、Spring3支持三种用于自动装配的注解:
1) Spring自带的@Autowired注解
2)JSR-330的@Inject注解
3)JSR-250的@Resource注解(对于资源的注入,比如数据库连接啊等等)

1、使用@Autowired

1.1、通常使用@Autowired标注setter方法,Spring会尝试对该方法执行byType自动装配

1.2、还可以使用@Autowired标注需要自动装配Bean引用的任意方法,包括构造器

1.3、 也可以使用@Autowired直接标注属性,并删除setter方法,且不受private限制

1.4、应用中必须确保只有一个Bean适合装配到@Autowired注解所标注的属性或参数中,如果没有匹配的Bean,或者存在多个匹配的Bean就会出错,解决方案:
1)可选的自动装配:设置@Autowired的required属性为false
2) 限制歧义性的依赖:@Qualifier注解,缩小自动装配候选Bean的范围
3)创建自定义的限定器:定义一个注解,使用@Qualifier注解作为它的元注解

2、借助@Inject实现基于标准的自动装配

2.1、Java依赖注入规范JSR-330制定了通用依赖注入模型

2.2、@Inject注解是JSR-330的核心部件,可完全替换Spring的@Autowired注解

2.3、和@Autowired注解一样,@Inject可以用来自动装配属性、方法和构造器,不同的是,@Inject没有required属性,因此@Inject注解所标注的依赖关系必须存在,否则抛异常

2.4、@Inject除了可直接注入一个引用,还可注入一个Provider,Provider接口可实现Bean引用的延迟注入以及注入Bean的多个实例

2.5、限定@Inject所标注的属性——为消除注解导致Bean定义的歧义,类似@Autowired的@Qualifier,@Inject对应有@Named注解,通过Bean的ID来标识可选择的Bean

2.6、创建自定义的JSR-330 Qualifier——JSR-330支持使用javax.inject包中的
@Qualifier注解来创建自定义的限定器注解,就像使用Spring的@Qualifier来创建自定义注解一样

3、在注解注入中使用表达式

3.1、Spring3引入了@Value装配注解来装配String类型和基本类型的值,可直接标注属性、方法或者方法参数

@Value("memory")
private String song;

3.2、传入@Value的String类型的参数只是一个表达式,它的计算结果可以是任意类型,所以@Value可标注任意类型的属性

3.3、借住SpEL表达式,@Value注解成为强大的装配可选方案,因为可以在运行期通过SpEL动态计算复杂表达式的值并把结果装配到Bean的属性中

@Value("#{properties.myFavoriteSong}")
private String song;

4、利用注解注入的配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsd"><context:annotation-config/><!-- Bean declarations go here --><bean id="missile" class="uav.autowired.Missile"/><bean id="m" class="uav.autowired.Missile"/><bean id="uav1" class="uav.autowired.Uav"/></beans>

什么是javax包:
javax是JavaEE的扩展包,一般都需要外部引入

例子程序: https://pan.baidu.com/s/1dFF3ptR

九、自动检测Bean

0、导言

0.1、Spring提供了<context:component-scan>元素,除了完成与<context:annotation-config>一样的工作,还可以自动检测和定义Bean
<context:annotation-config>实现了自动注入,但是我们要在xml文件里面手动定义Bean

0.2、有了<context:component-scan>元素,可以不使用<bean>元素,Spring应用中的大多数Bean能实现定义和装配

<context:component-scan base-package="com.javaee.spring.chineseIdol">
</context:component-scan>

0.3、<context:component-scan>元素会扫描指定的包及其所有子包,并查找出能够自动注册为Spring Bean的类

1、为自动检测标注Bean

1.1、默认情况下,<context:component-scan>查找使用 构造型注解所标注的类
1)@Component—通用的构造型注解,标识该类为Spring组件
2)@Controller—标识将该类定义为Spring MVC controller(过滤器组件)
3)@Repository—标识将该类定义为数据仓库(数据存储)
4)@Service—标识将该类定义为服务
5)使用@Component标注的任意自定义注解

2、过滤组件扫描

2.1、通过<context:component-scan>配置<context:include-filter>和/或者<context:exclude-filter>子元素,可以随意调整扫描策略
包含过滤器和排除过滤器

<context:component-scanbase-package="com.javaee.spring.chineseIdol"><context:include-filter type="assignable"expression="com.javaee.spring.chineseIdol.Instrument"/>
</context:component-scan>

2.2、<context:include-filter>的type和expression属性一起协作来定义组件扫描策略
assignable代表继承

2.3、上例实现了——要求只有派生于Instrument的所有类自动注册为String Bean

2.4、使用5种过滤器类型的任意一种来自定义组件扫描方式

2.5、还可以使用<context:exclude-filter>来告知<context:component-scan>哪些类不需要注册为Spring Bean

3、例子程序: http://pan.baidu.com/s/1sl6Xvqt

配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsd"><context:component-scan base-package="uav.scan"/><!-- Bean declarations go here --></beans>

十、使用Spring基于Java的配置

1、创建基于Java的配置

1.1、Spring的Java配置可以让我们不使用XML就可以编写多数Spring配置

1.2、但需要少量的XML来启动Java配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsd"><context:component-scan base-package="com.javaee.spring.chineseIdol"/></beans>

1.3、除了自动注册特定构造型标注的Bean之外,<context:component-scan>也会自动加载 @Configuration注解所标注的类

2、定义一个配置类

2.1、在基于Java的配置中使用@Configuration注解的Java类,等价于XML配置中的 <beans>元素(根元素)

2.2、@Configuration注解作为一个线索告知Spring:这个类将包含一个或多个Spring Bean的声明,这些Bean的声明是使用@Bean注解所标注的方法

package com.javaee.spring.chineseIdol;
import org.springframework.context.annotation.Configuration;@Configuration
public class ChineseIdolConfig {// Bean declaration methods go here
}

3、声明一个简单的Bean

@Bean
public Performer 小李() {return new Juggler();
}

3.1、该方法就是Java配置,等价于之前使用XML配置的<bean>元素

3.2、@Bean告知Spring该方法将返回一个对象,该对象应被注册为Spring应用上下文中的一个Bean。方法名作为该Bean的ID,该方法中的实现逻辑是为了创建Bean

4、使用Spring的基于Java的配置进行注入

4.1、使用Spring基于Java的配置涉及编写一个返回类实例的方法

4.2、实现注入
1)为Bean注入一个值,使用基于Java的配置,只需把数字直接传入构造器中

@Bean
public Performer 小李10() {return new Juggler(10);
}

2)Setter注入

@Bean
public Performer 小李() {Instrumentalist 小李 = new Instrumentalist();小李.setSong("memory");return 小李;
}

3)为Bean装配另一个Bean的引用

@Bean
private Ridable bike() {return new Bike();
}
@Bean
public Performer 小张() {return new RidableJuggler(bike());
}

4)注意:在Spring的Java配置中,通过声明方法引用一个Bean并不等同于调用该方法。
通过使用@Bean注解标注某方法,即告知Spring该方法定义的Bean要被注册进Spring的应用上下文中,那么在其他Bean的声明方法中引用该方法时,Spring都会拦截该方法的调用,并尝试在应用上下文中查找该Bean,而不是让方法创建一个新实例

十一、小结

1、装配Bean的三种主要方式:

1)自动化配置
2)基于Java的配置
3)基于XML的配置

2、c命名空间

3、p命名空间

Spring框架(JavaEE开发进阶Ⅲ)—基础和IoC相关推荐

  1. Spring 框架 详解 (四)------IOC装配Bean(注解方式)

    Spring的注解装配Bean Spring2.5 引入使用注解去定义Bean @Component  描述Spring框架中Bean Spring的框架中提供了与@Component注解等效的三个注 ...

  2. spring框架 web开发_go语言web开发框架:Iris框架讲解(一)

    Golang介绍 Go语言是谷歌推出的一种全新的编程语言,可以在不损失应用程序性能的情况下降低代码的复杂性.谷歌首席软件工程师罗布派克(Rob Pike)说:我们之所以开发Go,是因为过去10多年间软 ...

  3. spring框架 web开发_go语言web开发框架学习:Iris框架讲解(一)

    Golang介绍 Go语言是谷歌推出的一种全新的编程语言,可以在不损失应用程序性能的情况下降低代码的复杂性.谷歌首席软件工程师罗布派克(Rob Pike)说:我们之所以开发Go,是因为过去10多年间软 ...

  4. 如何利用spring框架来开发一个简单的小项目——书店项目

    这里我将用spring来开发一个简单的书店项目 Step1:所用到的开发软件为 idea , 所用到的jar包为 这些jar的下载可在 官网 下载,选择5.2.6版本下载,不会的在下面评论私信 Ste ...

  5. Qt 框架性开发实践——基础框架篇

    基于 Qt 的组件合成框架https://blog.csdn.net/luansxx/article/details/120668676 基于 Qt 的消息总线https://blog.csdn.ne ...

  6. 007.androidUI开发进阶(基础--案例) .

    1.Dialog有四种,分别是AlertDialog,ProgressDialog,DatePickerDialog,TimePickerDialog 1.1AlertDialog public cl ...

  7. spring框架三种类型项目实现--基础maven类型、纯注解开发型、aop结合注解开发型

    spring框架实现 1.基础maven类型 1.开发准备--pom.xml添加spring依赖 2.创建properties文件 还是三层架构开发 3.domain层创建实体类javabean 4. ...

  8. JAVAWEB开发之Spring详解之——Spring的入门以及IOC容器装配Bean(xml和注解的方式)、Spring整合web开发、整合Junit4测试

    Spring框架学习路线 Spring的IOC Spring的AOP,AspectJ Spring的事务管理,三大框架的整合 Spring框架概述 什么是Spring?  Spring是分层的Java ...

  9. Spring高级程序设计(Spring框架创始人倾情推荐的权威开发指南)

    Spring高级程序设计(Spring框架创始人倾情推荐的权威开发指南) 市场价 :¥99.00 会员价 : ¥74.25(75折) 样章免费试读:http://www.china-pub.com/1 ...

最新文章

  1. SQL2000输入的值与数据类型不一致,或者此值与列的长度不一致“
  2. mysql和mariadb对比_MySQL并发复制系列三:MySQL和MariaDB实现对比
  3. C#实现水晶报表绑定数据并实现打印
  4. “网红” WebAssembly 与 K8s 如何实现双剑合璧?
  5. C#中提示:当前上下文中不存在名称“ConfigurationManager”
  6. JZOJ 5410. 【NOIP2017提高A组集训10.22】小型耀斑
  7. sizeof 数组_简单的一维数组竟然有这么多坑?
  8. 华为面试改革,我们该怎么跟进?
  9. 面向对象chapter10
  10. mysql每10万条数据分区_WebGIS项目中利用mysql控制点库进行千万条数据坐标转换时的分表分区优化方案...
  11. js中apply、call和bind的区别
  12. 添加样式(后台给字段note(left,height-auto ))
  13. 使用javascript操作cookies的实例
  14. VMWARE 之 vSphere vCenter 安装基本配置
  15. JAVA核心技术卷1 corejava.zip 下载地址
  16. 数字图像处理 冈萨雷斯 (第四版) 比特平面分层,图像重建
  17. NXP IMX6ULL芯片时钟系统全概况
  18. PGP Shredder的使用,加密解密
  19. USRPx310的底板介绍
  20. Facebook新研究:根据照片自动生成卡通头像

热门文章

  1. 解决vue项目中的前端跨域问题
  2. 黑苹果修复重启_修复了随机重启问题
  3. 软件的国际化与本地化
  4. Linux学习--09
  5. 分立器件和集成电路不都是芯片吗?它们有什么区别?
  6. Pyecharts笔记(10)-模仿PBI的卡片图
  7. 背单词类APP测试与评估
  8. 湖南省计算机等级考试(二级)题库 第二部分
  9. Mac上检测系统性能工具:Geekbench
  10. 工地人员设备定位管理系统