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

More Related Content

DOC
Java面试宝典
DOC
Jsp面试知识
PPT
Javascript之昨是今非
DOC
Java程序员面试之葵花宝典
PDF
Java物件導向
PDF
Jquery指南
PPT
SCJP ch09
DOC
J2ee面试知识
Java面试宝典
Jsp面试知识
Javascript之昨是今非
Java程序员面试之葵花宝典
Java物件導向
Jquery指南
SCJP ch09
J2ee面试知识

What's hot (20)

DOC
Java面试笔试题大汇总
PDF
Spring 2.x 中文
PDF
Java SE 7 技術手冊第六章草稿 - 何謂繼承?
DOC
中心教员J2 Ee面试题
DOC
Java相关基础知识
DOCX
Spring4.x + hibernate4.x_配置详解
PPT
SCJP ch17
PPT
千呼萬喚始出來的Java SE 7
PDF
Jni攻略之八――操作对象的构造方法
PPT
SCJP ch11
PDF
掌星 移动互联网开发笔记-Vol001
PDF
《Python 3.5 技術手冊》第六章草稿
PDF
J2ee经典学习笔记
PPTX
Js的国(转载)
DOC
Java23种设计模式(总结)
PPT
jQuery介绍@disandu.com
PPT
PDF
Ejb工作原理学习笔记
DOC
Spring入门纲要
PDF
Spring 2.0 技術手冊第四章 - Spring AOP
Java面试笔试题大汇总
Spring 2.x 中文
Java SE 7 技術手冊第六章草稿 - 何謂繼承?
中心教员J2 Ee面试题
Java相关基础知识
Spring4.x + hibernate4.x_配置详解
SCJP ch17
千呼萬喚始出來的Java SE 7
Jni攻略之八――操作对象的构造方法
SCJP ch11
掌星 移动互联网开发笔记-Vol001
《Python 3.5 技術手冊》第六章草稿
J2ee经典学习笔记
Js的国(转载)
Java23种设计模式(总结)
jQuery介绍@disandu.com
Ejb工作原理学习笔记
Spring入门纲要
Spring 2.0 技術手冊第四章 - Spring AOP
Ad

Similar to Spring框架 (14)

PPT
Spring课件
PPT
Spring课件
PDF
Spring框架,技术详解及使用指导
PDF
Spring ioc详解
PDF
Spring从入门到精通
PPT
Di&aop
PDF
test
PPT
Exodus2 大局观
PDF
[圣思园][Java SE]Reflection
PPTX
2, object oriented programming
PDF
Spring中的object xml映射详解
PPT
Jvm内存管理基础
DOC
Java华为面试题
PDF
[圣思园][Java SE]Java se lesson 3
Spring课件
Spring课件
Spring框架,技术详解及使用指导
Spring ioc详解
Spring从入门到精通
Di&aop
test
Exodus2 大局观
[圣思园][Java SE]Reflection
2, object oriented programming
Spring中的object xml映射详解
Jvm内存管理基础
Java华为面试题
[圣思园][Java SE]Java se lesson 3
Ad

Spring框架

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