Spring课件

1,995 views

Published on

spring in action

Published in: Technology, Self Improvement
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,995
On SlideShare
0
From Embeds
0
Number of Embeds
29
Actions
Shares
0
Downloads
121
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

Spring课件

  1. 1. spring in action
  2. 2. 一、开始 spring 之旅 <ul><li>理解反向控制 (IOC) </li></ul><ul><ul><li>依赖注入:比 IOC 更好的名字。获得依赖对象的 </li></ul></ul><ul><ul><li>方式反转了。 </li></ul></ul><ul><ul><li>IOC 应用 </li></ul></ul><ul><ul><li>理解 AOP </li></ul></ul>
  3. 3. 二、装配 Bean <ul><li>2.1 容纳你的 bean </li></ul><ul><ul><li>bean 工厂 : 最简单的容器,提供了基础的依赖 </li></ul></ul><ul><ul><li>注入支持。创建各种类型的 Bean. </li></ul></ul><ul><ul><li>应用上下文 : 建立在 bean 工厂基础之上,提供系 </li></ul></ul><ul><ul><li>统架构服务。 </li></ul></ul>
  4. 4. 二、装配 Bean <ul><li>2.1 容纳你的 bean </li></ul><ul><ul><li>2.1.1 bean 工厂介绍 </li></ul></ul><ul><ul><ul><li>工厂设计模式,创建分发各种 bean 。配置好它们之 </li></ul></ul></ul><ul><ul><ul><li>间的写作关系,参与 bean 的生命周期。 </li></ul></ul></ul><ul><ul><ul><li>BeanFactory factory = new XmlBeanFactory( </li></ul></ul></ul><ul><ul><ul><li>new FileInputStream(“beans.xml”)); </li></ul></ul></ul><ul><ul><ul><li>bean 工厂只把 bean 的定义信息载进来,用到的时候 </li></ul></ul></ul><ul><ul><ul><li>才实例化。 </li></ul></ul></ul><ul><ul><ul><li>factory.getBean(“mybean”); 就可得到一个 </li></ul></ul></ul><ul><ul><ul><li>bean 。 </li></ul></ul></ul>
  5. 5. 二、装配 Bean <ul><li>2.1 容纳你的 bean </li></ul><ul><ul><li>2.1.2 使用应用上下文 </li></ul></ul><ul><ul><ul><li>ApplicationCotext,spring 更加高级的容器。功能 </li></ul></ul></ul><ul><ul><ul><li>强大: </li></ul></ul></ul><ul><ul><ul><li>1. 提供文本信息解析工具,包括对国际化支持。 </li></ul></ul></ul><ul><ul><ul><li>2. 提供载入文件资源的通用方法,如图片。 </li></ul></ul></ul><ul><ul><ul><li>3. 可以向注册为监听器的 bean 发送事件。 </li></ul></ul></ul><ul><ul><ul><li>在很少的情况下,使用 BeanFactory ,如在移动设 </li></ul></ul></ul><ul><ul><ul><li>备。 </li></ul></ul></ul>
  6. 6. 二、装配 Bean <ul><li>2.1 容纳你的 bean </li></ul><ul><ul><li>2.1.2 使用应用上下文 ( 续 ) </li></ul></ul><ul><ul><ul><li>三种经常用到的实现: </li></ul></ul></ul><ul><ul><ul><li>1.ClassPathXmlApplicationContext: 从类路径中加载。 </li></ul></ul></ul><ul><ul><ul><li>2.FileSystemXmlApplicationContext: 从文件系统加载。 </li></ul></ul></ul><ul><ul><ul><li>3.XmlWebApplicationContext: 从 web 系统中加载。 </li></ul></ul></ul>
  7. 7. 二、装配 Bean <ul><li>2.1 容纳你的 bean </li></ul><ul><ul><li>2.1.2 使用应用上下文 ( 续 ) </li></ul></ul><ul><ul><li>ApplicationContext context = </li></ul></ul><ul><ul><li>new FileSystemXmlApplicationContext(“ </li></ul></ul><ul><ul><li>c:foo.xml”); </li></ul></ul><ul><ul><li>ApplicationContext context = </li></ul></ul><ul><ul><li>new ClassPathXmlApplicationContext(“ </li></ul></ul><ul><ul><li>foo.xml”); </li></ul></ul>
  8. 8. 二、装配 Bean <ul><li>2.1 容纳你的 bean </li></ul><ul><ul><li>2.1.2 使用应用上下文 ( 续 ) </li></ul></ul><ul><ul><li>除了应用上下文提供的附加功能外,应用上下文 </li></ul></ul><ul><ul><li>与 bean 工厂的另一个重要区别是关于单例 bean </li></ul></ul><ul><ul><li>如何被加载。 </li></ul></ul><ul><ul><li>bean 工厂延迟加载所有 bean ,直到 getBean() </li></ul></ul><ul><ul><li>方法被调用。 </li></ul></ul><ul><ul><li>应用上下文会在启动后预载入所有单例 bean. 这样可确 </li></ul></ul><ul><ul><li>保应用不需要等待他们被创建。 </li></ul></ul>
  9. 9. 二、装配 Bean <ul><li>2.1 容纳你的 bean </li></ul><ul><ul><li>2.1.3 bean 的生命周期 </li></ul></ul><ul><ul><li>bean 被载入到容器中时,他的生命周期就开始 </li></ul></ul><ul><ul><li>了。 bean 工厂在一个 bean 可以使用前完成很多 </li></ul></ul><ul><ul><li>工作: </li></ul></ul><ul><ul><li>1. 容器寻找 bean 的定义信息并实例化。 </li></ul></ul><ul><ul><li>2. 使用依赖注入, spring 按 bean 定义信息配置 bean 的所有属性。 </li></ul></ul><ul><ul><li>3. 若 bean 实现了 BeanNameAware 接口,工厂调用 Bean 的 setBeanName </li></ul></ul><ul><ul><li>()方法传递 bean 的 ID 。 </li></ul></ul><ul><ul><li>4. 若 bean 实现了 BeanFactoryAware 接口,工厂调用 setBeanFactory () </li></ul></ul><ul><ul><li>方法传入工厂自身。 </li></ul></ul><ul><ul><li>5. 若 BeanPostProcessor 和 bean 关联,则它们的 </li></ul></ul><ul><ul><li>postProcessBeforeInitialization() 方法被调用。 </li></ul></ul><ul><ul><li>6. 若 bean 指定了 ini-method 方法、,它将被调用。 </li></ul></ul><ul><ul><li>7. 最后,若有 BeanPostProcessor 和 bean 关联,则它们的 </li></ul></ul><ul><ul><li>postProcessAfterInitialization() 方法被调用、。 </li></ul></ul>
  10. 10. 二、装配 Bean <ul><li>2.1 容纳你的 bean </li></ul><ul><ul><li>2.1.3 bean 的生命周期 ( 续 ) </li></ul></ul><ul><ul><li>将 bean 从工厂中删掉有两种方法: </li></ul></ul><ul><ul><li>1. 若 bean 实现了 DisposableBean 接口, </li></ul></ul><ul><ul><li>distroy() 方法被调用。 </li></ul></ul><ul><ul><li>2. 如果指定了定制的销毁方法,就调用这个方法。 </li></ul></ul><ul><ul><li>bean 在应用上下文中的生命周期和在 bean 工厂 </li></ul></ul><ul><ul><li>的生命周期唯一不同的是:若 bean 实现了 </li></ul></ul><ul><ul><li>ApplicationContextAware() 接口, </li></ul></ul><ul><ul><li>setApplicationContext() 方法会被调用。 </li></ul></ul>
  11. 11. 二、装配 Bean <ul><li>2.1 容纳你的 bean </li></ul><ul><ul><li>2.1.3 bean 的生命周期 ( 续 ) </li></ul></ul>实例化 设置属性值 调用 BeanNameAware 的 setBeanName() 方法 调用 BeanFactoryAware 的 setBeanFactory() 方法 调用 BeanPostProcessor 的 预初始化方法 调用 InitializingBean 的 afterPropertiesSet() 方法 调用调用定制的初始化方法 调用 BeanPostProcessor 的 后初始化方法 Bean 可以使用了 容器关闭 调用 DisposableBean 的 destory() 方法 调用定制的销毁方法 Bean 在 Spring Bean 工厂中的生命周期
  12. 12. 二、装配 Bean <ul><li>2.1 容纳你的 bean </li></ul><ul><ul><li>2.1.3 bean 的生命周期 ( 续 ) </li></ul></ul>实例化 设置属性值 调用 BeanNameAware 的 setBeanName() 方法 调用 BeanFactoryAware 的 setBeanFactory() 方法 调用 BeanPostProcessor 的 预初始化方法 调用 InitializingBean 的 afterPropertiesSet() 方法 调用调用定制的初始化方法 调用 BeanPostProcessor 的 后初始化方法 Bean 可以使用了 容器关闭 调用 DisposableBean 的 destory() 方法 调用定制的销毁方法 Bean 在 Spring Bean 应用上下文中的生命周期 调用 ApplicationContextAware 方法 setApplicationContext() 方法
  13. 13. 二、装配 Bean <ul><li>2.2 基本装配 </li></ul><ul><li>在 spring 容器内拼凑 bean 叫做装配。装 </li></ul><ul><li>配 bean 的时候,需要告诉容器哪些 bean </li></ul><ul><li>以及容器如何使用依赖注入将它们配合在 </li></ul><ul><li>一起。 </li></ul>
  14. 14. 二、装配 Bean <ul><li>2.2 基本装配 </li></ul><ul><ul><li>2.2.1 使用 XML 装配 </li></ul></ul><ul><ul><li>xml 是最常见的 spring 应用系统配置源。 </li></ul></ul><ul><ul><li>几种 spring 容器都支持使用 xml 装配 bean ,包括: </li></ul></ul><ul><ul><li>1.XmlBeanFactory: 调用 InputStream 载入上下文 </li></ul></ul><ul><ul><li>定义文件。 </li></ul></ul><ul><ul><li>2.ClassPathXmlApplicationContext: 从类路径载 </li></ul></ul><ul><ul><li>入上下文定义文件。 </li></ul></ul><ul><ul><li>3.XmlWenApplicationContext: 从 web 应用上下文 </li></ul></ul><ul><ul><li>中载入定义文件。 </li></ul></ul>
  15. 15. 二、装配 Bean <ul><li>2.2 基本装配 </li></ul><ul><ul><li>2.2.1 使用 XML 装配 ( 续 ) </li></ul></ul><ul><ul><li>上下文定义文件的根元素是 <beans>.<beans> 有多 </li></ul></ul><ul><ul><li>个 <bean> 子元素。每个 <bean> 元素定义了一个 </li></ul></ul><ul><ul><li>bean 如何被装配到 spring 容器中。 </li></ul></ul><ul><ul><li><beans> </li></ul></ul><ul><ul><li><bean id=“foo” class=“...Foo”/> </li></ul></ul><ul><ul><li><bean id=“bar” class=“...Bar”/> </li></ul></ul><ul><ul><li></beans> </li></ul></ul>
  16. 16. 二、装配 Bean <ul><li>2.2 基本装配 </li></ul><ul><ul><li>2.2.2 添加一个 bean </li></ul></ul><ul><ul><li>对 bean 的最基本的配置包括 bean 的 ID 和他的 </li></ul></ul><ul><ul><li>全称类名。 </li></ul></ul><ul><ul><li><bean id=“foo” class=“...Foo”/> </li></ul></ul><ul><ul><li>bean 的 id 是 foo 。 </li></ul></ul>
  17. 17. 二、装配 Bean <ul><li>2.2 基本装配 </li></ul><ul><ul><li>2.2.2 添加一个 bean( 续 ) </li></ul></ul><ul><ul><ul><li>原型与单实例 </li></ul></ul></ul><ul><ul><ul><li>spring 中的 bean 缺省情况下是单例模式。始终返 </li></ul></ul></ul><ul><ul><ul><li>回一个实例。若想返回不同的实例的话需要定义 </li></ul></ul></ul><ul><ul><ul><li>成原型模式。 </li></ul></ul></ul><ul><ul><ul><li>bean 的 singleton 属性告诉上下文该 bean 是否为 </li></ul></ul></ul><ul><ul><ul><li>单例的。缺省为 true 。若为 false 的话,为原型 </li></ul></ul></ul><ul><ul><ul><li>bean 。 </li></ul></ul></ul><ul><ul><ul><li><bean id=“foo” class=“...Foo” </li></ul></ul></ul><ul><ul><ul><li>singleton=“false”/> </li></ul></ul></ul>
  18. 18. 二、装配 Bean <ul><li>2.2 基本装配 </li></ul><ul><ul><li>2.2.2 添加一个 bean( 续 ) </li></ul></ul><ul><ul><li>使用原型 bean 会对性能产生影响,尽量不要把 singleton 设置为 false, 除非有必要。 </li></ul></ul>
  19. 19. 二、装配 Bean <ul><li>2.2 基本装配 </li></ul><ul><ul><li>2.2.2 添加一个 bean( 续 ) </li></ul></ul><ul><ul><ul><li>实例化与销毁 </li></ul></ul></ul><ul><ul><ul><li>spring 实例化 bean 或销毁 bean 时,有时需要作一些处理工作,因此 spring 可以在创建和拆卸 bean 的时候调用 bean 的两个生命周期方法。 </li></ul></ul></ul><ul><ul><ul><li><bean id=“foo” class=“...Foo” </li></ul></ul></ul><ul><ul><ul><li>init-method=“setup” </li></ul></ul></ul><ul><ul><ul><li>destory-method=“teardown”/> </li></ul></ul></ul>
  20. 20. 二、装配 Bean <ul><li>2.2 基本装配 </li></ul><ul><ul><li>2.2.2 添加一个 bean( 续 ) </li></ul></ul><ul><ul><li>spring 也提供了两个接口来实现相同的功能: </li></ul></ul><ul><ul><li>InitializingBean 和 DisposableBean. </li></ul></ul><ul><ul><li>InitializingBean 接口提供了一个 afterPropertiesSet() 方法。 </li></ul></ul><ul><ul><li>DisposableBean 接口提供了 destroy(). </li></ul></ul><ul><ul><li>不推荐使用该接口,它将你的 bean 和 springAPI 邦定在一起 。 </li></ul></ul>
  21. 21. 二、装配 Bean <ul><li>2.2 基本装配 </li></ul><ul><ul><li>2.2.3 通过 set 方法注入依赖 </li></ul></ul><ul><ul><li><bean> 元素的 < property > 子元素指明了使用它们的 set 方法来注入。可以注入任何东西,从基本类型到集合类,甚至是应用系统的 bean 。 </li></ul></ul>
  22. 22. 二、装配 Bean <ul><li>2.2 基本装配 </li></ul><ul><ul><li>2.2.3 通过 set 方法注入依赖 ( 续 ) </li></ul></ul><ul><ul><li>简单 bean 配置 </li></ul></ul><ul><ul><li>配置 bean 的简单属性,基本数据类型和 string 。 </li></ul></ul><ul><ul><li><bean id=“foo” class=“...Foo”> </li></ul></ul><ul><ul><li><property name=“name”> </li></ul></ul><ul><ul><li><value>tom</value> </li></ul></ul><ul><ul><li></property> </li></ul></ul><ul><ul><li></bean> </li></ul></ul>
  23. 23. 二、装配 Bean <ul><li>2.2 基本装配 </li></ul><ul><ul><li>2.2.3 通过 set 方法注入依赖 ( 续 ) </li></ul></ul><ul><ul><li>引用其它 bean </li></ul></ul><ul><ul><li><bean id=“foo” class=“...Foo”> </li></ul></ul><ul><ul><li><property name=“name”> </li></ul></ul><ul><ul><li><ref bean=“bar”> </li></ul></ul><ul><ul><li></property> </li></ul></ul><ul><ul><li></bean> </li></ul></ul><ul><ul><li><bean id=“bar” class=“...Bar”> </li></ul></ul><ul><ul><li></bean> </li></ul></ul>
  24. 24. 二、装配 Bean <ul><li>2.2 基本装配 </li></ul><ul><ul><li>2.2.3 通过 set 方法注入依赖 ( 续 ) </li></ul></ul><ul><ul><li>内部 bean </li></ul></ul><ul><ul><li><bean id=“foo” class=“...Foo”> </li></ul></ul><ul><ul><li><property name=“bar”> </li></ul></ul><ul><ul><li><bean class=“...Bar”> </li></ul></ul><ul><ul><li></property> </li></ul></ul><ul><ul><li></bean> </li></ul></ul><ul><ul><li>这种方式的缺点是你无法在其它地方重用这个 bar 实 </li></ul></ul><ul><ul><li>例,原因是它是专门为 foo 而用。 </li></ul></ul>
  25. 25. 二、装配 Bean <ul><li>2.2 基本装配 </li></ul><ul><ul><li>2.2.3 通过 set 方法注入依赖 ( 续 ) </li></ul></ul><ul><ul><li>装配集合 </li></ul></ul><ul><ul><li>若 bean 的属性是集合类型,按如下处理: </li></ul></ul><ul><ul><li>装配 List 和数组: </li></ul></ul><ul><ul><li><property name=“barlist”> </li></ul></ul><ul><ul><li><list> </li></ul></ul><ul><ul><li><value>bar1</value> </li></ul></ul><ul><ul><li><ref bean=“bar2”/> </li></ul></ul><ul><ul><li></list> </li></ul></ul><ul><ul><li></property> </li></ul></ul>
  26. 26. 二、装配 Bean <ul><li>2.2 基本装配 </li></ul><ul><ul><li>2.2.3 通过 set 方法注入依赖 ( 续 ) </li></ul></ul><ul><ul><li>装配集合 </li></ul></ul><ul><ul><li>装配 set : </li></ul></ul><ul><ul><li><property name=“barlist”> </li></ul></ul><ul><ul><li><set> </li></ul></ul><ul><ul><li><value>bar1</value> </li></ul></ul><ul><ul><li><ref bean=“bar2”/> </li></ul></ul><ul><ul><li></set> </li></ul></ul><ul><ul><li></property> </li></ul></ul><ul><ul><li>set 使用方法和 list 一样,不同的是对象被装配到 set </li></ul></ul><ul><ul><li>中,而 list 是装配到 List 或数组中装配。 </li></ul></ul>
  27. 27. 二、装配 Bean <ul><li>2.2 基本装配 </li></ul><ul><ul><li>2.2.3 通过 set 方法注入依赖 ( 续 ) </li></ul></ul><ul><ul><li>装配 map : </li></ul></ul><ul><ul><li><property name=“barlist”> </li></ul></ul><ul><ul><li><map> </li></ul></ul><ul><ul><li><entry key=“key1”> </li></ul></ul><ul><ul><li><value>bar1</value> </li></ul></ul><ul><ul><li></entry> </li></ul></ul><ul><ul><li><entry key=“key2”> </li></ul></ul><ul><ul><li><ref bean=“bar2”> </li></ul></ul><ul><ul><li></entry> </li></ul></ul><ul><ul><li><ref bean=“bar2”/> </li></ul></ul><ul><ul><li></map> </li></ul></ul><ul><ul><li></property> </li></ul></ul><ul><ul><li>map 中的 <entry> 的数值和 <list> 以及 <set> 的一样,可以使任何有效 </li></ul></ul><ul><ul><li>的属性元素,需要注意的是 key 值必须是 string 的。 </li></ul></ul>
  28. 28. 二、装配 Bean <ul><li>2.2 基本装配 </li></ul><ul><ul><li>2.2.3 通过 set 方法注入依赖 ( 续 ) </li></ul></ul><ul><ul><li>装配 Properties : </li></ul></ul><ul><ul><li><property name=“barlist”> </li></ul></ul><ul><ul><li><props> </li></ul></ul><ul><ul><li><prop key=“key1”>bar1</prop> </li></ul></ul><ul><ul><li><prop key=“key2”>bar2</prop> </li></ul></ul><ul><ul><li></props> </li></ul></ul><ul><ul><li></property> </li></ul></ul>
  29. 29. 二、装配 Bean <ul><li>2.2 基本装配 </li></ul><ul><ul><li>2.2.3 通过 set 方法注入依赖 ( 续 ) </li></ul></ul><ul><ul><li>若 bean 的属性是集合类型,按如下处理: </li></ul></ul><ul><ul><li>设置 null : </li></ul></ul><ul><ul><li><property name=“barlist”> </li></ul></ul><ul><ul><li><null/> </li></ul></ul><ul><ul><li></property> </li></ul></ul>
  30. 30. 二、装配 Bean <ul><li>2.2 基本装配 </li></ul><ul><ul><li>2.2.3 通过 set 方法注入依赖 ( 续 ) </li></ul></ul><ul><ul><li>Set 注入的替代: </li></ul></ul><ul><ul><li>set 注入是一种直接方式,缺点是它假设了所 </li></ul></ul><ul><ul><li>有的可变属性都可以通过 set 方法访问到。例如有些属性在创建时设置一次,以后不再改变。 </li></ul></ul><ul><ul><li>替代方式是通过构造函数设置一些属性值。 </li></ul></ul>
  31. 31. 二、装配 Bean <ul><li>2.2 基本装配 </li></ul><ul><ul><li>2.2.4 通过构造函数注入依赖 </li></ul></ul><ul><ul><li><bean id=“foo” class=“...Foo”> </li></ul></ul><ul><ul><li><constructor-arg> </li></ul></ul><ul><ul><li><value>42</value> </li></ul></ul><ul><ul><li></constructor> </li></ul></ul><ul><ul><li></bean> </li></ul></ul><ul><ul><li><bean id=“foo” class=“...Foo”> </li></ul></ul><ul><ul><li><constructor-arg> </li></ul></ul><ul><ul><li><ref bean=“bar”> </li></ul></ul><ul><ul><li></constructor> </li></ul></ul><ul><ul><li></bean> </li></ul></ul><ul><ul><li>set 注入的缺点是无法清晰表达哪些属性是必须的,哪些是可选 </li></ul></ul><ul><ul><li>的,构造注入的优势是通过构造强制依赖关系,不可能实例化不 </li></ul></ul><ul><ul><li>完全的或无法使用的 bean 。 </li></ul></ul>
  32. 32. 二、装配 Bean <ul><li>2.2 基本装配 </li></ul><ul><ul><li>2.2.4 通过构造函数注入依赖 ( 续 ) </li></ul></ul><ul><ul><li>解决构造函数参数不确定性 </li></ul></ul><ul><ul><li>构造函数多或参数类型大都相同该如何处理? </li></ul></ul><ul><ul><li>spring 并不是按照参数的顺序来配置参数的。 </li></ul></ul><ul><ul><li>有两种方法来解决构造参数的不确定性:序号和类型。 </li></ul></ul><ul><ul><li><constructor-arg> 有一个可选的 index 属性,可用来指定参数的顺序。 </li></ul></ul>
  33. 33. 二、装配 Bean <ul><li>2.2 基本装配 </li></ul><ul><ul><li>2.2.4 通过构造函数注入依赖 ( 续 ) </li></ul></ul><ul><ul><li>解决构造函数参数不确定性 </li></ul></ul><ul><ul><li>通过参数的顺序: </li></ul></ul><ul><ul><li><constructor-arg index=0> </li></ul></ul><ul><ul><li><value>http://www.tom.com</value> </li></ul></ul><ul><ul><li></construcotr-arg> </li></ul></ul><ul><ul><li><constructor-arg index=1> </li></ul></ul><ul><ul><li><value>bar1</value> </li></ul></ul><ul><ul><li></construcotr-arg> </li></ul></ul>
  34. 34. 二、装配 Bean <ul><li>2.2 基本装配 </li></ul><ul><ul><li>2.2.4 通过构造函数注入依赖 ( 续 ) </li></ul></ul><ul><ul><li>解决构造函数参数不确定性 </li></ul></ul><ul><ul><li>通过参数的类型: </li></ul></ul><ul><ul><li><constructor-arg type=“java.lang.String”> </li></ul></ul><ul><ul><li><value>http://www.tom.com</value> </li></ul></ul><ul><ul><li></construcotr-arg> </li></ul></ul><ul><ul><li><constructor-arg java.lang.URL> </li></ul></ul><ul><ul><li><value>bar1</value> </li></ul></ul><ul><ul><li></construcotr-arg> </li></ul></ul>
  35. 35. 二、装配 Bean <ul><li>2.3 自动装配 </li></ul><ul><li><bean id=“foo” class=“...Foo” </li></ul><ul><li>autowire=“autowire type”> </li></ul><ul><li>有四种自动装配类型: </li></ul><ul><li>1.byName: 寻找和属性名相同的 bean ,若找 </li></ul><ul><li>不到,则装不上。 </li></ul><ul><li>2.byType: 寻找和属性类型相同的 bean ,若找 </li></ul><ul><li>不到,则装不上,找到多个,抛异常。 </li></ul><ul><li>3.constructor: 查找和 bean 的构造参数一致的一个或 </li></ul><ul><li>多个 bean ,若找不到或找到多个,抛异常。按照参数的类型装配,与 (2) </li></ul><ul><li>相似 . </li></ul><ul><li>4.autodetect: 首先尝试用 (3) 来装配,然后使用 (2) 方式。不确定 </li></ul><ul><li>性的处理与 (3) 和 (2) 一致。 </li></ul><ul><li><bean id=“bar” class=“...Bar” autowire=“byName”/> </li></ul>
  36. 36. 二、装配 Bean <ul><li>2.3 自动装配 </li></ul><ul><ul><li>2.3.1 处理自动装配的不确定性 </li></ul></ul><ul><ul><li>使用 byType 和 constructor 自动装配时,若找到多个符合条件的 bean ,会报异常,因此最好的方式是不用自动组装。 </li></ul></ul>
  37. 37. 二、装配 Bean <ul><li>2.3 自动装配 </li></ul><ul><ul><li>2.3.2 混合使用手动和自动组装 </li></ul></ul><ul><ul><li><bean id=“bar” class=“...Bar” </li></ul></ul><ul><ul><li>autowire=“byName”> </li></ul></ul><ul><ul><li><property name=“cousedao”> </li></ul></ul><ul><ul><li><ref bean=“somebean” /> </li></ul></ul><ul><ul><li></property> </li></ul></ul><ul><ul><li></bean> </li></ul></ul>
  38. 38. 二、装配 Bean <ul><li>2.3 自动装配 </li></ul><ul><ul><li>2.3.3 缺省自动组装 </li></ul></ul><ul><ul><li>默认不是自动组装。 </li></ul></ul><ul><ul><li>通过 < beans default- </li></ul></ul><ul><ul><li>autowire=“byName”> </li></ul></ul><ul><ul><li>可将 bean 设置为自动组装。 </li></ul></ul>
  39. 39. 二、装配 Bean <ul><li>2.4 使用 spring 的特殊 bean </li></ul><ul><li>让 spring 特殊对待这些 bean 。使它们可以: </li></ul><ul><li>1. 通过配置后加工 bean ,涉及到 Bean 和 Bean 工厂生命 </li></ul><ul><li>周期。 </li></ul><ul><li>2. 改变依赖注入,将字符串转换成其它类型。 </li></ul><ul><li>3. 从属性文本装载信息,包括信息国际化。 </li></ul><ul><li>4. 监听并处理其它 bean 及 spring 发布的系统消息。 </li></ul><ul><li>5. 知道自己在 spring 中的唯一表识。 </li></ul>
  40. 40. 二、装配 Bean <ul><li>2.4 使用 spring 的特殊 bean </li></ul><ul><ul><li>2.4.1 对 bean 进行后处理 </li></ul></ul><ul><ul><li>BeanPostProcessor 接口提供机会来修改 bean 。 </li></ul></ul><ul><ul><li>public interface BeanPostProcessor{ </li></ul></ul><ul><ul><li>//Bean 初始化 ( 调用 afterPropertiesSet() 以及 Bean 的指 </li></ul></ul><ul><ul><li>// 定 initmethod 方法 ) 之前被调用。 </li></ul></ul><ul><ul><li>Object postProcessorBeforeInitialation(…); </li></ul></ul><ul><ul><li>// 在初始化之后马上调用 </li></ul></ul><ul><ul><li>Object postProcessorAfterInitialization(…); </li></ul></ul><ul><ul><li>} </li></ul></ul>
  41. 41. 二、装配 Bean <ul><li>2.4 使用 spring 的特殊 bean </li></ul><ul><ul><li>2.4.1 对 bean 进行后处理 ( 续 ) </li></ul></ul><ul><ul><li>注册后处理 Bean </li></ul></ul><ul><ul><li>如果使用的是 Bean 工厂 , 需要调用工厂的 addBeanPostProcessor() 来注册 . </li></ul></ul><ul><ul><li>factory.addBeanPostProcessor(…); </li></ul></ul><ul><ul><li>如果使用的是上下文同其他 Bean 一样 : </li></ul></ul><ul><ul><li><bean id=“” class=“……” /> </li></ul></ul>
  42. 42. 二、装配 Bean <ul><li>2.4 使用 spring 的特殊 bean </li></ul><ul><ul><li>2.4.2 对 bean 工厂进行后处理 </li></ul></ul><ul><ul><li>  BeanPostProcessor 在 bean 载入后,对 bean 进行一些后处理工作。而 BeanFactoryPostProcessor 在 bean 工厂载入所有 bean 的定义后,实例化 bean 之前,对 Bean 工厂做一些后处理工作。 </li></ul></ul><ul><ul><li>  public interface BeanFactoryPostProcessor{ </li></ul></ul><ul><ul><li>public void postProcessorBeanFactory(…); </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>如果使用的是应用上下文不需要将他注册为 Bean 工厂后处理器。上下文会自动注册它。按照正常的 Bean 声明即可。 </li></ul></ul>
  43. 43. 二、装配 Bean <ul><li>2.4 使用 spring 的特殊 bean </li></ul><ul><ul><li>2.4.3 分散配置 </li></ul></ul><ul><ul><li>将配置文件分成几个分散的配置文件是很有益的。如数据源。 </li></ul></ul><ul><ul><li><bean id=“propertyConfigurer” </li></ul></ul><ul><ul><li>class=“...PropertyPlaceholderConfigurer”> </li></ul></ul><ul><ul><li><property name=“locations”> </li></ul></ul><ul><ul><li><list> </li></ul></ul><ul><ul><li><value>jdbc.properties</value> </li></ul></ul><ul><ul><li><value>securtiy.properties</value> </li></ul></ul><ul><ul><li><value>application.properties</value> </li></ul></ul><ul><ul><li></list> </li></ul></ul><ul><ul><li></property> </li></ul></ul><ul><ul><li></bean> </li></ul></ul>
  44. 44. 二、装配 Bean <ul><li>2.4 使用 spring 的特殊 bean </li></ul><ul><ul><li>2.4.3 分散配置 ( 续 ) </li></ul></ul><ul><ul><li>jdbc.properties </li></ul></ul><ul><ul><li>database.url= </li></ul></ul><ul><ul><li>database.driver= </li></ul></ul><ul><ul><li>datebase.username= </li></ul></ul><ul><ul><li>datebase.password= </li></ul></ul>
  45. 45. 二、装配 Bean <ul><li>2.4 使用 spring 的特殊 bean </li></ul><ul><ul><li>2.4.3 分散配置 ( 续 ) </li></ul></ul><ul><ul><li>使用占位符变量代替 bean 装配文件中的硬编码配置。占位符采 </li></ul></ul><ul><ul><li>${variable} 形式。 </li></ul></ul><ul><ul><li><bean id=“datasource” </li></ul></ul><ul><ul><li>    class=“org.springframework.jdbc.datasource </li></ul></ul><ul><ul><li>           .DriverManagerDataSource”> </li></ul></ul><ul><ul><li><property name=“url”> </li></ul></ul><ul><ul><li><value>${database.url}</value> </li></ul></ul><ul><ul><li></property> </li></ul></ul><ul><ul><li>...... </li></ul></ul><ul><ul><li></bean> </li></ul></ul>
  46. 46. 二、装配 Bean <ul><li>2.4 使用 spring 的特殊 bean </li></ul><ul><ul><li>2.4.4 定制属性编辑器 </li></ul></ul><ul><ul><li>public contact{ </li></ul></ul><ul><ul><li>private PhoneNumber phone; </li></ul></ul><ul><ul><li>void setPhoneNumber(){ </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>...... </li></ul></ul><ul><ul><li>} </li></ul></ul>
  47. 47. 二、装配 Bean <ul><li>2.4 使用 spring 的特殊 bean </li></ul><ul><ul><li>2.4.4 定制属性编辑器 ( 续 ) </li></ul></ul><ul><ul><li>public PhoneNumber{ </li></ul></ul><ul><ul><li>private String areacode ; </li></ul></ul><ul><ul><li>private String prefix ; </li></ul></ul><ul><ul><li>private String number ; </li></ul></ul><ul><ul><li>...... </li></ul></ul><ul><ul><li>public PhoneNumber(arg0,arg1,arg2){ </li></ul></ul><ul><ul><li>...... </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>} </li></ul></ul>
  48. 48. 二、装配 Bean <ul><li>2.4 使用 spring 的特殊 bean </li></ul><ul><ul><li>2.4.4 定制属性编辑器 ( 续 ) </li></ul></ul><ul><ul><li><bean id=“infoPhone” </li></ul></ul><ul><ul><li>class=“PhoneNumber”> </li></ul></ul><ul><ul><li><constructor-arg index=0> </li></ul></ul><ul><ul><li><value>888</value> </li></ul></ul><ul><ul><li></constructor-arg> </li></ul></ul><ul><ul><li><constructor-arg index=1> </li></ul></ul><ul><ul><li><value>555</value> </li></ul></ul><ul><ul><li></constructor-arg> </li></ul></ul><ul><ul><li><constructor-arg index=2> </li></ul></ul><ul><ul><li><value>1212</value> </li></ul></ul><ul><ul><li></constructor-arg> </li></ul></ul><ul><ul><li></bean> </li></ul></ul><ul><ul><li><bean id=“contact” class=“Contact”> </li></ul></ul><ul><ul><li><property name=“phoneNumber”> </li></ul></ul><ul><ul><li><ref bean=“infoPhone”/> </li></ul></ul><ul><ul><li></property> </li></ul></ul><ul><ul><li></bean> </li></ul></ul>
  49. 49. 二、装配 Bean <ul><li>2.4 使用 spring 的特殊 bean </li></ul><ul><ul><li>2.4.4 定制属性编辑器 ( 续 ) </li></ul></ul><ul><ul><li>编写一个自定义的 PhoneEditor </li></ul></ul><ul><ul><li>class PhoneEditor extends </li></ul></ul><ul><ul><li>java.beans.PropertyEditorSupport { </li></ul></ul><ul><ul><li>void setAsText(String textvalue){ </li></ul></ul><ul><ul><li>...... </li></ul></ul><ul><ul><li>p=new PhoneNumber(......); </li></ul></ul><ul><ul><li>setValue(p); </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>} </li></ul></ul>
  50. 50. 二、装配 Bean <ul><li>2.4 使用 spring 的特殊 bean </li></ul><ul><ul><li>2.4.4 定制属性编辑器 ( 续 ) </li></ul></ul><ul><ul><li><bean id=“customerEditorConfigurer” </li></ul></ul><ul><ul><li>class=“...config.CustomEditorConfigurer”> </li></ul></ul><ul><ul><li><property name=“customEditors”> </li></ul></ul><ul><ul><li><map> </li></ul></ul><ul><ul><li><entry key=“Phone”> </li></ul></ul><ul><ul><li><bean id=“phoneEditor” </li></ul></ul><ul><ul><li>class=“PhoneEditor”> </li></ul></ul><ul><ul><li></bean> </li></ul></ul><ul><ul><li></entry> </li></ul></ul><ul><ul><li></map> </li></ul></ul><ul><ul><li></property> </li></ul></ul><ul><ul><li></bean> </li></ul></ul><ul><ul><li><bean id=“contact” class=“Contact”> </li></ul></ul><ul><ul><li><property name=phoneNumber> </li></ul></ul><ul><ul><li><value>888-555-1212</value> </li></ul></ul><ul><ul><li></property> </li></ul></ul><ul><ul><li></bean> </li></ul></ul>
  51. 51. 二、装配 Bean <ul><li>2.4 使用 spring 的特殊 bean </li></ul><ul><ul><li>2.4.5 解析文本信息 </li></ul></ul><ul><ul><li>有些信息经常发生改变或提供国际化功能。用本地语言显示文本。 </li></ul></ul><ul><ul><li>trainingtext.properties </li></ul></ul><ul><ul><li>trainingtext_en_US.properties </li></ul></ul><ul><ul><li>trainingtext_es_MX.properties </li></ul></ul><ul><ul><li>trainingtext_de_DE.properties </li></ul></ul><ul><ul><li>spring 提供了一个现成的 messageSource 接口的实现类。 ResourceBundleMessageSource. </li></ul></ul><ul><ul><li>Bean 的名字必须是 messageSource, </li></ul></ul><ul><ul><li>context.getMessage(……); </li></ul></ul>
  52. 52. 二、装配 Bean <ul><li>2.4 使用 spring 的特殊 bean </li></ul><ul><ul><li>2.4.5 解析文本信息 ( 续 ) </li></ul></ul><ul><ul><li><bean id=“messageSource” </li></ul></ul><ul><ul><li>class=“org.springframework. </li></ul></ul><ul><ul><li>context.support. </li></ul></ul><ul><ul><li>ResouceBundleMessageSource”> </li></ul></ul><ul><ul><li><property name=“basename”> </li></ul></ul><ul><ul><li><value>trainingtext</value> </li></ul></ul><ul><ul><li></property> </li></ul></ul><ul><ul><li></bean> </li></ul></ul><ul><ul><li>context.getMessage(...); </li></ul></ul><ul><ul><li><spring:message ...> </li></ul></ul>
  53. 53. 二、装配 Bean <ul><li>2.4 使用 spring 的特殊 bean </li></ul><ul><ul><li>2.4.6 监听事件 </li></ul></ul><ul><ul><li>应用上下文会发布很多事件,告诉感兴趣的监听器都 </li></ul></ul><ul><ul><li>发生了什么事件,这些事件都是抽象类 </li></ul></ul><ul><ul><li>org.sf.contxt.ApplicationEvent 的子类。 </li></ul></ul><ul><ul><li>系统事件有: </li></ul></ul><ul><ul><li>1.ContextCloseEvent 上下文关闭时发布 </li></ul></ul><ul><ul><li>2.ContextRefreshedEvent 上下文初始化或刷新 </li></ul></ul><ul><ul><li>3.RequestHandledEvent web 上下文中请求被处理 </li></ul></ul><ul><ul><li>后发布。 </li></ul></ul>
  54. 54. 二、装配 Bean <ul><li>2.4 使用 spring 的特殊 bean </li></ul><ul><ul><li>2.4.6 监听事件 ( 续 ) </li></ul></ul><ul><ul><li>若需要 bean 对系统事件进行响应需要实现接口 org.sf.ctxt.ApplicationListener. 该接口需要实现 onApplicationEvent(...) 方法。 </li></ul></ul><ul><ul><li>注册监听器: </li></ul></ul><ul><ul><li><bean id=“refreshListener” </li></ul></ul><ul><ul><li>class=“foo.RefreshListener”/> </li></ul></ul>
  55. 55. 二、装配 Bean <ul><li>2.4 使用 spring 的特殊 bean </li></ul><ul><ul><li>2.4.7 发布事件 </li></ul></ul><ul><ul><li>Bean 可以很容易的处理容器发布的事件 , 同时 </li></ul></ul><ul><ul><li>也可以发布自己的事件 . </li></ul></ul><ul><ul><li>首先要定义自己的事件 : </li></ul></ul><ul><ul><li>pubic class MyEvent extends ApplicationEvent{ </li></ul></ul><ul><ul><li>...... </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>// 发布事件 </li></ul></ul><ul><ul><li>context.publish(new MyEvent()); </li></ul></ul>
  56. 56. 二、装配 Bean <ul><li>2.4 使用 spring 的特殊 bean </li></ul><ul><ul><li>2.4.8 感知其他 bean </li></ul></ul><ul><ul><li>运行在 spring 容器中的 bean 不知道自己的注册名,运行在哪里。实现以下三个接口: </li></ul></ul><ul><ul><li>BeanNameAware: 知道自己的名字。 </li></ul></ul><ul><ul><li>BeanFactoryAware :所处的 bean 工厂。 </li></ul></ul><ul><ul><li>ApplicationContextAware :所在上下文 </li></ul></ul>
  57. 57. 二、装配 Bean <ul><li>2.4 使用 spring 的特殊 bean </li></ul><ul><ul><li>2.4.8 感知其他 bean( 续 ) </li></ul></ul><ul><ul><li>知道你是谁 </li></ul></ul><ul><ul><li>实现 BeanNameAware 接口。无需为该接口的 setBeanName() 方法作任何处理, bean 被载入时,容器会自动调用该方法,为其设置 id 或 name 的值。 </li></ul></ul>
  58. 58. 二、装配 Bean <ul><li>2.4 使用 spring 的特殊 bean </li></ul><ul><ul><li>2.4.8 感知其他 bean( 续 ) </li></ul></ul><ul><ul><li>知道你在哪里 </li></ul></ul><ul><ul><li>实现 BeanFactoryAware( 感知 ) 或 ApplicationContextAware 接口。分别定义了 setBeanFactory() 和 setApplicationContext() 方法。 </li></ul></ul>
  59. 59. 三、创建切面 <ul><li>3.1 AOP 介绍 </li></ul>CourseService CourseService CourseService 安 全 事 务 其 他
  60. 60. 三、创建切面 <ul><li>3.1 AOP 介绍 </li></ul><ul><ul><li>3.1.1 定义 AOP 术语 </li></ul></ul><ul><ul><li>1. 切面 (aspect): 要实现的交叉功能,是系统模块化的一个切面或领域。如日志记录。 </li></ul></ul><ul><ul><li>2. 连接点 : 应用程序执行过程中插入切面的地点,可以是方法调用,异常抛出,或者要修改的 </li></ul></ul><ul><ul><li>字段。 </li></ul></ul><ul><ul><li>3. 通知 : 切面的实际实现,他通知系统新的行为。如在日志通知包含了实 </li></ul></ul><ul><ul><li>现日志功能的代码,如向日志文件写日志。通知在连接点插入到应用系统中。 </li></ul></ul><ul><ul><li>4. 切入点 : 定义了通知应该应用在哪些连接点,通知可以应用到 AOP 框架支持的任何连接点。 </li></ul></ul><ul><ul><li>5. 引入 : 为类添加新方法和属性。 </li></ul></ul><ul><ul><li>6. 目标对象 : 被通知的对象。既可以是你编写的类也可以是第三方类。 </li></ul></ul><ul><ul><li>7. 代理 : 将通知应用到目标对象后创建的对象,应用系统的其他部分不用为了支持代理对象而 </li></ul></ul><ul><ul><li>改变。 </li></ul></ul><ul><ul><li>8. 织入 : 将切面应用到目标对象从而创建一个新代理对象的过程。织入发生在目标 </li></ul></ul><ul><ul><li>对象生命周期的多个点上: </li></ul></ul><ul><ul><li>编译期:切面在目标对象编译时织入 . 这需要一个特殊的编译器 . </li></ul></ul><ul><ul><li>类装载期:切面在目标对象被载入 JVM 时织入 . 这需要一个特殊的类载入器 . </li></ul></ul><ul><ul><li>运行期:切面在应用系统运行时织入 . </li></ul></ul>通知 程序执行 切 入 连接点
  61. 61. 三、创建切面 <ul><li>3.1 AOP 介绍 </li></ul><ul><ul><li>3.1.2 SpringAOP 实现 </li></ul></ul><ul><ul><li>用 java 编写 spring 通知 </li></ul></ul><ul><ul><li>在 spring 中所有的通知都是以 java 类的形式编写的。切入点定义在配置文件中编写,所以切面代码和配置文件对我们来说都很熟悉。 </li></ul></ul><ul><ul><li>对于其他框架 (Aspectj) ,需要特定的语法编写,如果使用的话,还需学习新的语言。 </li></ul></ul>
  62. 62. 三、创建切面 <ul><li>3.1 AOP 介绍 </li></ul><ul><ul><li>3.1.2 SpringAOP 实现 ( 续 ) </li></ul></ul><ul><ul><li>spring 的运行时通知对象 </li></ul></ul><ul><ul><li>spring 在运行期创建代理 , 不需要特殊的编译器 . </li></ul></ul><ul><ul><li>spring 有两种代理方式: </li></ul></ul><ul><ul><li>1. 若目标对象实现了若干接口, spring 使用 JDK 的 </li></ul></ul><ul><ul><li>java.lang.reflect.Proxy 类代理。该类让 spring 动态产生 </li></ul></ul><ul><ul><li>一个新类,它实现了所需的接口,织入了通知,并且代理对 </li></ul></ul><ul><ul><li>目标对象的所有请求。 </li></ul></ul><ul><ul><li>2. 若目标对象没有实现任何接口, spring 使用 </li></ul></ul><ul><ul><li>CGLIB 库生成目标对象的子类。使用该方式时需要注意 : </li></ul></ul><ul><ul><li>1. 对接口创建代理优于对类创建代理,因为会产生更加松耦合的系统。 </li></ul></ul><ul><ul><li>对类代理是让遗留系统或无法实现接口的第三方类库同样可以得到通知, </li></ul></ul><ul><ul><li>这种方式应该是备用方案。 </li></ul></ul><ul><ul><li>2. 标记为 final 的方法不能够被通知。 spring 是为目标类产生子类。任何需要 </li></ul></ul><ul><ul><li>被通知的方法都被复写,将通知织入。 final 方法是不允许重写的。 </li></ul></ul><ul><ul><li>spring 实现了 aop 联盟接口。 </li></ul></ul><ul><ul><li>spring 只支持方法连接点:不提供属性接入点, spring 的观点是属性拦截破坏了 </li></ul></ul><ul><ul><li>封装。面向对象的概念是对象自己处理工作,其他对象只能通过方法调用的得到的 </li></ul></ul><ul><ul><li>结果。 </li></ul></ul>
  63. 63. 三、创建切面 <ul><li>3.2 创建通知 </li></ul>当目标方法抛出异常时调用 在目标方法调用后调用 在目标方法调用前调用 拦截对目标方法调用 描述 Org.springframework.aop. ThrowsAdvice Org.springframework.aop. AfterReturningAdvice Org.springframework.aop. BeforeAdvice Org.springframework.aop. MethodInterceptor 接口 Around Before After Throws 通知类型
  64. 64. 三、创建切面 <ul><li>3.2 创建通知 </li></ul><ul><ul><li>3.2.1 前置通知 </li></ul></ul><ul><ul><li>public interface MethodBeforeAdvice{ </li></ul></ul><ul><ul><li>void before(Method m,Object[] </li></ul></ul><ul><ul><li>os ,Object target){ </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>该接口提供了获得目标方法、参数和目标对象的机会。不能够改变运行时参数,即不能替换参数对象和目标对象。 </li></ul></ul><ul><ul><li>注意在方法结束后不返回任何值东西。原因是该接口返回后,目标方法将会被调用,应该返回目标对象的返回值。该接口唯一能 </li></ul></ul><ul><ul><li>阻止目标方法被调用的途径是抛出异常或 (System.exit()) 。 </li></ul></ul>
  65. 65. 三、创建切面 <ul><li>3.2 创建通知 </li></ul><ul><ul><li>3.2.1 前置通知 ( 续 ) </li></ul></ul>public class WelcomeAdvice implements MethodBeforeAdvice{ public void before(Method m,Object[] os,Object target){ Customer c = (Customer)arg[0]; System.out.println(c.getName()); } } --------------------------------------------- // 创建目标代理对象 <bean id=“kwikEMartTarget” class=“…ApuKwikEMart” /> <bean id=“welcomeAdvice” class=“…WelcomeAdvice” /> <bean id=“kwikEMart” class=“……ProxyFactoryBean”> <property name=“proxyInterfaces”><value>……KwikEMart</value></property> <property name=“interceptorNames”> <list><value>welcomeAdvice</value></list> </property> <property name=“target”><ref bean=“kwikEMartTarget” /></property> </bean>
  66. 66. 三、创建切面 <ul><li>3.2 创建通知 </li></ul><ul><ul><li>3.2.1 前置通知 ( 续 ) </li></ul></ul><ul><ul><li>ProxyFactoryBean 是一个在 BeanFactory 中显式创建代理对象的中心类,可以给它一个 </li></ul></ul><ul><ul><li>要实现的接口、一个要代理的目标对象、一个 </li></ul></ul><ul><ul><li>要织入的通知,并且他将创建一个崭新的代理 </li></ul></ul><ul><ul><li>对象。 </li></ul></ul>
  67. 67. 三、创建切面 <ul><li>3.2 创建通知 </li></ul><ul><ul><li>3.2.2 后置通知 </li></ul></ul><ul><ul><li>同前置通知类似。 </li></ul></ul><ul><ul><li>public interface AfterReturningAdvice{ </li></ul></ul><ul><ul><li>public void afterReturning(Object returnValue,Method </li></ul></ul><ul><ul><li>m,Object[] os,Object target); </li></ul></ul><ul><ul><li>} </li></ul></ul>
  68. 68. 三、创建切面 <ul><li>3.2 创建通知 </li></ul><ul><ul><li>3.2.3 环绕通知 </li></ul></ul><ul><ul><li>public interface MethodInterceptor extends Interceptor{ </li></ul></ul><ul><ul><li>Object invoke(MethodInvocation invocation); </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>该接口同前两种通知有两个重要区别 :1. 该通知能够控制目标方法 </li></ul></ul><ul><ul><li>是否真的被调用。通过 invocation.proceed() 方法来调用。 </li></ul></ul><ul><ul><li>2. 该通知可以控制返回的对象。可以返回一个与 proceed() 方法返回对象完全不同的对象。但要谨慎使用。 </li></ul></ul>
  69. 69. 三、创建切面 <ul><li>3.2 创建通知 </li></ul><ul><ul><li>3.2.4 异常通知 </li></ul></ul><ul><ul><li>public interface ThrowsAdvice{ </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>该接口为标识性接口,没有任何方法,但实现该接口的类必须要有如下形 </li></ul></ul><ul><ul><li>式的方法: </li></ul></ul><ul><ul><li>void afterThrowing(Throwable throwable); </li></ul></ul><ul><ul><li>void afterThrowing(Method m,Object[] os,Object </li></ul></ul><ul><ul><li>target,Throwable throwable); </li></ul></ul><ul><ul><li>第一个方法只接受一个参数:需要抛出的异常。 </li></ul></ul><ul><ul><li>第二个方法接受异常、被调用的方法、参数以及目标对象。 </li></ul></ul>
  70. 70. 三、创建切面 <ul><li>3.2 创建通知 </li></ul><ul><ul><li>3.2.5 引入通知 </li></ul></ul><ul><ul><li>以前定义的通知类型是在目标对象的方法被调用 </li></ul></ul><ul><ul><li>的周围织入。引入通知给目标对象添加新的方法 </li></ul></ul><ul><ul><li>和属性。 </li></ul></ul>
  71. 71. 三、创建切面 <ul><li>3.3 定义切入点 </li></ul><ul><li>如果不能表达在应用系统的什么地方应用 </li></ul><ul><li>通知的话,通知将毫无用处,这就是切入点的用处。切入点决定了一个特定的类的特定方法是否满足一定的规则。若符合,通知就应用到该方法上。 </li></ul>
  72. 72. 三、创建切面 <ul><li>3.3 定义切入点 </li></ul><ul><ul><li>3.3.1 在 spring 中定义切入点 </li></ul></ul><ul><ul><li>public interface Pointcut{ </li></ul></ul><ul><ul><li>ClassFilter getClassFilter(); </li></ul></ul><ul><ul><li>MethodMatcher getMethodMatcher(); </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>切入点根据方法和类决定何处织入通知。 ClassFilter 接口决定了一个类 </li></ul></ul><ul><ul><li>是否符合通知的要求: </li></ul></ul><ul><ul><li>public interface ClassFilter{ </li></ul></ul><ul><ul><li>boolean matches(Class clazz); </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>实现该接口的类决定了以参数传递进来的类是否应该被通知。实现该接 </li></ul></ul><ul><ul><li>口的类一般根据类名决定,但不一定必须如此。该接口总是包含了一个 </li></ul></ul>
  73. 73. 三、创建切面 <ul><li>3.3 定义切入点 </li></ul><ul><ul><li>3.3.1 在 spring 中定义切入点 ( 续 ) </li></ul></ul><ul><ul><li>简单的 ClassFilter 接口实现 -ClassFilter.TRUTE 。它是规范的适合任何 </li></ul></ul><ul><ul><li>类的 ClassFilter 实例,适合用于只根据方法决定时候符合要求的切入。 </li></ul></ul><ul><ul><li>ClassFilter 通过类过滤切面, MethodMatcher 通过方法过滤切面。 </li></ul></ul><ul><ul><li>public interface MethodMatcher{ </li></ul></ul><ul><ul><li>boolean matches(Method m,Class targetClass); 1. </li></ul></ul><ul><ul><li>boolean isRuntime(); 2. </li></ul></ul><ul><ul><li>boolean matchers(Method m,Class target,Object[] args); 3. </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>1. 根据目标类和方法决定方法是否被通知。因为可以静态的判断,所以 </li></ul></ul><ul><ul><li>可以在 AOP 代理被创建时候调用一次这个方法。该方法的结果最终决 </li></ul></ul><ul><ul><li>定了通知是否被织入。 </li></ul></ul>
  74. 74. 三、创建切面 <ul><li>3.3 定义切入点 </li></ul><ul><ul><li>3.3.1 在 spring 中定义切入点 ( 续 ) </li></ul></ul><ul><ul><li>如果 1. 返回 true, 2. 被调用来决定 MethodMatcher 的类型。有两种类型:静态和动态。静态切入点的意思是通知总是被执行。如果一个切入点是静态的,该方法返回 false. 动态切入点根据运行时方法的参数值决定通知是否需要执行。如果切入点是动态的,该方法返回 true 。和 1. 方法类似,该方法也是在代理创建时运行一次。 </li></ul></ul>
  75. 75. 三、创建切面 <ul><li>3.3 定义切入点 </li></ul><ul><ul><li>3.3.1 在 spring 中定义切入点 ( 续 ) </li></ul></ul><ul><ul><li>如果切入点是静态的, 3. 永远不会执行,对于动态切入点,需要根据运行时的参数决定方法是否被通知,所以会增加系统的负担,尽量使用静态切入点。 </li></ul></ul>
  76. 76. 三、创建切面 <ul><li>3.3 定义切入点 </li></ul><ul><ul><li>3.3.2 理解 Advisor </li></ul></ul><ul><ul><li>大多数切面是由定义切面行为的通知和定义切面在什么地方执行的切入点组合而成的。 spring 认识到了这一点,提供了 Advisor 类。他把通知和切入点组合到一个对象中。更确切地说 PointcutAdvisor 提供了这些功能。 </li></ul></ul><ul><ul><li>public interface PointcutAdvisor{ </li></ul></ul><ul><ul><li>Pointcut getPointcut(); </li></ul></ul><ul><ul><li>Advice getAdvice(); </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>这样方便在一个地方定义切入点和通知。 </li></ul></ul>
  77. 77. 三、创建切面 <ul><li>3.3 定义切入点 </li></ul><ul><ul><li>3.3.3 使用 spring 的静态切入点 </li></ul></ul><ul><ul><li>静态切入点只在代理创建的时候执行一次而不 </li></ul></ul><ul><ul><li>是在运行期间每次方法调用都执行,所以性能 </li></ul></ul><ul><ul><li>比动态切入点好,是首选的切入点方式。 spring 为创建静态切入点提供了方便的父类。 </li></ul></ul><ul><ul><li>staticMethodMatherPointcut. </li></ul></ul>
  78. 78. 三、创建切面 <ul><li>3.3 定义切入点 </li></ul><ul><ul><li>3.3.3 使用 spring 的静态切入点 </li></ul></ul><ul><ul><li>NameMatchMethodPointcut: </li></ul></ul><ul><ul><li>public void setMappedName(String); </li></ul></ul><ul><ul><li>public void setMappedNames(String); </li></ul></ul><ul><ul><li>当调用的方法名字与给出的映射名字匹配时, </li></ul></ul><ul><ul><li>切点才匹配。也可在名字的开始和结束使用通配符。 </li></ul></ul>
  79. 79. 三、创建切面 <ul><li>3.3 定义切入点 </li></ul><ul><ul><li>3.3.3 使用 spring 的静态切入点 ( 续 ) </li></ul></ul><bean id=“xxxTarget” class=“xxxServiceImpl”/> <bean id=“xxxAdvice” class=“”/> <bean id=“xxxAdvisor” class=“…NameMatchMethodPointcutAdvisor”> <property name=“mappedName”> <value>order*<value> </property> <property name=“advice”> <ref bean=“xxxAdvice” /> </property> </bean> <bean id=“xxxService” class=“…ProxyFactoryBean”> <property name=“proxyInterfaces”> <value>……xxxService</value> </property> <property name=“interceptorNames”> <list><value>xxxAdvisor</value></list> </property> <property name=“target”><ref bean=“xxxTarget” /></property> </bean>
  80. 80. 三、创建切面 <ul><li>3.3 定义切入点 </li></ul><ul><ul><li>3.3.3 使用 spring 的静态切入点 ( 续 ) </li></ul></ul><ul><ul><li>正则表达式切入点 </li></ul></ul><ul><ul><li>RegexpMethodPointcut </li></ul></ul>setFoo setFoo setFoo setFooBar 不匹配 bar.setFoo setFoo setFooB, setFooBar setFooBar setFooB setFooB 匹配 .setFoo. setFoo.* setFoo.+ setFoo. 示例 匹配任何正则表达式符号 匹配前一个字符 0 次或多次 匹配前一个字符一次或多次 匹配任何单个字符 描述 . + * 符号
  81. 81. 三、创建切面 <ul><li>3.3 定义切入点 </li></ul><ul><ul><li>3.3.3 使用 spring 的静态切入点 ( 续 ) </li></ul></ul><bean id=“xxxTarget” class=“xxxServiceImpl”/> <bean id=“xxxAdvice” class=“”/> <bean id=“xxxAdvisor” class=“…RegExpPointcutAdvisor”> <property name=“pattern”> <value>.*get.+bar.+<value> </property> <property name=“advice”> <ref bean=“xxxAdvice” /> </property> </bean> <bean id=“xxxService” class=“…ProxyFactoryBean”> <property name=“proxyInterfaces”> <value>……xxxService</value> </property> <property name=“interceptorNames”> <list><value>xxxAdvisor</value></list> </property> <property name=“target”><ref bean=“xxxTarget” /></property> </bean> 该规则表示任何类的以 get 开头,后面至少有一个字符,然后跟着 by, 后面至少有一个字符的方法
  82. 82. 三、创建切面 <ul><li>3.3 定义切入点 </li></ul><ul><ul><li>3.3.4 使用动态切入点 </li></ul></ul><ul><ul><li>动态切入点需要判断运行时属性的值。 spring </li></ul></ul><ul><ul><li>提供了一种内置的动态切入点 :ControlFlowPointcut. 该切入点根据线程 </li></ul></ul><ul><ul><li>调用堆栈的信息来匹配方法。也就是说只有当 </li></ul></ul><ul><ul><li>指定的方法或类能在当前线程执行堆栈中找到时,返回 true. </li></ul></ul>
  83. 83. 三、创建切面 <ul><li>3.3 定义切入点 </li></ul><ul><ul><li>3.3.4 使用动态切入点 ( 续 ) </li></ul></ul><bean id=“xxxTarget” class=“xxxServiceImpl”/> <bean id=“xxxAdvice” class=“”/> <bean id=“xxxPointcut” class=“…ControlFlowPointcut”> <contructor-arg”> <value>javax.servlet.http.HttpServlet</value> </contructor-arg> </bean> <bean id=“xxxAdvisor” class=“…DefaultPointcutAdvisor”> <property name=“advice”> <ref bean=“xxxAdvice” /> </property> <property name=“pointcut”> <ref bean=“xxxPointcut”> </property> </bean> <bean id=“xxxService” class=“……ProxyFactoryBean”> …… </bean>
  84. 84. 三、创建切面 <ul><li>3.4 创建引入 </li></ul><ul><li>引入是为需要方法的类添加属性和方法。可以用一个已存在的类让他实现另外的接口,维持另外的状态 ( 这也叫混合 ) 。引入 </li></ul><ul><li>能够动态的建立复合对象,提供了多态继承的好处。 </li></ul>
  85. 85. 三、创建切面 <ul><li>3.4 创建引入 </li></ul>class AuditableIntroductionInterceptor extends DelegatingIntroductionInceptor{ private Date lastModifiedDate ; public Date getLastModifiedDate(){} public void setLastModifiedDate(Date date){} } 如果你的混合体要改变任何目标对象方法的行为的话,你就需要实现 invoke() 方法。 public Object invoke(MethodInvcation mi) throws Throwable{ String name = mi.getMethod().getName(); if(name.indexof(“set”) == 0){ throw new IllegalModificationException(); } return super.invoke(mi); } 我们复写了 invoke 方法,所以他拦截所有的方法的调用。注意我们调用的 super.invoke() 而 不是 mi.proceed(). 这样做是因为父类 DelegatingIntroductionInterceptorkeyijiang 可以 决定哪个类负责处理这个方法调用。这一点需要注意,当需要复写 invoke 方法时,你需要调用 super.invoke 方法来确保调用正确的方法。
  86. 86. 三、创建切面 <bean id=“xxxTarget” class=“xxxServiceImpl” /> <bean id=“myDelegatingIntroductionInterceptor” class=“xxxMyDelegatingIntr..” /> <bean id=“xxxAdvisor” class=“DefaultIntroductionAdvisor” singleton=“false”> <constructor-arg> <ref bean=“myDelegatingIntroductionInterceptro” /> </constructor-arg> </bean> <bean id=“xxx” class=“…ProxyFatoryBean”> <property name=“proxyTargetClass”> <value>true</value> </property> <property name=“singleton”> <value>false</value> </property> <property name=“proxyInterfaces”> <value>xxxService</value> </property> <property name=“interceptorNames”> <list> <value>xxxAdvisor</value> </list> </property> <property name=“target”><ref bean=“xxxTarget”/></property> </bean>
  87. 87. 三、创建切面 <ul><li>3.4 创建引入 </li></ul><ul><ul><li>谨慎使用引入通知 </li></ul></ul><ul><ul><li>spring 通知是在运行时织入,而不象其他的 AOP 框架将通知织入到类的字节码当中。这意味着,从其他方法创建或得道的对象不会被引入通知。例如直接实例化或返序列化的对象。 </li></ul></ul>
  88. 88. 三、创建切面 <ul><li>3.5 使用 proxyFactoryBean </li></ul>目标对象是否需要得到当前代理。 是用的 ProxyFactoryBean 实现。 spring 有两种实现: jdk 动态代理和 CGLIB 。通常不需要使用该属性。 是否返回同一个实例。 需要应用到目标对象上的通知的名字。可以是拦截器、 Advisor 或其他通知类型的名字。这个属性必须按照 beanFactory 中的使用顺序设置。 代理应该实现的接口列表 代理的目标对象 使用 target proxyInterfaces interceptorNames singleton exposeProxy aopProxyFactory 属性
  89. 89. 三、创建切面 <ul><li>3.5 使用 proxyFactoryBean( 续 ) </li></ul>是否对创建的代理进行优化 ( 只适用于 CGLIB) 。这会带来性能的提升,不过要慎用。 optimize 是否代理目标对象,而不是接口。只能在使用 CGLIB ( 即部署了 cglib 包 ) 时使用。 ProxyTargetClass 一旦工厂被创建,是否可以修改代理的通知。当为 true 时,运行时就不能修改 ProxyFactoryBean 了。通常不需要使用这个属性。 frozen 使用 属性
  90. 90. 三、创建切面 <ul><li>3.6 自动代理 </li></ul><ul><ul><li>有许多类需要通知时,显式的创建每个代理就会 </li></ul></ul><ul><ul><li>显得很笨拙。 spring 有一个自动代理机制,它 </li></ul></ul><ul><ul><li>可以让容器为我们产生代理。 </li></ul></ul><ul><ul><li>BeanNameAutoProxyCreator </li></ul></ul><ul><ul><li>DefaultAdvisorAutoProxyCreator </li></ul></ul>
  91. 91. 三、创建切面 <ul><li>3.6 自动代理 </li></ul><ul><ul><li>3.6.1 BeanNameAutoProxyCreator </li></ul></ul><ul><ul><li>该类为匹配一系列名字的 Bean 自动创建代理。这种名字匹配和前面讲到的 NameMethodMatherPointcut 类似,他也允许在名字的两端进行通配符。通常为符合相同命名规则的 bean 应用一个或一组切面。 </li></ul></ul>
  92. 92. 三、创建切面 <ul><li>3.6 自动代理 </li></ul><ul><ul><li>3.6.1 BeanNameAutoProxyCreator( 续 ) </li></ul></ul>public class PerformancethreshodInterceptor implements MethodInterceptor{ private final long thresholdInMillis ; … public Object invoke(MehtodInvocation mi){ long t = System.currentTimeMillis(); Object o = mi.proceed(); t = System.currenttimeMillis – t ; if(t > thresholdInMillis ){ …… . } return o ; } }
  93. 93. 三、创建切面 <ul><li>3.6 自动代理 </li></ul><ul><ul><li>3.6.1 BeanNameAutoProxyCreator( 续 ) </li></ul></ul><bean id=“performanceThresholdInterceptor” class=“…” > <constructor-arg> <value>5000</value> </constructor-arg> </bean> <bean id=“performanceThresholdProxyCreator” class=“…BeanNmaeAutoProxyCreator”> <property name=“beanNames”> <list> <values>*Service</values> </list> </property> <property name=“interceptorNames”> <value>performanceThresholdInterceptor<value> </property> </bean>
  94. 94. 三、创建切面 <ul><li>3.6 自动代理 </li></ul><ul><ul><li>3.6.2 DefaultAdvisorAutoProxyCreator( 续 ) </li></ul></ul><ul><ul><li>该类实现了 BeanPostProcessor 接口。当应用上下文 </li></ul></ul><ul><ul><li>读入所有的 Bean 的配置信息后,该类将扫描上下文, </li></ul></ul><ul><ul><li>寻找所有的 Advisor 。他将这些 Advisor 应用到所有符 </li></ul></ul><ul><ul><li>合切入点的 Bean 中。很重要的一点是这个代理创建器 </li></ul></ul><ul><ul><li>只能与 Advisor 配合使用。该类需要 Advisor 来知道哪些 Bean 需要通知。 </li></ul></ul>
  95. 95. 三、创建切面 <ul><li>3.6 自动代理 </li></ul><ul><ul><li>3.6.2 DefaultAdvisorAutoProxyCreator( 续 ) </li></ul></ul><bean id=“xxxInterceptor” class=“” /> <bean id=“advisor” class=“…RegexpMethodPointcutAdvisor”> <property name=“advice”> <ref beam=“xxxInterceptor” /> <property> <property name=“pattern”> <value>.+Service..+</value> </property> </bean> <bean id=“autoProxyCreator” class=“…DefaultAdvisorAutoProxyCreatro” />
  96. 96. 四、征服数据库 <ul><li>4.1 学习 dao 的理念 </li></ul><ul><li>DAO: 数据访问对象 (data access object) </li></ul>服务对象 数据访问接口 数据访问实现
  97. 97. 四、征服数据库 <ul><li>4.1 学习 dao 的理念 </li></ul><ul><ul><li>从 jdni 的数据源 </li></ul></ul><ul><ul><li><bean id=“dataSource” </li></ul></ul><ul><ul><li>class=“org…JndiObjectFactoryBean”> </li></ul></ul><ul><ul><li><property name=“jndiName”> </li></ul></ul><ul><ul><li><value>java:comp/env/jdbc/myDatasource</value> </li></ul></ul><ul><ul><li><property> </li></ul></ul><ul><ul><li></bean> </li></ul></ul><ul><ul><li>创建一个 DataSource 连接池 </li></ul></ul><ul><ul><li><bean id=“dataSource” </li></ul></ul><ul><ul><li>class=“org.apache.commons.dbcp.BasicDataSource”> </li></ul></ul><ul><ul><li><property name=“driver”> </li></ul></ul><ul><ul><li><value>${database.driver}</value> </li></ul></ul><ul><ul><li></property> </li></ul></ul><ul><ul><li><property name=“url”> </li></ul></ul><ul><ul><li>…… </li></ul></ul><ul><ul><li></bean> </li></ul></ul>
  98. 98. 四、征服数据库 <ul><li>4.2 在 Spring 中使用 JDBC </li></ul><ul><ul><li>4.2.2 使用 Jdbc Template(JdbcTemplate 模板类 ) </li></ul></ul><ul><ul><li>JdbcTemplate t = new JdbcTemplate(datasource); </li></ul></ul><ul><ul><li>class StudentDao implements StudentDao{ </li></ul></ul><ul><ul><li>JdbcTemplate jdbcTemplate; </li></ul></ul><ul><ul><li>…… </li></ul></ul><ul><ul><li>} </li></ul></ul>
  99. 99. 四、征服数据库 <ul><li>4.2 在 Spring 中使用 JDBC </li></ul><ul><li>将 jdbc template 连接到 daobean 中 </li></ul><ul><li><bean id=“jdbcTemplate” </li></ul><ul><li>class=“org……JdbcTemplate”/> </li></ul><ul><li><property name=“datasource”> </li></ul><ul><li><ref bean=“datasource”> </li></ul><ul><li></property> </li></ul><ul><li><bean id=“studentdao” </li></ul><ul><li>class=“StudentDao”> </li></ul><ul><li><property name=“jdbctemplate”> </li></ul><ul><li><ref bean=“jdbctemplate”> </li></ul><ul><li></property> </li></ul><ul><li></bean> </li></ul><ul><li>…… </li></ul>
  100. 100. 四、征服数据库 <ul><li>在 Spring 中使用 JDBC </li></ul><ul><li>将 jdbc template 连接到 daobean 中 </li></ul><ul><li>ProparedStatmentCreator </li></ul><ul><li>template.update(sql,params,types); </li></ul><ul><li>使用 BatchPreparedStatmentCreator 插入多个对象 </li></ul><ul><li>template.batchUpdate(sql,setter); </li></ul>
  101. 101. 四、征服数据库 <ul><li>在 Spring 中使用 JDBC </li></ul><ul><ul><li>读数据 : </li></ul></ul><ul><ul><li>使用 RowCallBackHandler 执行查询 </li></ul></ul><ul><ul><li>Temp.query(sql,params,new RowCallBackHandler()); </li></ul></ul><ul><ul><li>使用 RowMapper 查询 </li></ul></ul><ul><ul><li>Template.query(sql,params,new RowMapperResultReader(new PersonRowMapper())); </li></ul></ul>
  102. 102. 四、征服数据库 <ul><li>在 Spring 中使用 JDBC </li></ul><ul><li>调用存储过程 </li></ul><ul><li>CallableStatmentCallback cb=new </li></ul><ul><li>CallableStatementCallback(){ </li></ul><ul><li>public Object doInCallableStatement(CallableStatement cs){ </li></ul><ul><li>cs.execute(); </li></ul><ul><li>return null; </li></ul><ul><li>} </li></ul><ul><li>}; </li></ul><ul><li>jdbctemplate.execute(“{ARCHIVE_STUDENTS}”,cb); </li></ul>
  103. 103. 四、征服数据库 <ul><li>4.4 介绍 orm 框架支持 </li></ul><ul><ul><li>4.4.2 管理 hibernate 资源 </li></ul></ul><bean id=“dataSource” class=“org.springframework.jndi.JndiObjectFactoryBean”> <property name=“jndiName”> <value>java:comp/env/jdbc/trainingDatasource</value> </property> </bean> <bean id=“sessionFactory” class=“org.springframework.orm.hibernate .LocalSessionFactoryBean”/> <property name=“dataSource”> <ref bean=“dataSoure”/> </property> </bean>
  104. 104. 四、征服数据库 <ul><li>4.4 介绍 orm 框架支持 </li></ul><ul><ul><li>4.4.2 管理 hibernate 资源 ( 续 ) </li></ul></ul><ul><li>将 hibernate.properties 里的信息设定在 LocalSessionFactoryBean 中 </li></ul><ul><li><bean id=“sessioinFactory” </li></ul><ul><li>class=“ort.springframework.orm.hibernate.LocalsessionFactoryBean”> </li></ul><ul><li><property name=“hibernateProperties”> </li></ul><ul><li><props> </li></ul><ul><li><prop key=“hibernate.dialect”>net.sf.hibernate.dialect.MySQLDialect<prop> </li></ul><ul><li>…… </li></ul><ul><li></props> </li></ul><ul><li></property> </li></ul><ul><li><property name=“mappingResources”> </li></ul><ul><li><list> </li></ul><ul><li><value>student.hbm.xml</value> </li></ul><ul><li><value>Course.hbm.xml</value> </li></ul><ul><li></list> </li></ul><ul><li></property> </li></ul><ul><li></bean> </li></ul>
  105. 105. 四、征服数据库 <ul><li>4.4 介绍 orm 框架支持 </li></ul><ul><li>将 hibernate.properties 里的信息设定在 LocalSessionFactoryBean 中 </li></ul><ul><li><bean id=“sessioinFactory” </li></ul><ul><li>class=“ort.springframework.orm.hibernate.LocalsessionFactoryBean”> </li></ul><ul><li><property name=“hibernateProperties”> </li></ul><ul><li><props> </li></ul><ul><li><prop key=“hibernate.dialect”>net.sf.hibernate.dialect.MySQLDialect<prop> </li></ul><ul><li>…… </li></ul><ul><li></props> </li></ul><ul><li></property> </li></ul><ul><li><property name=“ mappingDirectoryLocations ”> </li></ul><ul><li><list> </li></ul><ul><li><value>classpath:/com/spring/persistence</value> </li></ul><ul><li>…… </li></ul><ul><li><value>Course.hbm.xml</value> </li></ul><ul><li></list> </li></ul><ul><li></property> </li></ul><ul><li><bean id=“hibernateTemplate” </li></ul><ul><li>class=“org.springframework.orm.hibernate.HIbernateTemplate”> </li></ul><ul><li><property name=“sessionFactory”> </li></ul><ul><li><ref bean=“sessionFactory” /> </li></ul><ul><li></property> </li></ul><ul><li></bean> </li></ul>
  106. 106. 四、征服数据库 <ul><li>4.4 介绍 orm 框架支持 ( 续 ) </li></ul><ul><li><bean id=“studentdao” class=“StudentDaoImpl”> </li></ul><ul><li><property name=“hibernateTemplate”> </li></ul><ul><li><ref bean=“hibernateTemplate”/> </li></ul><ul><li></property> </li></ul><ul><li></bean> </li></ul><ul><li><bean id=“coursedao” class=“CourseDaoImpl”> </li></ul><ul><li><property name=“hibernateTemplate”> </li></ul><ul><li><ref bean=“hibernateTemplate”/> </li></ul><ul><li></property> </li></ul><ul><li></bean> </li></ul>
  107. 107. 四、征服数据库 <ul><li>4.4 介绍 orm 框架支持 </li></ul><ul><ul><li>用 hibernate 模板访问 hibernate </li></ul></ul><ul><ul><li>public Student getStudent(final Integer id){ </li></ul></ul><ul><ul><li>return (Student)hibernateTemplate.execute( </li></ul></ul><ul><ul><li>new HibernateCallback(){ </li></ul></ul><ul><ul><li>public Object doInHibernate(Session session) throws </li></ul></ul><ul><ul><li>HibernateException{ </li></ul></ul><ul><ul><li>return session.load(Student.class,id); </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>} ); </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>hibernateTemplate 可以隐含创建 hibernateCallback 类。 </li></ul></ul><ul><ul><li>public Student getStudent(Integer id){ </li></ul></ul><ul><ul><li>return (Student)hibernateTemplate.load(Student.class,id); </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>public void updateStudent(Student s){ </li></ul></ul><ul><ul><li>hibernateTemplate.update(s); </li></ul></ul><ul><ul><li>} </li></ul></ul>
  108. 108. 四、征服数据库 <ul><li>4.4 介绍 orm 框架支持 </li></ul><ul><ul><li>HibernateDaoSupport 子类 </li></ul></ul><ul><ul><li>class StudentDaoHibernate extends HibernateDaoSupport{ </li></ul></ul><ul><ul><li>void updateStudent(Student s){ </li></ul></ul><ul><ul><li>getHibernateTemplate().update(s); </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>…… </li></ul></ul><ul><ul><li>} </li></ul></ul>
  109. 109. 四、征服数据库 <ul><li>spring 和 JDO( 略 ) </li></ul><ul><ul><li>配置 JDO </li></ul></ul><ul><ul><li>用 JdoTemplate 访问数据库 </li></ul></ul>
  110. 110. 征服数据库 <ul><li>spring 和 iBatis( 略 ) </li></ul>
  111. 111. 五、事务管理 <ul><li>5.1 理解事务 </li></ul><ul><ul><li>5.1.1 仅用四个词解释事务 </li></ul></ul><ul><li>atomic: 要么都发生,要么都不发生。 </li></ul><ul><li>consistent: 数据应该不被破坏。 </li></ul><ul><li>Isolate: 用户间操作不相混淆 </li></ul><ul><li>Durable: 永久保存 </li></ul>
  112. 112. 五、事务管理 <ul><li>5.1 理解事务 </li></ul><ul><ul><li>5.1.3 介绍 spring 的事务管理器 </li></ul></ul><ul><ul><li>spring 没有直接管理事务,而是将管理事务的责任委 </li></ul></ul><ul><ul><li>托给某个特定平台的事务实现。 </li></ul></ul>当 apache 的 ojb 用作持久化机制时,用它来管理事务。 使用一个 JTA 实现来管理事务。在一个事务跨越多个数据源时使用 当持久化机制是 Jdo 时,用它来管理事务。 当持久化机制是 hibernate 时,用它来管理事务 在单一的 JDBC Datasource 中的管理事务 目标 org.springframework.jdbc.datasource.DataSourceTransactionManager org.springframework.orm.hibernate.HibernateTransactionManager org.springframework.jdo.JdoTransactionManager org.springframework.transaction.jta.JtaTransactionManager org.springframework.orm.ojb.PersistenceBrokerTransactionManager 事务管理器实现
  113. 113. 五、事务管理 <ul><li>5.1 理解事务 </li></ul><ul><ul><li>5.1.3 spring 的事务管理器 ( 续 ) </li></ul></ul>platformTransactionmanager datasource Transaction manager hibernate Transaction manager jdo Transaction manager persistence Broker Transaction manager JTA Transaction manager jdbc hibernate JDO OJB JTA 每种事务管理器都充当了对特定平台的事务实现的代理。这样我们就只需要和 spring 中的事务打交道, 而不用关系实际上事务实现是什么样的。要使用一个事务管理器,你得再上下文中声明他。 程序控制事务管理能让你在代码中精确定义事务边界,声明式事务帮助把一个操作从事务规则中分离出 来。
  114. 114. 五、事务管理 <ul><li>5.1 理解事务 </li></ul><ul><ul><li>5.13 spring 的事务管理器 </li></ul></ul><ul><ul><li>JDBC 事务: </li></ul></ul><bean id=“transaction” class=“…DataSourceTransactoinManager”> <property name=“dataSource”> <ref bean=“dataSource”> </property> </bean> 在幕后, DataSourceTransactionManager 通过调用从 DataSource 得到的 Connection 对象来管理事务。 如: conn.rollback() conn.commit()
  115. 115. 五、事务管理 <ul><li>5.1 理解事务 </li></ul><ul><ul><li>5.13 spring 的事务管理器 </li></ul></ul>Hibernate 事务: <bean id=“transactionManager” class=“…HibernateTransactionManager”> <property name=“sessionFactory”> <ref bean=“sessionFactory” /> </property> </bean> 其中 sessionFactory 属性必须和一个 Hibernate 的 SessionFactory 绑定 HibernateTransactionManager 把事务管理委托给一个从 Hibernate session 中取得的 net….Transaction 对象。当一个事务成功完成时, HibernateTransactionManager 将调用 Transaction 对象的 commit() 方法。类似的,当一个事务失败时, Transaction 对象的 rollback() 方 法将被调用。
  116. 116. 五、事务管理 <ul><li>5.1 理解事务 </li></ul><ul><ul><li>5.1.3 spring 的事务管理器 </li></ul></ul><ul><ul><li>JDO 事务 ( 略 ) </li></ul></ul><ul><ul><li>OJB 事务 ( 略 ) </li></ul></ul>
  117. 117. 五、事务管理 <ul><li>5.2 在 spring 中编写事务 </li></ul>public void enrollStudentIncourse(){ transactionTemplate.execute(){ new TransactionCallback(){ public Object doInTransaction(TransactionStatus ts){ try{ //do stuffr } catch(Exception e){ ts.setRollbackOnly(); } return null; } } }; }
  118. 118. 五、事务管理 <ul><li>5.2 在 spring 中编写事务 ( 续 ) </li></ul>注入事务模板: <bean id=“transactionTemplate” class=“…TransactionTemplate”> <property name=“transactionManager”> <ref bean=“transactionManager” /> </property> </bean> <bean id=“courseService” class=“…CourseServiceImpl” > <property name=“transactionTemplate”> <ref bean=“transactionTemplate” /> </property> </bean>
  119. 119. 五、事务管理 <ul><li>5.2 在 spring 中编写事务 </li></ul><ul><ul><li>在代码中添加事务的一种方法是使用 spring 的 </li></ul></ul><ul><ul><li>TransactionTemplate 类。该类采用了一套回调机制。 </li></ul></ul>public void enrollStudentInCourse(){ transactionTemplate.execute( new TransactionCallback(){ public Object doInTransaction(TransactionStatus ts){ try{ //do stuff } catch(Exception e){ ts.setRollbackOnly(); } return null; } } ); }
  120. 120. 五、事务管理 <ul><li>5.2 在 spring 中编写事务 ( 续 ) </li></ul><bean id=“transactionTemplate” class=“org.springframework.transaction.support.TransactionTemplate”> <property name=“transactionManager”> <ref bean=“transactionManager” /> </property> </bean> <bean id=“courseService” class=“CourseServiceImpl”> <property name=“transactionTemplate”> <ref bean=“transactionTemplate” /> </property> </bean>
  121. 121. 五、事务管理 <ul><li>5.3 声明式事务 </li></ul><ul><ul><li>spring 对声明式的事务管理的支持是通过它的 </li></ul></ul><ul><ul><li>AOP 框架实现的。事务是一个切面,“包裹着” </li></ul></ul><ul><ul><li>方法。要在 spring 应用中使用声明式事务,需要使用 TransactionProxyFactoryBean. 这个代理工厂对象类似于 ProxyFactoryBean 处理事务,只不过它的目的是将方法包装在事务的上下文中。 </li></ul></ul>
  122. 122. 五、事务管理 <ul><li>5.3 声明式事务 ( 续 ) </li></ul><bean id=“courseService” class=“org.springframework.transaction.interceptor.TransactionProxyFactoryBean”> <property name=“proxyInterfaces”> <list> <value>CourseService</value> 代理所实现的接口 </list> </property> <property name=“target”> <ref bean=“courseServiceTarget” /> 被代理的对象 </property> <propety name=“transactionManager”> <ref bean=“transactionManager” /> 事务管理器 </property> <property name=“transactionAttributeSource”> <ref bean=“attributeSource” /> 事务的属性源 </property> </bean>
  123. 123. 五、事务管理 <ul><li>5.3 声明式事务 </li></ul><ul><ul><li>5.3.1 理解事务属性 </li></ul></ul><ul><ul><li>传播行为 : </li></ul></ul>表示该方法不应在事务中运行。如果一个现有的事务正在运行,他将在该方法的运行期间被挂起。如果使用 jta 的事务管理器,需要访问 jtatansactionmanager. 当前的方法不应该运行在一个事务上下文中。如果当前存在一个事务,则会抛出一个异常。 若当前已经存在一个事务,则该方法应当运行在一个嵌套的事务中。被嵌套的事务可以从当前事务中单独的提交或回滚。若当前事务不存在,则看起来就和 PROPAGATION_REQUIRED 没有两样。 该方法必须运行在一个事务中。如果当前事务不存在,将抛出一个异常。 意义 PROPAGATION_MANDATORY PROPAGATION_NESTED PROPAGATION_NEVER PROPAGATION_NOT_SUPPORTED 传播行为
  124. 124. 五、事务管理 <ul><li>5.3 声明式事务 </li></ul><ul><ul><li>5.3.1 理解事务属性 </li></ul></ul><ul><ul><li>传播行为 ( 续 ) </li></ul></ul>传播规则回答了一个问题,就是新的事务是否要被启动或是挂起,或者方法是否要在事务环境中运行。 当前方法不需要事务处理环境,但如果有一个事务已经在运行的话,这个方法也可以在这个事务里运行。 PROPAGATION_SUPPORTS 表示当前方法必须运行在它自己的事务里。他将启动一个新的事务。如果一个现有事务在运行的话,将在这个方法运行期间被挂起。若使用 jtaTransactionManager ,则需要访问 transactionManager 表示当前方法必须运行在一个事务中。若一个现有的事务正在进行中,该方法将会运行在这个事务中。否则的话,就要开一个新的事务。 意义 PROPAGATION_REQUIRES_NEW PROPAGATION_REQUIRED 传播行为
  125. 125. 五、事务管理 <ul><li>5.3 声明式事务 </li></ul><ul><ul><li>5.3.1 理解事务属性 ( 续 ) </li></ul></ul><ul><ul><li>隔离级别 </li></ul></ul><ul><ul><li>脏读 : 一个事务读取了另一个事务改写但还未 </li></ul></ul><ul><ul><li>提交的数据,如果这些数据被回滚,则 </li></ul></ul><ul><ul><li>读到的数据是无效的。 </li></ul></ul><ul><ul><li>不可重复读 : 一个事务执行相同的查询两次或两次以 </li></ul></ul><ul><ul><li>上,但每次查询结果都不同。 </li></ul></ul><ul><ul><li>幻读 : 一个事务读取了几行记录后,另一个事务插入一 </li></ul></ul><ul><ul><li>些记录,幻读就发生了。再后来的查询中,第一 </li></ul></ul><ul><ul><li>个事务就会发现有些原来没有的记录。 </li></ul></ul>
  126. 126. 五、事务管理 <ul><li>5.3 声明式事务 </li></ul><ul><ul><li>5.3.1 理解事务属性 ( 续 ) </li></ul></ul><ul><ul><li>隔离级别 </li></ul></ul>完全服从 ACID 的隔离级别,确保不发生脏、幻、不可重复读。这在所有的隔离级别中是最慢的,它是典型的通过完全锁定在事务中涉及的数据表来完成的。 对相同字段的多次读取是一致的,除非数据被事务本身改变。可防止脏、不可重复读,幻读仍可能发生。 允许在并发事务已经提交后读取。可防止脏读,但幻读和 不可重复读仍可发生。 允许你读取还未提交后数据。可能导致脏、幻、不可重服 使用后端数据库默认的隔离级别 含义 ISOlATION_DEFAULT ISOLATION_READ_UNCOMMITED ISOLATION_READ_COMMITTED ISOLATION_REPEATABLE_READ ISOLATION_SERIALABLE 隔离级别
  127. 127. 五、事务管理 <ul><li>5.3 声明式事务 </li></ul><ul><ul><li>理解事务属性 ( 续 ) </li></ul></ul><ul><ul><li>只读 </li></ul></ul><ul><ul><li>若对数据库只进行读操作,可设置事务只读的属性,使用某些优化措施。数据库会进行优化处理。若使用 hibernate 作为持久化机制,声明一个只读事务会使 hibernate 的 flush 模式设置为 FLUSH_NEVER 。避免不必要的数据同步,将所有更新延迟到事务的结束。 </li></ul></ul>
  128. 128. 五、事务管理 <ul><li>5.3 声明式事务 </li></ul><ul><ul><li>5.3.1 理解事务属性 ( 续 ) </li></ul></ul><ul><ul><li>事务超时 </li></ul></ul><ul><ul><li>若事务在长时间的运行,会不必要的占用数据库资源。设置超时后,会在指定的时间片回滚。将那些具有可能启动新事务的传播行为的方法的事务设置超时才有意义 (PROPAGATION_REQUIRED,PROPAGATION_REQUIRES_NEW,PROPAGATION_NESTED) 。 </li></ul></ul>
  129. 129. 五、事务管理 <ul><li>5.3 声明式事务 </li></ul><ul><ul><li>5.3.2 声明一个简单的事务策略 TransactionProxyFactoryBean 从 TransactoinAttributeSource 获得一个方法的事务属性。 </li></ul></ul>public interface TransactionAttributeSource{ public TransactionAttribute getTransactionAttribute(Method ,tartgetClass); } 总是匹配事务属性源: <bean id=“transactionAttributeSource” class=“org…..MatchAlwaysTransactionAttributeSource”> …… </bean>
  130. 130. 五、事务管理 <ul><li>5.3 声明式事务 </li></ul><ul><ul><li>5.3.2 声明一个简单的事务策略 ( 续 ) </li></ul></ul><ul><ul><li>MatchAlwaysTransactionAttributeSource 可能是最简单的事务属性源的实现。每一次他的 getTransactionAttribute() 方法被调用时,他总是简单的返回相同的 TransactionAttribute ,而不管这个事务中 包装了哪个方法 ( 默认是 PROPAGATION_REQUIRED 和 ISOLATION_DEFAULT). 那就是 MatchAlwaysTransactionAttributeSource 的“永远匹配 (match always)” 部分在起作用。 </li></ul></ul>
  131. 131. 五、事务管理 <ul><li>5.3 声明式事务 </li></ul><ul><ul><li>5.3.2 声明一个简单的事务策略 ( 续 ) </li></ul></ul><ul><ul><li>改变默认的事务属性如果希望改变 MatchAlwaysTransactionAttributeSource 的返回的默认的 TransactionAttribute ,可以在 TransactionAttribute 属性中置入另一个事务属性。如返回一个带 PROPAGATION_REQUIRES_NEW 和 ISOLATION_REPEATED_READ 策略的 TransactionAttribute. </li></ul></ul><bean id=“myTransactionAttribute” class=“org……DefaultTransactionAttribute”> <property name=“propagationBehaviorName”> <value>PROPAGATION_REQUIRES_NEW</value> </property> <property name=“isolationLevelName”> <value>ISOLATION_REPEATABLE_READ</value> </property> </bean>
  132. 132. 五、事务管理 <ul><li>5.3 声明式事务 </li></ul><ul><ul><li>5.3.2 声明一个简单的事务策略 ( 续 ) </li></ul></ul><ul><ul><li>改变默认的事务属性 </li></ul></ul><bean id=“transaction” class=“org…MatchAlwaysTransactionAttributeSource”> <property name=“transactionAttribute”> <ref bean=“myTransactionAttribute” /> </property> </bean> --------------------------------------------------------------------------------- 虽然可以改变事务属性参数,但总是返回相同的事务属性,而不关心参与交易的是哪 个方法。如果对不同的方法应用不同的事务策略时,使用 NameMatchTransactionAttributeSource 类。
  133. 133. 五、事务管理 <ul><li>5.4 通过方法名声明事务 </li></ul><ul><ul><li>5.4.1 使用 NameMatchTransactionAttributeSource. </li></ul></ul><ul><ul><li>该事务属性源可以在方法名的基础上声明事务。如为了在 enrollStudentInCourse() 方法具有的” requires new” 的传播行为。需要替换 transactionAttributeSource 对象的声明。 </li></ul></ul><bean id=“transactionAttributeSource” class=“org……NameMatchTransactionAttributeSource”> <property name=“properties”> <props> <prop key=“enrollStudentIncourse”> PROPAGATION_REQUIRES_NEW </prop> </props> </property> </bean>
  134. 134. 五、事务管理 <ul><li>5.4 通过方法名声明事务 </li></ul><ul><ul><li>5.4.1 使用 NameMatchTransactionAttributeSource. </li></ul></ul><ul><ul><li>该事务属性源的 properties 属性把方法名映射到事务属性描述器上。事务属性描述器有以下几种形式: </li></ul></ul>PROPAGATION,ISOLATION,readonly,-Exception,+Exception 传播行为 隔离级别 ( 可选 ) 是否只读 ( 可选 ) 回滚规则 ( 可选 ) <bean id=“transactionAttributeSource” class=“org……NameMatchTransactionAttributeSource”> <property name=“properties”> <props> <prop key=“enrollStudentIncourse”> PROPAGATION_REQUIRES_NEW,ISOLATION_REPEATABLE_READ </prop> </props> </property> </bean>
  135. 135. 五、事务管理 <ul><li>5.4 通过方法名声明事务 </li></ul><ul><ul><li>5.4.1 使用 NameMatchTransactionAttributeSource( 续 ) </li></ul></ul><ul><ul><li>使用只读事务 </li></ul></ul><bean id=“transactionAttributeSource” class=“org……NameMatchTransactionAttributeSource”> <property name=“properties”> <props> <prop key=“enrollStudentIncourse”> PROPAGATION_REQUIRES_NEW,ISOLATION_REPEATABLE_READ, readOnly </prop> </props> </property> </bean>
  136. 136. 五、事务管理 <ul><li>5.4 通过方法名声明事务 </li></ul><ul><ul><li>5.4.1 使用 NameMatchTransactionAttributeSource( 续 ) </li></ul></ul><ul><ul><li>指定回滚规则 </li></ul></ul><bean id=“transactionAttributeSource” class=“org……NameMatchTransactionAttributeSource”> <property name=“properties”> <props> <prop key=“enrollStudentIncourse”> PROPAGATION_REQUIRES_NEW,ISOLATION_REPEATABLE_READ, -CourseException </prop> </props> </property> </bean> --------------------------------------------------------------------------------------------------- 负号异常抛出时,触发回滚,正号异常抛出时,事务仍可提交。
  137. 137. 五、事务管理 <ul><li>5.4 通过方法名声明事务 </li></ul><ul><ul><li>5.4.1 使用 NameMatchTransactionAttributeSource( 续 ) </li></ul></ul><ul><ul><li>使用通配符匹配 </li></ul></ul><bean id=“transactionAttributeSource” class=“org……NameMatchTransactionAttributeSource”> <property name=“properties”> <props> <prop key=“get*”> PROPAGATION_REQUIRES_NEW,ISOLATION_REPEATABLE_READ, -CourseException </prop> </props> </property> </bean> --------------------------------------------------------------------------------------------------- 负号异常抛出时,触发回滚,正号异常抛出时,事务仍可提交。
  138. 138. 五、事务管理 <ul><li>5.4 通过方法名声明事务 </li></ul><ul><ul><li>5.4.2 名称匹配事务的捷径 </li></ul></ul><ul><ul><li>TransactionProxyFactoryBean 也有一个 TransactionAttibutes 属性。与其把 NameMatchTransactionAttributeSource 对象置入该属性,不如直接把事务属性邦定到该属性上。如下所示: </li></ul></ul><bean id=“transactionAttributeSource” class=“org……TransactionProxyFactoryBean”> … <property name=“transactionProperties”> <props> <prop key=“enrollStudentInCourses”> PROPAGATION_REQUIRES_NEW,ISOLATION_REPEATABLE_READ, -CourseException </prop> </props> </property> </bean> 将事务属性设置到 transactionProperties 属性中和把 NameMatchTransactionAttributeSource 置入到 transactionAttributeSource 中的功能是一样的。
  139. 139. 五、事务管理 <ul><li>5.5 用元数据声明事务 </li></ul><ul><ul><li>5.5.1 用元数据书写事务属性 </li></ul></ul><bean id=“transactionAttributeSource” class=“org……AttributeTransactionAttributeSource”> <constructor-arg> <ref bean=“attributesImpl” /> </constructor> </bean>
  140. 140. 五、事务管理 <ul><li>5.5 用元数据声明事务 </li></ul><ul><ul><li>5.5.2 用 Commons Attributes 声明事务 </li></ul></ul><ul><ul><li>声明一个属性的实现 </li></ul></ul><ul><ul><li><bean id=“attributeImpl” </li></ul></ul><ul><ul><li>class=“org……CommonsAttributes”> </li></ul></ul><ul><ul><li>… </li></ul></ul><ul><ul><li></bean> </li></ul></ul>
  141. 141. 五、事务管理 <ul><li>5.5 用元数据声明事务 </li></ul><ul><ul><li>5.5.2 用 Commons Attributes 声明事务 ( 续 ) </li></ul></ul><ul><ul><li>给事务方法加标签 </li></ul></ul><ul><ul><li>/** </li></ul></ul><ul><ul><li>*attribute-name(“arg1”,property=“arg2”) </li></ul></ul><ul><ul><li>*/ </li></ul></ul>
  142. 142. 五、事务管理 <ul><li>5.6 修建事务声明 </li></ul><ul><ul><li>5.6.1 从父 TransactionProxyFactoryBean 继承 </li></ul></ul><bean id=“abstractTxDefinition” class=“org……TransactionProxyFactoryBean” lazy=“true”> <property name=“transactionManager”> <ref bean=“transactionManager” /> </property> <property name=“transactionAttributeSource”> <ref bean=“attributeSource” /> </property> </bean> <bean id=“courseService” parent=“abstractTxDefinition”> <property name=“target”> <ref bean=“courseServiceTarget”/> </property> </bean>
  143. 143. 事务管理 <ul><li>修建事务声明 </li></ul><ul><ul><li>自动代理事务 </li></ul></ul><bean id=“autoProxy” class=“org……DefaultAdvisorAutoProxyCreator”> </bean>
  144. 144. 远程调用 <ul><li>spring 远程调用概览 </li></ul>访问 webservices Jax-rpc 访问对 ejb 实现的遗留的 j2ee 系统 考虑网络限制时,访问基于 spring 的服务 考虑网络限制,通过 http 访问基于 java 的服务 不考虑网络限制(防火墙),访问公开基于 java 的服务 使用场景 RMI Hession 或 burlap http invoker Ejb RPC 模式
  145. 145. 远程调用 <ul><li>spring 远程调用概览 </li></ul>服务接口 代理 服务接口 客户端 服务 将远程方法调用序列化和反序列化
  146. 146. 远程调用 <ul><li>spring 远程调用概览 </li></ul>服务接口 服务 bean RemoteExporter 客户端 将远程方法调用序列化和反序列化
  147. 147. 远程调用 <ul><li>与 RMI 一起工作 </li></ul><ul><ul><li>连接 RMI 服务 </li></ul></ul><bean id=“paymentService” class=“org.sf.remoting.rmi.RmiProxyFactoryBean”> <property name=“serviceUrl”> <value>rmi://${paymenthost}/PayService</value> </property> <property name=“serviceInterface”> <value>com…..PaymentService</value> </property> </bean>
  148. 148. 远程调用 <ul><li>与 RMI 一起工作 </li></ul><ul><ul><li>输出 RMI 服务 </li></ul></ul><bean id=“paymentService” class=“org.sf.remoting.rmi.RmiProxyFactoryBean”> <property name=“serviceUrl”> <value>rmi://${paymenthost}/PayService</value> </property> <property name=“serviceInterface”> <value>com…..PaymentService</value> </property> </bean> -------------------------------------------------------------------------------------------------------- <bean id=“org………remoting.rmi.RmiServiceExporter”> <property name=“service”> <ref bean=“paymentService”> </property> <property name=“service”> <ref bean=“paymentService”> </property> <property name=“service”> <ref bean=“paymentService”> </property> </bean>
  149. 149. <bean id=“paymentService” class=“org.sf.remoting.rmi.RmiProxyFactoryBean”> <property name=“serviceUrl”> <value>rmi://${paymenthost}/PayService</value> </property> <property name=“serviceInterface”> <value>com…..PaymentService</value> </property> </bean> ------------------------------------------------------------------------------------ <bean id=“org………remoting.rmi.RmiServiceExporter”> <property name=“service”> <ref bean=“paymentService”> </property> <property name=“serviceName”> <value>Payment</value> </property> <property name=“serviceInterface”> <value>……PaymentService</value> </property> </bean>
  150. 150. 远程调用 <ul><li>使用 http invoker </li></ul><ul><ul><li>通过 http 访问服务 </li></ul></ul><bean id=“paymentService” class=“org……HttpInvokerProxyFactoryBean”> <property name=“serviceUrl”> <value>http://${servername}/${contextpath}/pay.service</value> </property> <property name=“serviceInterface”> <value>com……PaymentService</value> </property> </bean>
  151. 151. 远程调用 <ul><li>使用 http invoker </li></ul><ul><ul><li>把 Bean 作为 HTTP 服务公开 </li></ul></ul><bean id=“httpPaymentService” class=“org……HttpInvokerServiceExporter”> <property name=“service”> <ref bean=“paymentService” /> </property> <property name=“serviceInterface”> <value>com……PaymentService</value> </property> </bean>
  152. 152. 访问企业级服务 <ul><li>发送电子邮件 </li></ul><bean id=“mailSender” class=“…..JavaMailSenderImpl”> <property name=“host”> <value>mail.springinaction.com</value> </property> </bean> host: 邮件服务器主机名。 默认端口 25 。可通过 <proerty name=“port”> 修改 -------------------------------------------------------- 消息模版 <bean id=“mailMessage” class=“…..SimpleMailMessage”> <property name=“to”> <value>dd@dd.com</value> </property> <property name=“from”> <value>dd@dd.com</value> </property> <property name=“subject”> <value>sss</value> </property> </bean>
  153. 153. 访问企业级服务 class XXX extends TimerTask{ public void run(){ …… } } ------------------------------------- 调度定时器任务 <bean id=“schedualTask” class=“org……ScheduleTimerTask”> <property name=“timerTask”> <ref bean=“myTimerTask” /></property> <property name=“period”><86400000</value></property> <property name=“delay”>3600000</property> </bean>
  154. 154. 访问企业级服务 <ul><li>调度任务 </li></ul><ul><ul><li>使用 java Timer </li></ul></ul><ul><ul><li>按任意周期运行。继承 java.util.TimerTask </li></ul></ul>class XXX extends TimerTask{ public void run(){ …… } } ------------------------------------- 调度定时器任务 <bean id=“schedualTask” class=“org……ScheduleTimerTask”> <property name=“timerTask”> <ref bean=“myTimerTask” /></property> <property name=“period”><86400000</value></property> <property name=“delay”>3600000</property> </bean> 启动任务: <bean class=“TimerFactoryBean”> <period 86400000(24 小时 ) <delay 3600000>
  155. 155. 访问企业级服务 <ul><li>调度任务 </li></ul><ul><ul><li>使用 java Timer </li></ul></ul><ul><ul><li>按任意周期运行。继承 java.util.TimerTask( 续 ) </li></ul></ul><ul><ul><li>timerTask: 运行哪个任务。 </li></ul></ul><ul><ul><li>period: 频度。 24 小时运行一次。 </li></ul></ul><ul><ul><li>delay: 首次等待多久后启动。 </li></ul></ul>
  156. 156. 访问企业级服务 <ul><li>调度任务 </li></ul><ul><ul><li>使用 Quartz 调度器 </li></ul></ul><ul><ul><li>可以每隔多少毫秒启动任务,还允许在某个特定的时间运行。 </li></ul></ul><ul><ul><li>1. 创建一个工作 </li></ul></ul><ul><ul><li>class EmailReportJob extends QuartzJobBean{…} </li></ul></ul><ul><ul><li><bean id=“reportJob” class=“……JobDetailBean”> </li></ul></ul><ul><ul><li><propety name=“jobClass”>EmailReportJob </li></ul></ul><ul><ul><li></propety> </li></ul></ul><ul><ul><li><property name=“jobDataAsMap”> </li></ul></ul><ul><ul><li><map></map> </li></ul></ul><ul><ul><li></property> </li></ul></ul>
  157. 157. 访问企业级服务 <ul><li>调度任务 </li></ul><ul><ul><li>使用 Quartz 调度器 </li></ul></ul><ul><ul><li>可以每隔多少毫秒启动任务,还允许在某个特定的时间运行。 </li></ul></ul><ul><ul><li>2. 调度工作 </li></ul></ul><ul><ul><li><bean id=“simple” class=“……SimpleTriggerBean”> </li></ul></ul><ul><ul><li><propety name=“jobDetail”> </li></ul></ul><ul><ul><li><ref bean=“reportJob”/> </li></ul></ul><ul><ul><li></propety> </li></ul></ul><ul><ul><li>startDelay: </li></ul></ul><ul><ul><li>repeartInterval: </li></ul></ul>
  158. 158. 访问企业级服务 <ul><li>调度任务 </li></ul><ul><ul><li>使用 Quartz 调度器 </li></ul></ul><ul><ul><li>可以每隔多少毫秒启动任务,还允许在某个特定的时间运行。 </li></ul></ul><ul><ul><li>3. 调度 cron 工作 </li></ul></ul><ul><ul><li><bean id=“xxx” class=“……CronTriggerBean”> </li></ul></ul><ul><ul><li><propety name=“jobDetail”> </li></ul></ul><ul><ul><li><ref bean=“reportJob”/> </li></ul></ul><ul><ul><li></propety> </li></ul></ul><ul><ul><li>cronExpression:006**? </li></ul></ul>
  159. 159. 访问企业级服务 <ul><li>一个 cron 表达式有 >=6 个有空格分隔的时间元素。从左至右依次为: </li></ul><ul><li>1. 秒 0 - 59 </li></ul><ul><li>2. 分钟 0-59 </li></ul><ul><li>3. 小时 0-23 </li></ul><ul><li>4. 月份中的日期 1-31 </li></ul><ul><li>5. 月份 1-12 </li></ul><ul><li>6. 星期几 1-7 </li></ul><ul><li>7. 年份 1970-2099 </li></ul>
  160. 160. 访问企业级服务 <ul><li>启动工作 </li></ul><ul><li><bean id=“ ” class=“…SchedulerFactoryBean”> </li></ul><ul><li><property name=“triggers”> </li></ul><ul><li><list> </li></ul><ul><li><ref bean=“”/> </li></ul><ul><li></list> </li></ul><ul><li></property> </li></ul><ul><li></bean> </li></ul>
  161. 161. 访问企业级服务 <ul><li>调度任务 </li></ul><ul><ul><li>按调度计划调用方法 </li></ul></ul>class XXX extends TimerTask{ public void run(){ …… } } ------------------------------------- 调度定时器任务 <bean id=“schedualTask” class=“org……ScheduleTimerTask”> <property name=“timerTask”> <ref bean=“myTimerTask” /></property> <property name=“period”><86400000</value></property> <property name=“delay”>3600000</property> </bean>
  162. 162. 第八章 建立 web 层 <ul><li>8.1 开始 springMVC 之旅 </li></ul>DispatcherServlet HandlerMapping Controller ViewResolver View ModelAndView
  163. 163. 第八章 建立 web 层 <ul><li>8.1 开始 springMVC 之旅 </li></ul><ul><ul><li>8.1.2 配置 DispatcherServlet </li></ul></ul><servlet> <servlet-name>action</servlet-name> <servlet-value>……DispatcherServer</servlet-value> </servlet> <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.htm</url-pattern> </servlet-mapping>
  164. 164. 第八章 建立 web 层 <ul><li>8.1 开始 springMVC 之旅 </li></ul><ul><ul><li>8.1.2 配置 DispatcherServlet( 续 ) </li></ul></ul>分解应用上下文 <listener> <listener-class>……ContextLoaderListener</listener-class> </listener> -------------------- 或 <servlet> <servlet-name>context</servlet-name> <servlet-class>……ContextLoaderServlet</servlet-class> <servlet> 不管使用哪种上下文载入器,都需要告诉它配置文件的位置。如果没有指定,将默认需寻找 /WEB-INF/application-Context.xml 。但还可以通过设定 contextConigLocation 参数来指定 多个配置文件。 <context-parm> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/xxx.xml,xxxxx.xml</param-value> </context-parm>
  165. 165. 第八章 建立 web 层 <ul><li>8.1 开始 springMVC 之旅 </li></ul><ul><ul><li>8.1.3 spring MVC 概述 </li></ul></ul><ul><ul><li>1. 编写控制器类 </li></ul></ul><ul><ul><li>2. 在 DispatcherServlet 上下文配置文件配控制器 </li></ul></ul><ul><ul><li>  3. 配置视图解析器 将控制器与 jsp 结合起来 </li></ul></ul><ul><ul><li>4. 编写将主页呈现给用户的 JSP 文件。 </li></ul></ul>
  166. 166. 第八章 建立 web 层 <ul><li>8.1 开始 springMVC 之旅 </li></ul><ul><ul><li>8.1.3 spring MVC 概述 </li></ul></ul><ul><ul><li>创建控制器: </li></ul></ul><ul><ul><li>class HomeController implements Controller{ </li></ul></ul><ul><ul><li>ModelAndView handleRequest(){ </li></ul></ul><ul><ul><li>return new ModelAndView(“index”); </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>配置控制器 </li></ul></ul><ul><ul><li><bean name=“/home” class=“…HomeController”> </li></ul></ul><ul><ul><li><property name=“…”></property> </li></ul></ul><ul><ul><li><property name=“…”></property> </li></ul></ul><ul><ul><li></bean> </li></ul></ul>
  167. 167. 第八章 建立 web 层 <ul><li>8.1 开始 springMVC 之旅 </li></ul><ul><ul><li>8.1.3 spring MVC 概述 ( 续 ) </li></ul></ul><ul><ul><li>声明视图解析器 </li></ul></ul><ul><ul><li><bean id=“viewResolver” </li></ul></ul><ul><ul><li>class=“…InternalResourceViewResolver”> </li></ul></ul><ul><ul><li><property name=“prefix”>/jsps/</property> </li></ul></ul><ul><ul><li><property name=“suffix”>.jsp</property> </li></ul></ul><ul><ul><li></bean> </li></ul></ul><ul><ul><li>ModelAndView 将 prifix + url + suffix 。 </li></ul></ul>
  168. 168. 第八章 建立 web 层 <ul><li>8.1 开始 springMVC 之旅 </li></ul><ul><ul><li>8.1.3 spring MVC 概述 </li></ul></ul><ul><ul><li>合并起来 </li></ul></ul><ul><ul><li>1. 中央控制器接受 /home.htm 样式的请求 </li></ul></ul><ul><ul><li>2. 询问 BeanNameUrlHandlerMapping( 默认 ) ,找到处理器。 </li></ul></ul><ul><ul><li>3. 业务控制器处理 </li></ul></ul><ul><ul><li>4. 返回 ModelAndView 对象。带有逻辑试图名。 </li></ul></ul><ul><ul><li>5. 中央控制器通过试图解析器返回 jsp 文件路径。 </li></ul></ul><ul><ul><li>6. 导向 jsp 页面,展现给用户。 </li></ul></ul>
  169. 169. 第八章 建立 web 层 <ul><li>8.2 将请求映射到控制器 </li></ul><ul><ul><li>1.BeanNameUrlHandlerMapping </li></ul></ul><ul><ul><li>2.SimpleUrlHandlerMapping </li></ul></ul><ul><ul><li>3.CommonsPathMapHandlerMapping </li></ul></ul>
  170. 170. 第八章 建立 web 层 <ul><li>8.2 将请求映射到控制器 </li></ul><ul><ul><li>8.2.1 将 URL 映射到 Bean 名称 </li></ul></ul><bean id=“” class=“ BeanNameUrlHandlerMapping ” /> <bean name=“/listCourses.htm ” class=“….ListCoursesController”> <property name=“”> <ref/> </property> </bean>
  171. 171. 第八章 建立 web 层 <ul><li>8.2 将请求映射到控制器 </li></ul><ul><ul><li>8.2.2 使用 SimpleUrlHandlerMapping </li></ul></ul><bean id=“” class=“ SimpleUrlHandlerMapping ”> <property name=“mappings”> <props> <prop key=“/xxx.service”>xxxController</prop> <prop key=“/xxx.service”>xxxController</prop> … </props> </property> </bean>
  172. 172. 第八章 建立 web 层 <ul><li>8.2 将请求映射到控制器 </li></ul><ul><ul><li>8.2.4 使用多映射处理器 </li></ul></ul><bean id=“” class=“BeanNameUrlHandlerMapping”> <property name=“ order ”><value>1</value></property> </bean> <bean id=“” class=“SimpleUrlHandlerMapping”> <property name=“ order ”><value>2</value></property> </bean>
  173. 173. 第八章 建立 web 层 <ul><li>8.3 用控制器处理请求 </li></ul>复杂多页面的输入

×