Spring 简介与入门
Spring 简介 <ul><li>与 Hibernate 、 Struts 一样, Spring 也是一个开源项目,它的作者是 Rod Johnson ,官方网站是 http://www.springframework.org/ 。 </li...
Spring 简介 <ul><li>Rod Johnson 是悉尼大学博士, </li></ul><ul><li> 猜猜他的专业是什么? </li></ul><ul><li>Rod Johnson 在开发出 Spring </li></ul><...
Spring 简介 <ul><li>Spring 核心技术包括两个方面,一是控制反转( Inversion of Control, IoC ),另一个是面向方面编程( Aspect Oriented Programming, AOP )。 </...
Spring 简介
Spring 简介
Spring 技术基础 <ul><li>Spring 的核心是 IoC 和 AOP ,它们都是由 Java 原有技术发展而来的。 </li></ul><ul><li>IoC 技术是通过 Java 的反射机制以及 JavaBean 的自省机制实现...
反射机制 <ul><li>Java 的反射机制允许程序在运行时动态加载对象,并且动态地调用其中的方法。 </li></ul><ul><li>JFC 中的 java.lang.reflect 包便提供了这种支持,主要是通过 java.lang.C...
反射机制 <ul><li>public Object myInvoke(String className, String methodName, Object args[]) { </li></ul><ul><li>Object results...
反射机制 <ul><li>使用时指明类名和方法名: </li></ul><ul><li>class SomeToBeInvoke { </li></ul><ul><li>public int calculate(int i) { </li></...
Class 类 <ul><li>java.lang.Class 代表一个类,可以通过三种方式得到 Class 的实例: </li></ul><ul><li>Object.getClass() </li></ul><ul><li>Class.fo...
Class 类 <ul><li>可以通过 Class 加载类并了解类的内部结构: </li></ul><ul><li>获取构造函数: Constructor getConstructor(Class[] parameterTypes)  Con...
Field 类 <ul><li>java.lang.reflect.Field   代表属性,是 java.lang.reflect.AccessibleObject   的子类,故可以调用其 setAccessible 方法访问 privat...
Method 类 <ul><li>java.lang.reflect.Method   代表类中的方法,它也是 java.lang.reflect.AccessibleObject 的子类,可以通过 setAccessible 访问 priva...
Contructor 类 <ul><li>java.lang.reflect.Constructor 代表构造函数,是 java.lang.reflect.AccessibleObject 的子类,可以通过 setAccessible 访问 p...
JavaBean 自省机制 <ul><li>JavaBean 的属性一般都具有 getter 方法和 setter 方法,通过这些方法可以更改或读取 JavaBean 属性。 </li></ul><ul><li>JavaBean 具有的自省机制...
Introspector <ul><li>自省机制是使用 Introspector 实现的。 </li></ul><ul><li>Introspector 的方法大部分都是静态的,可以直接调用,如 getBeanInfo(Class beanC...
PropertyDescriptor  <ul><li>PropertyDescriptor  代表了属性,可以通过它得到属性的 getter 方法和 setter 方法。即 : </li></ul><ul><li>Method getRead...
<ul><li>所谓代理模式即是由代理对象接管对象访问,用户在使用时感觉是在原始对象操作,但实际是通过代理对象访问的原始对象。 </li></ul><ul><li>Java 为代理模式提供了内置的支持,这是通过 java.lang.reflec...
代理( Proxy )模式 <ul><li>所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动。 </li></ul><ul><li>在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到...
代理模式的结构
代理模式的角色 <ul><li>抽象主题角色:声明了真实主题和代理主题的共同接口,这样在任何可用真实主题的地方都可以使用代理主题。 </li></ul><ul><li>代理主题角色:代理主题角色内部含有对真实主题的引用,从而可以在任何时候操作真...
代理模式的时序
装配 Bean
IoC 与 Bean 装配 <ul><li>在 Spring 中,对象间的协作是通过 IoC 机制完成的。 </li></ul><ul><li>反向控制也叫依赖注入( Dependency Injection , DI ),简单来说就是将 Ja...
Bean 容器 <ul><li>ApplicationContext 与 BeanFactory 都是接口, ApplicationContext 是由 BeanFactory 接口扩展而来,它增强了 BeanFactory 的功能。 </li...
BeanFactory <ul><li>以下是 BeanFactory 声明的方法,都是与 Bean 装配相关的: </li></ul><ul><li>boolean containsBean(String name)  </li></ul><...
BeanFactory <ul><li>Spring 给出一些 BeanFactory 的实现类,其中最为常用的是 XmlBeanFactory 。 </li></ul><ul><li>1 、通过文件系统 </li></ul><ul><li>R...
Resource <ul><li>创建 XmlBeanFactory 时需要以 Resource 作为构造函数的参数。 </li></ul><ul><li>Resource 接口位于 org.springframework.core.io  包...
Resource <ul><li>实现了 Resource 接口的类包括: </li></ul><ul><li>AbstractResource,  </li></ul><ul><li>ByteArrayResource,  -- byte[]...
Resource <ul><li>Resource 中定义了以下方法: </li></ul><ul><li>Resource createRelative(String relativePath)  </li></ul><ul><li>bool...
装配 Bean <ul><li>通常可以通过三种方式装配 Bean </li></ul><ul><li>通过 setter 方法 </li></ul><ul><li>通过构造函数 </li></ul><ul><li>自动装配 </li></ul...
装配 Bean <ul><li>无论使用 BeanFactory 还是 Applicationcontext 均可以视之为容器,使用的 Bean 必须向容器注册。 </li></ul><ul><li>注册是通过在配置文件中加入 Bean 声明:...
装配 Bean <ul><li><!ELEMENT bean ( </li></ul><ul><li>description?, </li></ul><ul><li>(constructor-arg |  </li></ul><ul><li>p...
原型或单例 <ul><li>如下代码的执行结果是什么? </li></ul><ul><li>FirstBean bean = (FirstBean)factory.getBean(&quot;my&quot;); </li></ul><ul><...
原型或单例 <ul><li>BeanFactory 维护所有单例 bean ,也即维护了对单例 bean 的引用,因此 factory 只知道创建单例 bean 的数目,而无从知晓原型 bean 。 </li></ul><ul><li>原型 b...
延迟加载 <ul><li>如下代码执行的结果是什么? </li></ul><ul><li>System.out.println(&quot;before loading&quot;); </li></ul><ul><li>FirstBean b...
初始化与清理 <ul><li>在许多情况下,需要在对象加载后立即初始化资源,而在删除对象前先清理资源 </li></ul><ul><li>在 spring 中,提供了两种方式实现初始化和清理工作。 </li></ul><ul><li>通过设置 ...
初始化与清理 <ul><li><bean id=&quot;first&quot; class=&quot;mybeans.FirstBean&quot; init-method=&quot;init&quot; destroy-method=...
初始化与清理 <ul><li>通过 InitializingBean 和 DisposableBean. </li></ul><ul><li>InitializingBean 接口中仅定义了一个方法,即 void  afterPropertie...
初始化与清理 <ul><li>初始化与清理的次序 </li></ul><ul><li>无论是哪种初始化方式,都是在 bean 构造完毕,并且 属性已经注入 到对象中后才执行的。 </li></ul><ul><li>初始化时, Initializ...
Setter 装配 <ul><li>在配置文件中, <bean> 元素的 <property> 元素 指明了使用属性的 setter 方法注入依赖。 </li></ul><ul><li><!ELEMENT property ( </li></u...
Setter 装配- 装配种类 <ul><li>可以通过 setter 方法加载以下类型的属性: </li></ul><ul><li>基本类型 </li></ul><ul><li>Bean 类型 </li></ul><ul><li>内部 bea...
Setter 装配-基本类型 <ul><li>装配基本类型: </li></ul><ul><li>包括八种基本类型及它们的包装类,还有 String 类型。 </li></ul><ul><li>不必关心具体类型, spring 可以通过反射机制...
Setter 装配-基本类型 <ul><li><bean id=&quot;first&quot; class=&quot;mybeans.FirstBean&quot; >  </li></ul><ul><li><property name=...
Setter 装配- bean 类型 <ul><li>装配 bean 类型属性: </li></ul><ul><li>只有通过配置文件向容器注册的 bean 才能通过注入机制设置到其它 bean 的属性上。 </li></ul><ul><li>...
Setter 装配- bean 类型 <ul><li><bean id=&quot;first&quot; class=&quot;mybeans.FirstBean&quot;>  </li></ul><ul><li><property na...
Setter 装配- bean 类型 <ul><li>内部 Bean </li></ul><ul><li><bean id=&quot;outer&quot; class=&quot;...&quot;> </li></ul><ul><li><...
Setter 装配-集合类型 <ul><li>Spring 支持以下四种集合的装配: </li></ul><ul><li><list> -- java.util.List </li></ul><ul><li><set> -- java.util...
Setter 装配- list 集合 <ul><li><property name=&quot;someList&quot;> </li></ul><ul><li><list> </li></ul><ul><li><value>someValu...
Setter 装配- set 集合 <ul><li><property name=&quot;someSet&quot;> </li></ul><ul><li><set> </li></ul><ul><li><value>just some s...
Setter 装配- map 集合 <ul><li><property name=&quot;someMap&quot;> </li></ul><ul><li><map> </li></ul><ul><li><entry> </li></ul>...
Setter 装配- props 集合 <ul><li><property name=&quot;people&quot;> </li></ul><ul><li><props> </li></ul><ul><li><prop key=&quot...
Setter 装配-设置 null <ul><li>如果希望将属性设置为空,使用以下方法不能达到目的: </li></ul><ul><li><property name=&quot;age&quot; > </li></ul><ul><li><...
构造装配 <ul><li>构造装配通过构造函数装配 bean 属性,一般在以下情况下使用: </li></ul><ul><li>属性没有 setter 方法,是只读属性 </li></ul><ul><li>属性只需要设置一次,以后就不会再更改 ...
构造装配 <ul><li><bean id=&quot;first&quot; class=&quot;mybeans.FirstBean&quot;>  </li></ul><ul><li><constructor-arg> </li></u...
自动装配 <ul><li>可以通过 spring 框架自动为 bean 装配属性。 </li></ul><ul><li>自动装配只能装配 bean 类型,即取代 ref 元素。 </li></ul><ul><li>使用自动装配只需在 bean ...
自动装配类型 <ul><li>“ no“ -不使用自动装配, spring 推荐。 </li></ul><ul><li>“ byName” -依据名称或 ID 装配 bean ,如果没有找到,则不装配 </li></ul><ul><li>“ b...
装配 Bean <ul><li>通过 BeanFactory 获取 Bean 与直接 new 一个 Bean 是完全不同的。 </li></ul><ul><li>通过 BeanFactory 获取的 bean 能将所有依赖注入到 bean 中,...
ApplicationContext <ul><li>ApplicationContext 与 BeanFactory 的作用相类似,都起到装配、管理 Bean 的作用。 </li></ul><ul><li>不同的是, ApplicationC...
ApplicationContext <ul><li>ApplicationContext 接口由以下接口扩展而来: </li></ul><ul><li>ListableBeanFactory -可以列出所有 bean </li></ul><u...
面向切面- AOP
AOP 简介 <ul><li>AOP 最初由  Gregor Kiczales 在施乐的 Palo Alto 研究中心领导的一个研究小组于 1997 年提出。 </li></ul><ul><li>目前,宣称能够支持 AOP 的项目已达近百种, ...
AOP 简介 <ul><li>AOP 是 OOP 的延续,是 Aspect Oriented Programming 的缩写,意思是面向方面编程。  </li></ul><ul><li>它将分布在各个类中具有相同功能的代码片段整合到一起,由单独...
AOP 简介
AOP 术语 <ul><li>切面( Aspect ):从对象中抽取出来的交叉功能模块 </li></ul><ul><li>通知( Adivice ):切面的具体实现 </li></ul><ul><li>连接点( Joinpoint ):可以插...
AOP 术语 <ul><li>目标对象( Target Object ): </li></ul><ul><li>被通知的对象 </li></ul><ul><li>代理( AOP Proxy ): </li></ul><ul><li>由 AOP ...
AOP 实现技术 <ul><li>目前,人们使用传统语言对核心业务进行编程,对横切面的功能模块则使用面向切面的编程语言。 </li></ul><ul><li>面向切面的编程语言可以是已有编程语言的扩展,如 AspectJ , AspectC++...
AOP 实现技术 <ul><li>Spring 使用两种机制实现 AOP 技术,一是使用 java 的动态代理,即 java.lang.reflect.Proxy 类创建代理。 </li></ul><ul><li>二是使用 CGLIB 库自动生...
AOP 实现技术 <ul><li>由于目前 AOP 还没有完全的统一标准,因此实现出来的 AOP 框架也是多种多样的,为此人们成立了一个 AOP 联盟,用于统一这种混乱局面 </li></ul><ul><li>Aop Alliance 是由多个...
AOP 快速入门 <ul><li>背景:课程在开课前应该向任课老师发出上课通知。 </li></ul><ul><li>创建步骤: </li></ul><ul><li>创建目标对象,目标对象必须是实现了某种接口的。 </li></ul><ul><...
AOP 快速入门-创建目标 <ul><li>public class J2eeCourse implements Course { </li></ul><ul><li>String name; </li></ul><ul><li>public ...
AOP 快速入门-创建目标 <ul><li>使用 Java 动态代理机制实现的 AOP 必须要将目标对象中的方法声明在一个接口中: </li></ul><ul><li>public interface Course { </li></ul><u...
AOP 快速入门-创建通知 <ul><li>此处创建的是前置通知: </li></ul><ul><li>public class CourseAdvice implements MethodBeforeAdvice { </li></ul><u...
AOP 快速入门-注册 <ul><li><beans> </li></ul><ul><li><bean id=&quot;courseTarget&quot; class=&quot;aop.J2eeCourse&quot;> </li></u...
通知的类型 <ul><li>通知是切面的具体实现,在 Spring 中通知被分为以下几种类型: </li></ul>
通知的类型 <ul><li>除 MethodInterceptor (环绕通知)是由 aop alliance 定义以外,其余接口均位于 org.springframework.aop 中 </li></ul><ul><li>MethodInt...
切入点 <ul><li>切入点用于定义通知加入到目标对象中的位置,没有切入点通知将被应用于所有方法上。 </li></ul><ul><li>Spring 以 org.springframework.aop.PointCut 来定义切入点。 </...
切入点
Advisor 概述 <ul><li>由于 ProxyFactoryBean 只接受 Advice 和 Advisor 类型的 Interceptor (参照 API ),所以不能直接应用 PointCut 到 ProxyFactoryBean...
Advisor 概述 <ul><li>public interface  Advisor  { </li></ul><ul><li>Advice  getAdvice ();       </li></ul><ul><li>boolean  i...
内置切入点 <ul><li>静态切入点 </li></ul><ul><li>StaticMethodMatcherPointcut (抽象) </li></ul><ul><li>NameMatchMethodPointcut -名字匹配 </l...
名称匹配 <ul><li>在 NameMatchMethodPointcut 中,除了定义了一般 PointCut 的方法外,还定义了以下一些方法: </li></ul><ul><li>void  setMappedName (String m...
相应 Advisor <ul><li>与 NameMatchMethodPointcut 对应的 Advisor 是 NameMatchMethodPointcutAdvisor 。 </li></ul><ul><li>在 NameMatchM...
相应 Advisor <ul><li><bean id=&quot;advice&quot; class=&quot;aop.CourseAdvice&quot;/> </li></ul><ul><li><bean id=&quot;advis...
正则表达式匹配 <ul><li>通过直接指定方法的办法简单有效,但如果在大型系统中,方法较多的情况下,一个个指出通知的方法名则会显得臃肿。 </li></ul><ul><li>JdkRegexpMethodPointcut 使用正则表达式的形式...
正则表达式匹配 <ul><li>无论是 JDK 版本的,还是 Perl5 版本的,它们都是由 AbstractRegexpMethodPointcut 继承而来,这个方法中定义以下两个方法: </li></ul><ul><li>void set...
相应 Advisor <ul><li>与这两个 PointCut 对应的 Advisor 都是 RegexpMethodPointcutAdvisor   </li></ul><ul><li>Pointcut getPointcut()  </...
相应 Advisor <ul><li><bean id=&quot;advisor&quot; class=&quot;org.springframework.aop.support.RegexpMethodPointcutAdvisor&qu...
数据层应用
DAO 支持 <ul><li>Spring 提供了对数据层的广泛支持,这包括: </li></ul><ul><li>传统 JDBC </li></ul><ul><li>Hibernate </li></ul><ul><li>JDO </li><...
JDBC 方式 <ul><li>Spring JDBC 方式采用 模板 与 回调 相结合的模式,核心类是 JdbcTemplate 。 </li></ul>
JDBC 方式 <ul><li>使用 JDBC 方法处理 DAO ,必须要知道数据源 DataSource 。 </li></ul><ul><li>Spring DAO 层中,获取数据源方法有三种: </li></ul><ul><li>通过 J...
DriverManagerDataSource <ul><li>为了方便测试, Spring 提供了简便易用的 DataSource 实现,即 DriverManagerDataSource ,可直接创建 : </li></ul><ul><li...
DriverManagerDataSource <ul><li>也可以通过 IOC 机制注入: </li></ul><ul><li><bean id=&quot;dataSource&quot; class=&quot;org.springfr...
第三方连接池 <ul><li>最常使用的第三方连接池是 Apache 的 jakarta common dbcp 项目。这里主要使用的是 org.apache.commons.dbcp.BasicDataSource </li></ul><ul...
第三方连接池 <ul><li><bean id=&quot;newDs&quot; class=&quot;org.apache.commons.dbcp.BasicDataSource&quot;> </li></ul><ul><li><pr...
JNDI 方式 <ul><li><bean id=&quot;dataSource&quot; class=&quot;org.springframework.jndi.JndiObjectFactoryBean&quot;> </li></u...
JdbcTemplate <ul><li>总的来说, Spring 在支持 JDBC 访问数据库时采用了模板与回调相结合的方式。其中: </li></ul><ul><li>JdbcTemplate 是模板; </li></ul><ul><li>...
JdbcTemplate 查询 <ul><li>依据模板回调原则, Spring 定义了以下查询方法: </li></ul><ul><li>Object query(PreparedStatementCreator psc, ResultSet...
JdbcTemplate 查询 <ul><li>Spring 提供了一些简便的查询方法: </li></ul><ul><li>1.  temp. queryForList (&quot;select * from building&quot;)...
JdbcTemplate 更新 <ul><li>依据模板回调原则, Spring 定义了以下更新方法: </li></ul><ul><li>int update(PreparedStatementCreator psc)  </li></ul>...
JdbcTemplate 更新 <ul><li>为了方便, Spring 同样定义更新使用的方法: </li></ul><ul><li>int update(String sql) </li></ul><ul><li>int update(St...
映射对象 <ul><li>Spring 同 Hibernate 类似,也可以将查询结果映射成对象,但这需要用户自定义。 </li></ul><ul><li>这是通过 SqlQuery 和 SqlUpdate 类实现的,前者用于查询,后者用于更新...
映射对象
映射对象
整合 Hibernate <ul><li>Hibernate 的核心是 SessionFactory ,它就像 JDBC 中的 DataSource 一样。 </li></ul><ul><li>Spring 提供了以 IOC 机制导入 Sess...
整合 Hibernate
整合 Hibernate <ul><li>在应用上, Spring 也提供了模板与回调模式来实现 Hibernate 对数据库的操作。 </li></ul><ul><li>HibernateTemplate 是模板,而 HibernateCal...
整合 Hibernate <ul><li>类似于 JdbcTemplate , HiberateTemplate 中也加入了一些简便的方法,可以实现增、删改操作。 </li></ul><ul><li>这些方法基本都可以在 Hibernate 的...
表述层应用
集成 Struts <ul><li>Spring 提供了三种集成 Struts 的方法: </li></ul><ul><li>显式集成 </li></ul><ul><li>Action 代理 </li></ul><ul><li>RequestP...
显式集成 <ul><li>显示集成 Struts 时要求所有需要使用 Spring 的 Action 都必须通过显式继承 ActionSupport ,位于 org.springframework.web.struts.   包中 </li><...
Action 代理 <ul><li>Action 代理方式集成 Struts 需要将所有 Action 的地址都映射到 DelegatingActionProxy 上,位于 org.springframework.web.struts 包中。 ...
Action 代理 多模块时,路径如何写?
RequestProcessor 代理 <ul><li>RequestProcessor 代理的方式是改写了模块控制器,要求模块控制器必须是 DelegatingRequestProcessor 。 </li></ul><ul><li>这时,所...
Spring 事务支持 <ul><li>Spring 最为自豪的当属事务管理,因为它在不使用 EJB 服务器的情况下,实现了对事务的宣称式支持。这在以往是仅能由 Session Bean 提供的功能。 </li></ul><ul><li>Spr...
Spring 事务支持
Spring 事务支持 注:以上类均实现了 PlatformTransactionManager
Spring 事务支持 <ul><li>由于不同的平台实现事务管理采用的是不同的资源,例如 JDBC 使用直接使用 Connection 管理事务,而 Hibernate 则使用 Session 。 </li></ul><ul><li>在实现上...
Spring 事务支持
Spring 事务支持 <ul><li>与 EJB 相同, Spring 对事务的支持也分为编程式和宣称式两种(对应 EJB 的 BMT 和 CMT )。 </li></ul><ul><li>在 编程式 事务管理中, Spring 依然采用了模...
编程式事务管理 <ul><li>Spring 提供了两种方式实现编程式事务管理: </li></ul><ul><li>1 、使用 TransactionTemplate 与 TransactionCallback 结合。 </li></ul><...
编程式事务管理 <ul><li>使用 TransactionTemplate 时,在其内部仍然要知道具体的事务管理平台,即 PlatformTransactionManager 。这可以通过 IOC 机制注入。如 </li></ul>
编程式事务管理
编程式事务管理 <ul><li>事实上, Spring 为模板提供了两个回调类,即 TransactionCallbackWithoutResult   和 TransactionCallback   ,前者是后者的实现,并且是一个抽象类。 <...
编程式事务管理 <ul><li>也可直接使用 PlatformTransactionManager : </li></ul>
宣称式事务 <ul><li>Spring 宣称式事务与 Session Bean 的 CMT 事务管理在使用上极为相似,但是在很多方面 Spring 要优于 EJB : </li></ul><ul><li>EJB 事务管理是绑定在 JTA 上的...
宣称式事务 <ul><li>Spring 的宣称式事务管理实际上是应用了 Spring 的 AOP 特性,将事务管理的代码织入到原代码中。 </li></ul><ul><li>使用的代理类是 TransactionProxyFactoryBea...
宣称式事务
传播行为
传播行为
Upcoming SlideShare
Loading in …5
×

Spring框架

2,180 views

Published on

Spring框架 概述

Published in: Technology, Education
  • Be the first to comment

Spring框架

  1. 1. Spring 简介与入门
  2. 2. Spring 简介 <ul><li>与 Hibernate 、 Struts 一样, Spring 也是一个开源项目,它的作者是 Rod Johnson ,官方网站是 http://www.springframework.org/ 。 </li></ul><ul><li>Spring 的基础思想来源于 Rod Johnson 的一本著名的 j2ee 书籍: Expert One-on-One J2EE Design and Development 。在这本书中, Rod Johnson 列举 EJB 的种种问题,并提出了相应的解决办法。 </li></ul><ul><li>从那时起,人们对于 EJB 的狂热追捧才算结束,转而进入更理性的时代。 </li></ul>
  3. 3. Spring 简介 <ul><li>Rod Johnson 是悉尼大学博士, </li></ul><ul><li> 猜猜他的专业是什么? </li></ul><ul><li>Rod Johnson 在开发出 Spring </li></ul><ul><li> 之前,主要从事项目开发咨询 </li></ul><ul><li> 与培训工作。在 Spring 被广泛认可之后,创办了 interface21 公司,致力于 Spring 咨询与培训 </li></ul><ul><li>Rod Johnson 还是 JDO2.0 和 Servlet2.4 专家组成员。 </li></ul>
  4. 4. Spring 简介 <ul><li>Spring 核心技术包括两个方面,一是控制反转( Inversion of Control, IoC ),另一个是面向方面编程( Aspect Oriented Programming, AOP )。 </li></ul><ul><li>Spring 囊括了十分丰富的内容,包括表述层、数据层,它提供了许多原来只有 EJB 才能提供的功能(如宣称式的事务管理),但 Spring 又无须运行在 EJB 容器上。 </li></ul><ul><li>无论 Spring 涉足到哪一个领域,使用的都是简单的 JavaBean ,一般无须再实现复杂的接口。 </li></ul>
  5. 5. Spring 简介
  6. 6. Spring 简介
  7. 7. Spring 技术基础 <ul><li>Spring 的核心是 IoC 和 AOP ,它们都是由 Java 原有技术发展而来的。 </li></ul><ul><li>IoC 技术是通过 Java 的反射机制以及 JavaBean 的自省机制实现的 </li></ul><ul><li>AOP 技术是依赖代理模式实现的, JFC 中提供了对代理模式的内在支持, Spring 也是通过这种技术实现的。 </li></ul><ul><li>为了能够理解 Spring 的 IoC 机制,下面对反射机制和自省机制做简单介绍。 </li></ul>
  8. 8. 反射机制 <ul><li>Java 的反射机制允许程序在运行时动态加载对象,并且动态地调用其中的方法。 </li></ul><ul><li>JFC 中的 java.lang.reflect 包便提供了这种支持,主要是通过 java.lang.Class 、 java.lang.reflect.Method 、 Field 、 Constuctor 等类完成这项工作的。 </li></ul><ul><li>例如,如果有下面的方法: </li></ul><ul><li>Object myInvoke(String class, </li></ul><ul><li>String methodName, </li></ul><ul><li>Objec[] args) </li></ul><ul><li>实现动态调用某一类的某一方法,该如何实现? </li></ul>
  9. 9. 反射机制 <ul><li>public Object myInvoke(String className, String methodName, Object args[]) { </li></ul><ul><li>Object results = null; </li></ul><ul><li>try { </li></ul><ul><li>Class clazz = Class.forName(className); </li></ul><ul><li>Method method = null; </li></ul><ul><li>for (int i = 0; i < clazz.getMethods().length; i++) { </li></ul><ul><li>method = clazz.getMethods()[i]; </li></ul><ul><li>if(methodName.equals(method.getName())) { </li></ul><ul><li>results = method.invoke(clazz.newInstance(), args); </li></ul><ul><li>break; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>} catch (Exception e) { </li></ul><ul><li>e.printStackTrace(); </li></ul><ul><li>} </li></ul><ul><li>return results; </li></ul><ul><li>} </li></ul>
  10. 10. 反射机制 <ul><li>使用时指明类名和方法名: </li></ul><ul><li>class SomeToBeInvoke { </li></ul><ul><li>public int calculate(int i) { </li></ul><ul><li>return i*i; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>ReflectDemo demo = new ReflectDemo(); </li></ul><ul><li>Object obj = demo.myInvoke(&quot;SomeToBeInvoke&quot;, </li></ul><ul><li> &quot;calculate&quot;, </li></ul><ul><li>new Object[]{new Integer(6)}); </li></ul><ul><li>System.out.println(obj); </li></ul>
  11. 11. Class 类 <ul><li>java.lang.Class 代表一个类,可以通过三种方式得到 Class 的实例: </li></ul><ul><li>Object.getClass() </li></ul><ul><li>Class.forName() </li></ul><ul><li>直接用类名点 class ,如: A.class </li></ul><ul><li>Class 的实例代表的是类,不代表类的实例。即 Class c = A.class , c 是类而不是实例。如果创建实例,可以调用 newInstance() 方法。 </li></ul>
  12. 12. Class 类 <ul><li>可以通过 Class 加载类并了解类的内部结构: </li></ul><ul><li>获取构造函数: Constructor getConstructor(Class[] parameterTypes) Constructor[] getConstructors() </li></ul><ul><li>获取方法: Method getMethod(String name, Class[] parameterTypes) Method[] getMethods() </li></ul><ul><li>获取属性: Field getField(String name) Field[] getFields() </li></ul><ul><li>检查特性: Class[] getInterfaces() 、 Package getPackage() 、 boolean isArray() 、 boolean isInterface() </li></ul>
  13. 13. Field 类 <ul><li>java.lang.reflect.Field 代表属性,是 java.lang.reflect.AccessibleObject 的子类,故可以调用其 setAccessible 方法访问 private 类型的属性。 </li></ul><ul><li>Field 中声明了多个 getter 和 setter 方法,可以设置属性的值。 </li></ul>
  14. 14. Method 类 <ul><li>java.lang.reflect.Method 代表类中的方法,它也是 java.lang.reflect.AccessibleObject 的子类,可以通过 setAccessible 访问 private 类型方法。 </li></ul><ul><li>可以通过调用 Object invoke(Object obj, Object[] args) 方法,间接调用对象方法。 </li></ul>
  15. 15. Contructor 类 <ul><li>java.lang.reflect.Constructor 代表构造函数,是 java.lang.reflect.AccessibleObject 的子类,可以通过 setAccessible 访问 private 类型方法。 </li></ul><ul><li>可以通过 Object newInstance(Object[] initargs 方法调用构造函数,创建新实例。 </li></ul>
  16. 16. JavaBean 自省机制 <ul><li>JavaBean 的属性一般都具有 getter 方法和 setter 方法,通过这些方法可以更改或读取 JavaBean 属性。 </li></ul><ul><li>JavaBean 具有的自省机制可以在不知道 JavaBean 都有哪些属性的情况下,设置它们的值。 </li></ul>
  17. 17. Introspector <ul><li>自省机制是使用 Introspector 实现的。 </li></ul><ul><li>Introspector 的方法大部分都是静态的,可以直接调用,如 getBeanInfo(Class beanClass) 可以得到一个 JavaBean 的 BeanInfo 实例。 </li></ul><ul><li>BeanInfo 实例包含了一个 JavaBean 类属性和方法的信息。如: </li></ul><ul><li>BeanDescriptor getBeanDescriptor() </li></ul><ul><li>MethodDescriptor [] getMethodDescriptors() </li></ul><ul><li>PropertyDescriptor [] getPropertyDescriptors() </li></ul>
  18. 18. PropertyDescriptor <ul><li>PropertyDescriptor 代表了属性,可以通过它得到属性的 getter 方法和 setter 方法。即 : </li></ul><ul><li>Method getReadMethod() </li></ul><ul><li>Method getWriteMethod() </li></ul><ul><li>通常在不知道 JavaBean 属性时,如果设置 JavaBean 属性就采用 PropertyDescriptor 。 PropertyDescriptor(String propertyName, Class beanClass) </li></ul>
  19. 19. <ul><li>所谓代理模式即是由代理对象接管对象访问,用户在使用时感觉是在原始对象操作,但实际是通过代理对象访问的原始对象。 </li></ul><ul><li>Java 为代理模式提供了内置的支持,这是通过 java.lang.reflect.Proxy 以及 java.lang.reflect. InvocationHandler 实现的。 </li></ul>代理( Proxy )模式
  20. 20. 代理( Proxy )模式 <ul><li>所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动。 </li></ul><ul><li>在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。 </li></ul>
  21. 21. 代理模式的结构
  22. 22. 代理模式的角色 <ul><li>抽象主题角色:声明了真实主题和代理主题的共同接口,这样在任何可用真实主题的地方都可以使用代理主题。 </li></ul><ul><li>代理主题角色:代理主题角色内部含有对真实主题的引用,从而可以在任何时候操作真实主题对象,代理角色通常在将客户端调用传递给真实的主题之前或之后,都要执行某个操作。 </li></ul><ul><li>真实主题角色:定义了代理角色所代表的真实对象。 </li></ul>
  23. 23. 代理模式的时序
  24. 24. 装配 Bean
  25. 25. IoC 与 Bean 装配 <ul><li>在 Spring 中,对象间的协作是通过 IoC 机制完成的。 </li></ul><ul><li>反向控制也叫依赖注入( Dependency Injection , DI ),简单来说就是将 JavaBean 需要的对象通过配置文件加载进来。 </li></ul><ul><li>Spring 提供了两种装配 Bean 的容器,一是 BeanFactoy ,另一个是 ApplicationContext 。 </li></ul><ul><li>两者做为容器,所有的 Bean 都应该通过容器装配,而容器也知道自己都装配了哪些 Bean 。 </li></ul>
  26. 26. Bean 容器 <ul><li>ApplicationContext 与 BeanFactory 都是接口, ApplicationContext 是由 BeanFactory 接口扩展而来,它增强了 BeanFactory 的功能。 </li></ul><ul><li>Bean 容器能够加载的对象并不一定是严格遵循 JavaBeans 规范的 Java 类,任何可实例化的类都可以通过 Spring Bean 容器加载进来。通常称这些类为 POJO 。 </li></ul><ul><li>要记住, BeanFactory 不仅仅只具备实例化 Bean 的功能,它还知道所有的 Bean ,可以配置和管理它们。 </li></ul>
  27. 27. BeanFactory <ul><li>以下是 BeanFactory 声明的方法,都是与 Bean 装配相关的: </li></ul><ul><li>boolean containsBean(String name) </li></ul><ul><li>String[] getAliases(String name) </li></ul><ul><li>Object getBean(String name) </li></ul><ul><li>Object getBean(String name, Class requiredType) </li></ul><ul><li>Class getType(String name) </li></ul><ul><li>boolean isSingleton(String name) </li></ul>
  28. 28. BeanFactory <ul><li>Spring 给出一些 BeanFactory 的实现类,其中最为常用的是 XmlBeanFactory 。 </li></ul><ul><li>1 、通过文件系统 </li></ul><ul><li>Resource res = new FileSystemResource(&quot;beans.xml&quot;); </li></ul><ul><li>XmlBeanFactory factory = new XmlBeanFactory(res); </li></ul><ul><li>2 、通过类路径 </li></ul><ul><li>ClassPathResource res = new ClassPathResource(&quot;beans.xml&quot;); </li></ul><ul><li>XmlBeanFactory factory = new XmlBeanFactory(res); </li></ul><ul><li>3 、通过 ApplicationContext 加载 </li></ul><ul><li>ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext( </li></ul><ul><li>new String[] {&quot;applicationContext.xml&quot;, &quot;applicationContext-part2.xml&quot;}); </li></ul><ul><li>BeanFactory factory = (BeanFactory) appContext; </li></ul>
  29. 29. Resource <ul><li>创建 XmlBeanFactory 时需要以 Resource 作为构造函数的参数。 </li></ul><ul><li>Resource 接口位于 org.springframework.core.io 包内,通过 XmlBeanFactory 创建 BeanFactory 时都要使用到这个接口。 </li></ul><ul><li>Resource 代表了所有可以访问的底层资源,如文件系统、类路径、 URL 等等。 </li></ul>
  30. 30. Resource <ul><li>实现了 Resource 接口的类包括: </li></ul><ul><li>AbstractResource, </li></ul><ul><li>ByteArrayResource, -- byte[] </li></ul><ul><li>ClassPathResource, -- String path </li></ul><ul><li>DescriptiveResource, -- String description 不实际指向资源,只包含描述信息 </li></ul><ul><li>FileSystemResource, -- File , or, String path </li></ul><ul><li>InputStreamResource, -- InputStream </li></ul><ul><li>ServletContextResource, -- ServletContext, String </li></ul><ul><li>UrlResource -- URL , or , String path </li></ul>
  31. 31. Resource <ul><li>Resource 中定义了以下方法: </li></ul><ul><li>Resource createRelative(String relativePath) </li></ul><ul><li>boolean exists() </li></ul><ul><li>String getDescription() </li></ul><ul><li>File getFile() </li></ul><ul><li>String getFilename() </li></ul><ul><li>URL getURL() </li></ul><ul><li>boolean isOpen() </li></ul>
  32. 32. 装配 Bean <ul><li>通常可以通过三种方式装配 Bean </li></ul><ul><li>通过 setter 方法 </li></ul><ul><li>通过构造函数 </li></ul><ul><li>自动装配 </li></ul><ul><li>其中,使用 setter 方法装配 Bean 是最为常用的。 </li></ul>
  33. 33. 装配 Bean <ul><li>无论使用 BeanFactory 还是 Applicationcontext 均可以视之为容器,使用的 Bean 必须向容器注册。 </li></ul><ul><li>注册是通过在配置文件中加入 Bean 声明: </li></ul><ul><li><beans> </li></ul><ul><li><bean id=“first” class=“mybeans.FirstBean”/> </li></ul><ul><li><bean id=“second&quot; class=“mybeans.Second”/> </li></ul><ul><li></beans> </li></ul><ul><li>注册后的 Bean 是被容器识别的,容器可以协调他们之间的关系 </li></ul>
  34. 34. 装配 Bean <ul><li><!ELEMENT bean ( </li></ul><ul><li>description?, </li></ul><ul><li>(constructor-arg | </li></ul><ul><li>property | </li></ul><ul><li>lookup-method | </li></ul><ul><li>replaced-method)* </li></ul><ul><li>)> </li></ul>
  35. 35. 原型或单例 <ul><li>如下代码的执行结果是什么? </li></ul><ul><li>FirstBean bean = (FirstBean)factory.getBean(&quot;my&quot;); </li></ul><ul><li>FirstBean bean1 = (FirstBean)factory.getBean(&quot;my&quot;); </li></ul><ul><li>System.out.println(bean==bean1); </li></ul><ul><li>结果依赖于 bean 元素的 singleton 属性,如果设置 true ,则以单例模式加载 bean ,则永远指向同一个 bean ;反之则每次实例化一个。 </li></ul><ul><li>也即在单例模式下, BeanFactory 维护所有的 bean </li></ul>
  36. 36. 原型或单例 <ul><li>BeanFactory 维护所有单例 bean ,也即维护了对单例 bean 的引用,因此 factory 只知道创建单例 bean 的数目,而无从知晓原型 bean 。 </li></ul><ul><li>原型 bean 创建后即脱离了容器,容器不维护对 bean 的引用,因此也无法再管理 bean 。 </li></ul><ul><li>不是绝对必要,不要使用原型,而应尽可能使用单例。 </li></ul>
  37. 37. 延迟加载 <ul><li>如下代码执行的结果是什么? </li></ul><ul><li>System.out.println(&quot;before loading&quot;); </li></ul><ul><li>FirstBean bean = (FirstBean)factory.getBean(&quot;my&quot;); </li></ul><ul><li>System.out.println(“after loading”); </li></ul><ul><li>在 bean 的构造函数中,包含: </li></ul><ul><li>System.out.println(“bean init”); </li></ul><ul><li>结果依赖于 bean 的 lazy-init 属性,如果设置为 true ,则在第一次加载该 bean 时初始化;否则在初始化容器时就加载所有 bean 。 </li></ul><ul><li>延迟加载仅在 bean 单例模式下起作用 。 </li></ul>
  38. 38. 初始化与清理 <ul><li>在许多情况下,需要在对象加载后立即初始化资源,而在删除对象前先清理资源 </li></ul><ul><li>在 spring 中,提供了两种方式实现初始化和清理工作。 </li></ul><ul><li>通过设置 bean 的 init-method 和 destroy-method 指定初始与清理方法 </li></ul><ul><li>通过实现 InitializingBean 及 DisposableBean 接口,由容器在加载与删除 bean 时自动调用。 </li></ul>
  39. 39. 初始化与清理 <ul><li><bean id=&quot;first&quot; class=&quot;mybeans.FirstBean&quot; init-method=&quot;init&quot; destroy-method=&quot;destroy&quot; > </li></ul><ul><li><property name=&quot;message&quot;> </li></ul><ul><li><value>Hi, Rod Johnson</value> </li></ul><ul><li></property> </li></ul><ul><li></bean> </li></ul><ul><li>可以通过 destroySingletons 方法删除所有单例 bean </li></ul><ul><li>原型 bean 在创建后即脱离 BeanFactory 的维护,所以只能调用初始化方法,而不能做清理工作。 </li></ul>
  40. 40. 初始化与清理 <ul><li>通过 InitializingBean 和 DisposableBean. </li></ul><ul><li>InitializingBean 接口中仅定义了一个方法,即 void afterPropertiesSet () </li></ul><ul><li>DisposableBean 接口也是这样,方法为:  void destroy () </li></ul><ul><li>这两个接口都位于 org.springframework.beans.factory 包中,须向容器注册 id 以及 class 。 </li></ul>
  41. 41. 初始化与清理 <ul><li>初始化与清理的次序 </li></ul><ul><li>无论是哪种初始化方式,都是在 bean 构造完毕,并且 属性已经注入 到对象中后才执行的。 </li></ul><ul><li>初始化时, InitializingBean 定义的初始化方法 先于 init-method 中指定的方法。 </li></ul><ul><li>清理时, DisposableBean 定义的清理方法 先于 destroy-method 指定的方法。 </li></ul>
  42. 42. Setter 装配 <ul><li>在配置文件中, <bean> 元素的 <property> 元素 指明了使用属性的 setter 方法注入依赖。 </li></ul><ul><li><!ELEMENT property ( </li></ul><ul><li>description?, </li></ul><ul><li>(bean | ref | idref | value | null | list | set | map | props)? </li></ul><ul><li>)> </li></ul><ul><li><!ATTLIST property name CDATA #REQUIRED> </li></ul><ul><li><!ATTLIST property ref CDATA #IMPLIED> </li></ul><ul><li><!ATTLIST property value CDATA #IMPLIED> </li></ul><ul><li>Setter 装配要求 bean 中必须与相应的 setter 方法,即使没有这个属性 </li></ul>
  43. 43. Setter 装配- 装配种类 <ul><li>可以通过 setter 方法加载以下类型的属性: </li></ul><ul><li>基本类型 </li></ul><ul><li>Bean 类型 </li></ul><ul><li>内部 bean 类型 </li></ul><ul><li>集合类型 </li></ul><ul><li>设置空值 </li></ul>
  44. 44. Setter 装配-基本类型 <ul><li>装配基本类型: </li></ul><ul><li>包括八种基本类型及它们的包装类,还有 String 类型。 </li></ul><ul><li>不必关心具体类型, spring 可以通过反射机制了解到属性的类型信息 </li></ul><ul><li>可以通过 <property> 的子元素 <value> 来设置基本类型的值,也可以通过其属性 value 来设置,效果完全相同。 </li></ul>
  45. 45. Setter 装配-基本类型 <ul><li><bean id=&quot;first&quot; class=&quot;mybeans.FirstBean&quot; > </li></ul><ul><li><property name=&quot;message&quot;> </li></ul><ul><li><value>Hi, Rod Johnson</value> </li></ul><ul><li></property> </li></ul><ul><li><property name=&quot;age&quot; value=&quot;1&quot; /> </li></ul><ul><li></bean> </li></ul><ul><li>注意不能同时使用 value 子元素和 value 属性 </li></ul>
  46. 46. Setter 装配- bean 类型 <ul><li>装配 bean 类型属性: </li></ul><ul><li>只有通过配置文件向容器注册的 bean 才能通过注入机制设置到其它 bean 的属性上。 </li></ul><ul><li>使用 <ref> 子元素或 ref 属性设置 </li></ul><ul><li>Spring 即是通过这种方式建立起 bean 间的依赖关系,实现强大的 bean 管理功能。 </li></ul>
  47. 47. Setter 装配- bean 类型 <ul><li><bean id=&quot;first&quot; class=&quot;mybeans.FirstBean&quot;> </li></ul><ul><li><property name=&quot;message&quot;> </li></ul><ul><li><value>Hi, Rod Johnson</value> </li></ul><ul><li></property> </li></ul><ul><li><property name=&quot;age&quot; value=&quot;1&quot; /> </li></ul><ul><li><property name=&quot;second&quot; ref=&quot;second&quot;/> </li></ul><ul><li></bean> </li></ul><ul><li><bean id=“second” class=“mybeans.SecondBean” > </li></ul><ul><li><property name=&quot;first&quot;> </li></ul><ul><li><ref bean=&quot;first&quot;/> </li></ul><ul><li></property> </li></ul><ul><li></bean> </li></ul>
  48. 48. Setter 装配- bean 类型 <ul><li>内部 Bean </li></ul><ul><li><bean id=&quot;outer&quot; class=&quot;...&quot;> </li></ul><ul><li><property name=&quot;target&quot;> </li></ul><ul><li><bean class=&quot;com.mycompany.PersonImpl&quot;> </li></ul><ul><li><property name=&quot;name&quot;> </li></ul><ul><li><value>Tony</value> </li></ul><ul><li></property> </li></ul><ul><li></bean> </li></ul><ul><li></property> </li></ul><ul><li></bean> </li></ul>
  49. 49. Setter 装配-集合类型 <ul><li>Spring 支持以下四种集合的装配: </li></ul><ul><li><list> -- java.util.List </li></ul><ul><li><set> -- java.util.Set </li></ul><ul><li><map> -- java.util.Map </li></ul><ul><li><props> -- java.util.Properties </li></ul>
  50. 50. Setter 装配- list 集合 <ul><li><property name=&quot;someList&quot;> </li></ul><ul><li><list> </li></ul><ul><li><value>someValue</value> </li></ul><ul><li><ref bean=&quot;myDataSource&quot;/> </li></ul><ul><li><list> </li></ul><ul><li><value>anyValue</value> </li></ul><ul><li></list> </li></ul><ul><li></list> </li></ul><ul><li></property> </li></ul>
  51. 51. Setter 装配- set 集合 <ul><li><property name=&quot;someSet&quot;> </li></ul><ul><li><set> </li></ul><ul><li><value>just some string</value> </li></ul><ul><li><ref bean=&quot;myDataSource&quot;/> </li></ul><ul><li></set> </li></ul><ul><li></property> </li></ul>
  52. 52. Setter 装配- map 集合 <ul><li><property name=&quot;someMap&quot;> </li></ul><ul><li><map> </li></ul><ul><li><entry> </li></ul><ul><li><key><value>yup an entry</value></key> </li></ul><ul><li><value>just some string</value> </li></ul><ul><li></entry> </li></ul><ul><li><entry> </li></ul><ul><li><key><value>yup a ref</value></key> </li></ul><ul><li><ref bean=&quot;myDataSource&quot;/> </li></ul><ul><li></entry> </li></ul><ul><li></map> </li></ul><ul><li></property> </li></ul>
  53. 53. Setter 装配- props 集合 <ul><li><property name=&quot;people&quot;> </li></ul><ul><li><props> </li></ul><ul><li><prop key=&quot;HarryPotter&quot;> </li></ul><ul><li>The magic property </li></ul><ul><li></prop> </li></ul><ul><li><prop key=&quot;JerrySeinfeld&quot;> </li></ul><ul><li>The funny property </li></ul><ul><li></prop> </li></ul><ul><li></props> </li></ul><ul><li></property> </li></ul>
  54. 54. Setter 装配-设置 null <ul><li>如果希望将属性设置为空,使用以下方法不能达到目的: </li></ul><ul><li><property name=&quot;age&quot; > </li></ul><ul><li><value></value> </li></ul><ul><li></property> </li></ul><ul><li>应该按如下方式注入: </li></ul><ul><li><property name=&quot;age&quot; > </li></ul><ul><li><null/> </li></ul><ul><li></property> </li></ul><ul><li>属性必须为 Object </li></ul>
  55. 55. 构造装配 <ul><li>构造装配通过构造函数装配 bean 属性,一般在以下情况下使用: </li></ul><ul><li>属性没有 setter 方法,是只读属性 </li></ul><ul><li>属性只需要设置一次,以后就不会再更改 </li></ul><ul><li>一般使用构造装配只装配少量属性 </li></ul><ul><li>构造装配下,构造函数中应该包含有需要装配的属性 </li></ul>
  56. 56. 构造装配 <ul><li><bean id=&quot;first&quot; class=&quot;mybeans.FirstBean&quot;> </li></ul><ul><li><constructor-arg> </li></ul><ul><li><value>http://www.sohu.com</value> </li></ul><ul><li></constructor-arg> </li></ul><ul><li><constructor-arg> </li></ul><ul><li><value>http://localhost:8080</value> </li></ul><ul><li></constructor-arg> </li></ul><ul><li><property name=&quot;age&quot; value=&quot;1&quot; /> </li></ul><ul><li></bean> </li></ul><ul><li>多个参数时使用多个 constructor-arg 指定,出现 次序决定了参数次序,或者使用 index 属性指定 </li></ul>
  57. 57. 自动装配 <ul><li>可以通过 spring 框架自动为 bean 装配属性。 </li></ul><ul><li>自动装配只能装配 bean 类型,即取代 ref 元素。 </li></ul><ul><li>使用自动装配只需在 bean 元素中加入属性 autowire ,自动装配可被手动装配覆盖。 </li></ul><ul><li>也可以选择在 beans 中加入 default-autowire 属性,为所有 bean 设置默认自动装配。 </li></ul>
  58. 58. 自动装配类型 <ul><li>“ no“ -不使用自动装配, spring 推荐。 </li></ul><ul><li>“ byName” -依据名称或 ID 装配 bean ,如果没有找到,则不装配 </li></ul><ul><li>“ byType” -依据类型自动装配,如果存在两个以上同种类型,则抛出异常。 </li></ul><ul><li>“ constructor” -依据当前 bean 构造函数装配,查找与构造函数参数 同类型 bean </li></ul><ul><li>“ autodetect” -自动检测,先通过 constructor ,再使用 byType </li></ul>
  59. 59. 装配 Bean <ul><li>通过 BeanFactory 获取 Bean 与直接 new 一个 Bean 是完全不同的。 </li></ul><ul><li>通过 BeanFactory 获取的 bean 能将所有依赖注入到 bean 中,属性的值会依设置而定。 </li></ul><ul><li>New 出来的 bean 属性值必须主动设置。 </li></ul><ul><li>在需要使用 spring 框架情况下,所有 bean 都应该由容器来管理。 </li></ul>
  60. 60. ApplicationContext <ul><li>ApplicationContext 与 BeanFactory 的作用相类似,都起到装配、管理 Bean 的作用。 </li></ul><ul><li>不同的是, ApplicationContext 在此基础上增强了 BeanFactory 的功能,这包括国际化、加载资源、发布事件等等。 </li></ul><ul><li>实现了 ApplicationContext 接口的类包括: </li></ul><ul><li>1 、 ClassPathXmlApplicationContext </li></ul><ul><li>2 、 FileSystemXmlApplicationContext </li></ul><ul><li>3 、 GenericApplicationContext </li></ul><ul><li>4 、 GenericWebApplicationContext </li></ul><ul><li>5 、 StaticApplicationContext </li></ul><ul><li>6 、 StaticWebApplicationContext </li></ul><ul><li>7 、 XmlWebApplicationContext </li></ul><ul><li>它们的使用方法与 BeanFactory 基本相同 </li></ul>
  61. 61. ApplicationContext <ul><li>ApplicationContext 接口由以下接口扩展而来: </li></ul><ul><li>ListableBeanFactory -可以列出所有 bean </li></ul><ul><li>HierarchicalBeanFactory -可以找到父工厂 </li></ul><ul><li>MessageSource -处理国际化 </li></ul><ul><li>ApplicationEventPublisher -处理事件 </li></ul><ul><li>ResourcePatternResolver -资源解析 </li></ul>
  62. 62. 面向切面- AOP
  63. 63. AOP 简介 <ul><li>AOP 最初由 Gregor Kiczales 在施乐的 Palo Alto 研究中心领导的一个研究小组于 1997 年提出。 </li></ul><ul><li>目前,宣称能够支持 AOP 的项目已达近百种, Java 语言的实现也有 20 多种,其中最为完善的是 AspectJ 。这是由 Gregor Kiczales 领导的小组完成的。 </li></ul>
  64. 64. AOP 简介 <ul><li>AOP 是 OOP 的延续,是 Aspect Oriented Programming 的缩写,意思是面向方面编程。 </li></ul><ul><li>它将分布在各个类中具有相同功能的代码片段整合到一起,由单独的功能模块完成,不仅减少了代码的重复量,降低了耦合,也提高了代码的可维护性。 </li></ul><ul><li>不要认为 AOP 会取代 OOP ,它只是 OOP 的补充。但就像当年的 OOP 一样,它很可能引发一场软件产业的革命。 </li></ul>
  65. 65. AOP 简介
  66. 66. AOP 术语 <ul><li>切面( Aspect ):从对象中抽取出来的交叉功能模块 </li></ul><ul><li>通知( Adivice ):切面的具体实现 </li></ul><ul><li>连接点( Joinpoint ):可以插入方法的地方 </li></ul><ul><li>切入点( Pointcut ):连接点的集合 </li></ul><ul><li>引入( Introduction ):为已经存在的类添加新方法和属性 </li></ul>
  67. 67. AOP 术语 <ul><li>目标对象( Target Object ): </li></ul><ul><li>被通知的对象 </li></ul><ul><li>代理( AOP Proxy ): </li></ul><ul><li>由 AOP 框架创建的目标对象的代理对象 </li></ul><ul><li>织入( Weaving ): </li></ul><ul><li>将通知与目标对象结合在一起,生成新的代码片段的过程 </li></ul>
  68. 68. AOP 实现技术 <ul><li>目前,人们使用传统语言对核心业务进行编程,对横切面的功能模块则使用面向切面的编程语言。 </li></ul><ul><li>面向切面的编程语言可以是已有编程语言的扩展,如 AspectJ , AspectC++ , AspectC , AspectC# , Apostle 等,或是一种新的语言 </li></ul><ul><li>Java 语言可以使用反射( Reflection ),基于动态代理( Dynamic Proxy )或其它机制的拦截框架,基于元数据( Metadata )的操作,以及类载入时对字节码的操作等来实现 AOP 。 </li></ul>
  69. 69. AOP 实现技术 <ul><li>Spring 使用两种机制实现 AOP 技术,一是使用 java 的动态代理,即 java.lang.reflect.Proxy 类创建代理。 </li></ul><ul><li>二是使用 CGLIB 库自动生成目标对象的子类,同时织入通知。 </li></ul><ul><li>动态代理要求目标对象必须要实现接口(只有这样才能创建代理),而 CGLIB 则没有这种限制。 </li></ul>
  70. 70. AOP 实现技术 <ul><li>由于目前 AOP 还没有完全的统一标准,因此实现出来的 AOP 框架也是多种多样的,为此人们成立了一个 AOP 联盟,用于统一这种混乱局面 </li></ul><ul><li>Aop Alliance 是由多个 AOP 项目组成的组织,定义一套 AOP 标准的 Java 接口,以方便各种 AOP 框架可以互通。 </li></ul><ul><li>Spring 也是以这套接口为基础的。 </li></ul>
  71. 71. AOP 快速入门 <ul><li>背景:课程在开课前应该向任课老师发出上课通知。 </li></ul><ul><li>创建步骤: </li></ul><ul><li>创建目标对象,目标对象必须是实现了某种接口的。 </li></ul><ul><li>创建通知,通知定义了一个切面的具体逻辑。 </li></ul><ul><li>向上下文注册。 </li></ul>
  72. 72. AOP 快速入门-创建目标 <ul><li>public class J2eeCourse implements Course { </li></ul><ul><li>String name; </li></ul><ul><li>public J2eeCourse(String name) { </li></ul><ul><li>this.name = name; </li></ul><ul><li>} </li></ul><ul><li>public void process(Teacher teacher) { </li></ul><ul><li>System.out.println(name + &quot; is in process, and the teacher is “ </li></ul><ul><li> + teacher.getName()); </li></ul><ul><li>teacher.giveClass(); </li></ul><ul><li>} </li></ul><ul><li>public String getName() { </li></ul><ul><li>return name; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  73. 73. AOP 快速入门-创建目标 <ul><li>使用 Java 动态代理机制实现的 AOP 必须要将目标对象中的方法声明在一个接口中: </li></ul><ul><li>public interface Course { </li></ul><ul><li>public void process(Teacher teacher); </li></ul><ul><li>public String getName(); </li></ul><ul><li>} </li></ul>
  74. 74. AOP 快速入门-创建通知 <ul><li>此处创建的是前置通知: </li></ul><ul><li>public class CourseAdvice implements MethodBeforeAdvice { </li></ul><ul><li>public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable { </li></ul><ul><li>Course course = (Course)arg2; </li></ul><ul><li>Teacher teacher = (Teacher) arg1[0]; </li></ul><ul><li>System.out.println(&quot;hi, teacher &quot; + teacher.getName() + </li></ul><ul><li>&quot;, there is a &quot; + course.getName()+ </li></ul><ul><li>&quot;, do you have time to listener this class?&quot;); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  75. 75. AOP 快速入门-注册 <ul><li><beans> </li></ul><ul><li><bean id=&quot;courseTarget&quot; class=&quot;aop.J2eeCourse&quot;> </li></ul><ul><li><constructor-arg value =” j2ee“/> </li></ul><ul><li></bean> </li></ul><ul><li><bean id=&quot;rod&quot; class=&quot;aop.TeacherRod&quot;> </li></ul><ul><li><constructor-arg value=“Rod Johnson”/> </li></ul><ul><li></bean> </li></ul><ul><li><bean id=&quot;advice&quot; class=&quot;aop.CourseAdvice&quot;/> </li></ul><ul><li><bean id=&quot;course&quot; class=&quot;org.springframework.aop.framework.ProxyFactoryBean&quot;> </li></ul><ul><li><property name=&quot;proxyInterfaces&quot; value=“aop.Course”/> </li></ul><ul><li><property name=&quot;interceptorNames&quot;> </li></ul><ul><li><list><value>advice</value></list> </li></ul><ul><li></property> </li></ul><ul><li><property name=&quot;target” ref&quot;courseTarget&quot; /> </li></ul><ul><li></bean> </li></ul><ul><li></beans> </li></ul>
  76. 76. 通知的类型 <ul><li>通知是切面的具体实现,在 Spring 中通知被分为以下几种类型: </li></ul>
  77. 77. 通知的类型 <ul><li>除 MethodInterceptor (环绕通知)是由 aop alliance 定义以外,其余接口均位于 org.springframework.aop 中 </li></ul><ul><li>MethodInterceptor 位于 org.aopalliance.intercept 包中,因此如果需要使用这个接口,必须导入 aopalliance 的 jar 文件。 </li></ul>
  78. 78. 切入点 <ul><li>切入点用于定义通知加入到目标对象中的位置,没有切入点通知将被应用于所有方法上。 </li></ul><ul><li>Spring 以 org.springframework.aop.PointCut 来定义切入点。 </li></ul><ul><li>切入点分为两类,即静态切入点和动态切入点 </li></ul><ul><li>静态切入点下,通知总被执行,动态切入点下,通知依据运行时的参数决定通知是否需要执行。 </li></ul>
  79. 79. 切入点
  80. 80. Advisor 概述 <ul><li>由于 ProxyFactoryBean 只接受 Advice 和 Advisor 类型的 Interceptor (参照 API ),所以不能直接应用 PointCut 到 ProxyFactoryBean 上 </li></ul><ul><li>Advisor 是 Spring AOP 中特有的概念,它持有通知,并决定通知是否应用到当前实例上。 </li></ul><ul><li>由于切入点是决定通知是否应用的重要依据,故 PointcutAdvisor 中持有通知和切入点,并依据切入点决定是否应用通知。 </li></ul>
  81. 81. Advisor 概述 <ul><li>public interface Advisor { </li></ul><ul><li>Advice getAdvice ();       </li></ul><ul><li>boolean isPerInstance (); </li></ul><ul><li>} </li></ul><ul><li>public interface PointcutAdvisor extends Advisor { </li></ul><ul><li>Pointcut getPointcut () </li></ul><ul><li>} </li></ul><ul><li>由于 PointcutAdvisor 继承自 Advisor ,因此可以当成 </li></ul><ul><li>Interceptor 使用。 </li></ul>
  82. 82. 内置切入点 <ul><li>静态切入点 </li></ul><ul><li>StaticMethodMatcherPointcut (抽象) </li></ul><ul><li>NameMatchMethodPointcut -名字匹配 </li></ul><ul><li>JdkRegexpMethodPointcut - JDK 与此同时表达式 </li></ul><ul><li>Perl5RegexpMethodPointcut - Perl 5 正则表达式 </li></ul><ul><li>动态切入点 </li></ul><ul><li>DynamicMethodMatcherPointcut (抽象) </li></ul><ul><li>ControlFlowPointcut </li></ul>
  83. 83. 名称匹配 <ul><li>在 NameMatchMethodPointcut 中,除了定义了一般 PointCut 的方法外,还定义了以下一些方法: </li></ul><ul><li>void setMappedName (String mappedName) </li></ul><ul><li>void setMappedNames (String[] mappedNames) </li></ul><ul><li>只有与指定名称匹配的方法才会被应用通知,可以通过 IOC 机制设置匹配名称。 </li></ul>
  84. 84. 相应 Advisor <ul><li>与 NameMatchMethodPointcut 对应的 Advisor 是 NameMatchMethodPointcutAdvisor 。 </li></ul><ul><li>在 NameMatchMethodPointcutAdvisor 中没有定义直接设置 PointCut 的方法,但由于是由 NameMatchMethodPointcutAdvisor 继承而来,故可以通过设置 mappedName 生成。 </li></ul>
  85. 85. 相应 Advisor <ul><li><bean id=&quot;advice&quot; class=&quot;aop.CourseAdvice&quot;/> </li></ul><ul><li><bean id=&quot;advisor&quot; class=&quot;org.springframework.aop.support.NameMatchMethodPointcutAdvisor&quot;> </li></ul><ul><li><property name=“mappedName” value=”process“ /> </li></ul><ul><li><property name=“advice” ref=&quot;advice&quot; /> </li></ul><ul><li></bean> </li></ul><ul><li><bean id=&quot;course&quot; class=&quot;org.springframework.aop.framework.ProxyFactoryBean&quot;> </li></ul><ul><li><property name=&quot;proxyInterfaces“ value=“aop.Course”/> </li></ul><ul><li><property name=&quot;interceptorNames&quot;> </li></ul><ul><li><list><value> advisor </value></list> </li></ul><ul><li></property> </li></ul><ul><li><property name=&quot;target“ ref=&quot;courseTarget&quot; /> </li></ul><ul><li></bean> </li></ul><ul><li>在定义 mappedName 时,可以使用通配符 * </li></ul>
  86. 86. 正则表达式匹配 <ul><li>通过直接指定方法的办法简单有效,但如果在大型系统中,方法较多的情况下,一个个指出通知的方法名则会显得臃肿。 </li></ul><ul><li>JdkRegexpMethodPointcut 使用正则表达式的形式指定匹配的方法,是更为通用的一种方法。 </li></ul><ul><li>除了 JdkRegexpMethodPointcut 还有 Perl5RegexpMethodPointcut ,它们的区别仅在于前者使用 JDK 语法,而后者使用 perl 5 </li></ul>
  87. 87. 正则表达式匹配 <ul><li>无论是 JDK 版本的,还是 Perl5 版本的,它们都是由 AbstractRegexpMethodPointcut 继承而来,这个方法中定义以下两个方法: </li></ul><ul><li>void setPattern(String pattern) </li></ul><ul><li>void setPatterns(String[] patterns) </li></ul><ul><li>可以使用 IOC 机制定义正则表达式。 </li></ul><ul><li>特别强调,正则表达式下,匹配的是类名和方法名 </li></ul>
  88. 88. 相应 Advisor <ul><li>与这两个 PointCut 对应的 Advisor 都是 RegexpMethodPointcutAdvisor </li></ul><ul><li>Pointcut getPointcut() </li></ul><ul><li>void setPattern(String pattern) </li></ul><ul><li>void setPatterns(String[] patterns) </li></ul><ul><li>void setPerl5(boolean perl5) </li></ul><ul><li>设置 setPerl5 为 true 时,强制使用 Perl 5 语法形式的正则表达式,这时必须引入 Jakarta ORO 包 </li></ul>
  89. 89. 相应 Advisor <ul><li><bean id=&quot;advisor&quot; class=&quot;org.springframework.aop.support.RegexpMethodPointcutAdvisor&quot;> </li></ul><ul><li><property name=&quot;pattern&quot;> </li></ul><ul><li><value .*process.* </value> </li></ul><ul><li></property> </li></ul><ul><li><property name=&quot;advice&quot;> </li></ul><ul><li><ref bean=&quot;advice&quot;/> </li></ul><ul><li></property> </li></ul><ul><li></bean> </li></ul><ul><li>标红处写成 ^aop.Course.process$ 只针对一个类的一个特定方法 </li></ul>
  90. 90. 数据层应用
  91. 91. DAO 支持 <ul><li>Spring 提供了对数据层的广泛支持,这包括: </li></ul><ul><li>传统 JDBC </li></ul><ul><li>Hibernate </li></ul><ul><li>JDO </li></ul><ul><li>Oracle TopLink </li></ul><ul><li>Apache OJB </li></ul><ul><li>iBATIS SQL Map </li></ul>
  92. 92. JDBC 方式 <ul><li>Spring JDBC 方式采用 模板 与 回调 相结合的模式,核心类是 JdbcTemplate 。 </li></ul>
  93. 93. JDBC 方式 <ul><li>使用 JDBC 方法处理 DAO ,必须要知道数据源 DataSource 。 </li></ul><ul><li>Spring DAO 层中,获取数据源方法有三种: </li></ul><ul><li>通过 JNDI </li></ul><ul><li>使用第三方的连接池 </li></ul><ul><li>使用 DriverManagerDataSource </li></ul>
  94. 94. DriverManagerDataSource <ul><li>为了方便测试, Spring 提供了简便易用的 DataSource 实现,即 DriverManagerDataSource ,可直接创建 : </li></ul><ul><li>DriverManagerDataSource dataSource = new DriverManagerDataSource(); </li></ul><ul><li>dataSource.setDriverClassName( “……&quot;); </li></ul><ul><li>dataSource.setUrl( “……&quot;); </li></ul><ul><li>dataSource.setUsername( “……&quot;); </li></ul><ul><li>dataSource.setPassword( “……&quot;); </li></ul>
  95. 95. DriverManagerDataSource <ul><li>也可以通过 IOC 机制注入: </li></ul><ul><li><bean id=&quot;dataSource&quot; class=&quot;org.springframework.jdbc.datasource.DriverManagerDataSource&quot;> </li></ul><ul><li><property name=&quot;driverClassName&quot; value=&quot;com.mysql.jdbc.Driver&quot;/> </li></ul><ul><li><property name=&quot;url&quot; value=&quot;jdbc:mysql://localhost:3306/hibernate&quot;/> </li></ul><ul><li><property name=&quot;username&quot; value=&quot;root&quot;/> </li></ul><ul><li><property name=&quot;password&quot; value=&quot;root&quot;/> </li></ul><ul><li></bean> </li></ul>
  96. 96. 第三方连接池 <ul><li>最常使用的第三方连接池是 Apache 的 jakarta common dbcp 项目。这里主要使用的是 org.apache.commons.dbcp.BasicDataSource </li></ul><ul><li>由于 BasicDataSource 的属性均通过 setter 方法暴露出来,因此可以使用 IOC 机制注入。 </li></ul><ul><li>例如: </li></ul>
  97. 97. 第三方连接池 <ul><li><bean id=&quot;newDs&quot; class=&quot;org.apache.commons.dbcp.BasicDataSource&quot;> </li></ul><ul><li><property name=&quot;driverClassName&quot; value=&quot;com.mysql.jdbc.Driver&quot; /> </li></ul><ul><li><property name=&quot;url&quot; value=&quot;jdbc:mysql://localhost:3306/hibernate&quot; /> </li></ul><ul><li><property name=&quot;username&quot; value=&quot;root&quot; /> </li></ul><ul><li><property name=&quot;password&quot; value=&quot;root&quot; /> </li></ul><ul><li></bean> </li></ul>
  98. 98. JNDI 方式 <ul><li><bean id=&quot;dataSource&quot; class=&quot;org.springframework.jndi.JndiObjectFactoryBean&quot;> </li></ul><ul><li><property name=&quot;jndiName&quot; value=&quot;java:comp/env/jdbc/DataSource&quot;/> </li></ul><ul><li></bean> </li></ul><ul><li><bean id=&quot;jt&quot; class=&quot;org.springframework.jdbc.core.JdbcTemplate&quot;> </li></ul><ul><li><property name=&quot;dataSource&quot; ref=&quot;dataSource&quot;/> </li></ul><ul><li></bean> </li></ul><ul><li>注意, JdbcTemplate 中的 dataSource 是 DataSource 类型,但设置的却是 JndiObjectFactoryBean 。 </li></ul>
  99. 99. JdbcTemplate <ul><li>总的来说, Spring 在支持 JDBC 访问数据库时采用了模板与回调相结合的方式。其中: </li></ul><ul><li>JdbcTemplate 是模板; </li></ul><ul><li>StatementCallback 是执行 Statement 语句的回调; </li></ul><ul><li>PreparedStatementCallback 、 PreparedStatementCreator 、 PreparedStatementSetter 是 PreparedStatement 语句的回调 </li></ul><ul><li>CallableStatementCallback 等是 CallableStatement 语句的回调。 </li></ul>
  100. 100. JdbcTemplate 查询 <ul><li>依据模板回调原则, Spring 定义了以下查询方法: </li></ul><ul><li>Object query(PreparedStatementCreator psc, ResultSetExtractor rse) </li></ul><ul><li>List query(PreparedStatementCreator psc, RowCallbackHandler rch) </li></ul><ul><li>List query(PreparedStatementCreator psc, RowMapper rowMapper) </li></ul><ul><li>以上几个方法中,第一个参数用于生成语句,第二个参数则用于处理结果,它们都用于在运行时回调 </li></ul>
  101. 101. JdbcTemplate 查询 <ul><li>Spring 提供了一些简便的查询方法: </li></ul><ul><li>1. temp. queryForList (&quot;select * from building&quot;); </li></ul><ul><li>返回 List ,内部元素为 Map ,键对象为列名,值对象为列值。 </li></ul><ul><li>2. temp. queryForMap (&quot;select * from building where id=3&quot;); </li></ul><ul><li>返回 Map ,键对象为列名,值对象为列值,所以要求必须返回单一行。 </li></ul><ul><li>3. temp. queryForObject (&quot;select building_name from building where id=1&quot;, String.class) </li></ul><ul><li>返回对象,依据指定的类型决定返回对象的类型,仅针对单行单列 </li></ul><ul><li>4. 此外还有 queryForInt 及 queryForLong 等等。 </li></ul>
  102. 102. JdbcTemplate 更新 <ul><li>依据模板回调原则, Spring 定义了以下更新方法: </li></ul><ul><li>int update(PreparedStatementCreator psc) </li></ul><ul><li>int update(PreparedStatementCreator psc, KeyHolder generatedKeyHolder) </li></ul><ul><li>int update(PreparedStatementCreator psc, PreparedStatementSetter pss) </li></ul><ul><li>以上参数也均为方法提供了运行回调接口。 </li></ul>
  103. 103. JdbcTemplate 更新 <ul><li>为了方便, Spring 同样定义更新使用的方法: </li></ul><ul><li>int update(String sql) </li></ul><ul><li>int update(String sql, Object[] args) </li></ul><ul><li>int update(String sql, Object[] args, int[] argTypes) </li></ul><ul><li>int update(String sql, PreparedStatementSetter pss) </li></ul><ul><li>用法参照 API </li></ul>
  104. 104. 映射对象 <ul><li>Spring 同 Hibernate 类似,也可以将查询结果映射成对象,但这需要用户自定义。 </li></ul><ul><li>这是通过 SqlQuery 和 SqlUpdate 类实现的,前者用于查询,后者用于更新。 SqlQuery 是抽象类,一般使用其子类 MappingSqlQuery 类派生子类。 </li></ul>
  105. 105. 映射对象
  106. 106. 映射对象
  107. 107. 整合 Hibernate <ul><li>Hibernate 的核心是 SessionFactory ,它就像 JDBC 中的 DataSource 一样。 </li></ul><ul><li>Spring 提供了以 IOC 机制导入 SessionFactory 的可能,这是通过 LocalSessionFactoryBean 实现的。 </li></ul><ul><li>由于 Hibernate 版本更新向前不兼容,因此 Spring 也提供了两套接口对于不同的 Hibernate 版本。 </li></ul><ul><li>org.springframework.orm.hibernate 支持 Hibernate 2.1 ,而 org.springframework.orm.hibernate3 则支持 hibernate3 </li></ul>
  108. 108. 整合 Hibernate
  109. 109. 整合 Hibernate <ul><li>在应用上, Spring 也提供了模板与回调模式来实现 Hibernate 对数据库的操作。 </li></ul><ul><li>HibernateTemplate 是模板,而 HibernateCallback 则是回调接口。 </li></ul><ul><li>HibernateTemplate 提供的 execute 方法,需要以 HibernateCallback 为参数,执行时则在合适的时候回调对象。 </li></ul>
  110. 110. 整合 Hibernate <ul><li>类似于 JdbcTemplate , HiberateTemplate 中也加入了一些简便的方法,可以实现增、删改操作。 </li></ul><ul><li>这些方法基本都可以在 Hibernate 的 Session 接口中找到,或者是 HQL 、 QBC 、 QBE 等等。 </li></ul><ul><li>具体参照 API 文档 </li></ul>
  111. 111. 表述层应用
  112. 112. 集成 Struts <ul><li>Spring 提供了三种集成 Struts 的方法: </li></ul><ul><li>显式集成 </li></ul><ul><li>Action 代理 </li></ul><ul><li>RequestProcessor 代理 </li></ul><ul><li>无论是哪种方法都必须先向 Struts 框架注册一个插件,即: </li></ul>
  113. 113. 显式集成 <ul><li>显示集成 Struts 时要求所有需要使用 Spring 的 Action 都必须通过显式继承 ActionSupport ,位于 org.springframework.web.struts. 包中 </li></ul><ul><li>这个类是 Action 的子类,包含了能够得到 ApplicationContext 的方法,即 </li></ul><ul><li>WebApplicationContext getWebApplicationContext() </li></ul>
  114. 114. Action 代理 <ul><li>Action 代理方式集成 Struts 需要将所有 Action 的地址都映射到 DelegatingActionProxy 上,位于 org.springframework.web.struts 包中。 </li></ul><ul><li>它也是 Action 的子类,代理所有 Action 请求。真正的 Action 请求则以 Spring 注册 bean 的形式注册在容器中,如: </li></ul>
  115. 115. Action 代理 多模块时,路径如何写?
  116. 116. RequestProcessor 代理 <ul><li>RequestProcessor 代理的方式是改写了模块控制器,要求模块控制器必须是 DelegatingRequestProcessor 。 </li></ul><ul><li>这时,所有的 Action 都会被转到 Spring 中查找,所以在 Struts 中配置 action 的 type 属性已经没有意义: </li></ul>
  117. 117. Spring 事务支持 <ul><li>Spring 最为自豪的当属事务管理,因为它在不使用 EJB 服务器的情况下,实现了对事务的宣称式支持。这在以往是仅能由 Session Bean 提供的功能。 </li></ul><ul><li>Spring 对事务的宣称式支持是通过 AOP 机制实现,也即在需要声明事务属性的方法中织入通知。 </li></ul>
  118. 118. Spring 事务支持
  119. 119. Spring 事务支持 注:以上类均实现了 PlatformTransactionManager
  120. 120. Spring 事务支持 <ul><li>由于不同的平台实现事务管理采用的是不同的资源,例如 JDBC 使用直接使用 Connection 管理事务,而 Hibernate 则使用 Session 。 </li></ul><ul><li>在实现上, Spring 要求为 JDBC 事务管理器注入数据源 DataSource ,而为 Hibernate 事务管理器注入 SessionFactory </li></ul><ul><li>所以使用不同的数据层解决方案,相应的事务管理器也完全不同。 </li></ul>
  121. 121. Spring 事务支持
  122. 122. Spring 事务支持 <ul><li>与 EJB 相同, Spring 对事务的支持也分为编程式和宣称式两种(对应 EJB 的 BMT 和 CMT )。 </li></ul><ul><li>在 编程式 事务管理中, Spring 依然采用了模板与回调模式。 </li></ul><ul><li>在 宣称式 事务管理中, Spring 采用了与 EJB 类似的 事务属性 来管理事务。 </li></ul>
  123. 123. 编程式事务管理 <ul><li>Spring 提供了两种方式实现编程式事务管理: </li></ul><ul><li>1 、使用 TransactionTemplate 与 TransactionCallback 结合。 </li></ul><ul><li>2 、直接使用一个 PlatformTransactionManager 的实现。 </li></ul>
  124. 124. 编程式事务管理 <ul><li>使用 TransactionTemplate 时,在其内部仍然要知道具体的事务管理平台,即 PlatformTransactionManager 。这可以通过 IOC 机制注入。如 </li></ul>
  125. 125. 编程式事务管理
  126. 126. 编程式事务管理 <ul><li>事实上, Spring 为模板提供了两个回调类,即 TransactionCallbackWithoutResult 和 TransactionCallback ,前者是后者的实现,并且是一个抽象类。 </li></ul><ul><li>TransactionStatus 作为参数传给回调函数,通过 TransactionStatus 可以设置事务只可回滚。 </li></ul><ul><li>需要注意, 运行时异常可导致自动回滚 。其余则必须设置成只可回滚。 </li></ul>
  127. 127. 编程式事务管理 <ul><li>也可直接使用 PlatformTransactionManager : </li></ul>
  128. 128. 宣称式事务 <ul><li>Spring 宣称式事务与 Session Bean 的 CMT 事务管理在使用上极为相似,但是在很多方面 Spring 要优于 EJB : </li></ul><ul><li>EJB 事务管理是绑定在 JTA 上的,而 Spring 则可以应用在任何情况下。 </li></ul><ul><li>EJB 事务管理不支持 POJOs </li></ul><ul><li>Spring 提供声明式回滚规则,并且可以通过 AOP 在事务中定制其它行为 </li></ul><ul><li>Spring 不依赖服务器 </li></ul><ul><li>但有一点, Spring 是无法取代 EJB 的,那就是分布式的事务管理。 </li></ul>
  129. 129. 宣称式事务 <ul><li>Spring 的宣称式事务管理实际上是应用了 Spring 的 AOP 特性,将事务管理的代码织入到原代码中。 </li></ul><ul><li>使用的代理类是 TransactionProxyFactoryBean ,位于 org.springframework.transaction.interceptor 包 </li></ul>
  130. 130. 宣称式事务
  131. 131. 传播行为
  132. 132. 传播行为

×