1、Spring,轻量级容器框架,Spring简介,Spring是一个控制反转(Ioc)和面向切面编程(AOP)的轻量级的容器,为软件开发提供全方位支持的应用程序框架。控制反转(Inversion of Control,IoC)与依赖注入(Dependency Injection,DI)。由容器来管理对象之间的依赖关系(而不是对象本身来管理),就叫“控制反转”或“依赖注入”.,控制反转,应用本身不负责依赖对象的创建和维护,而是由外部容器来负责。这样控制权就由应用转移到外部容器,控制权的转移就是所谓的反转。,容器是符合某种规范能够提供一系列服务的管理器,开发人员可以利用容器所提供的服务来方便地实现某
2、些特殊的功能。所谓的“重量级”容器是指那些完全遵守J2EE的规范,提供规范中所有的服务。EJB就是典型的例子。“轻量级”容器的也是遵守J2EE的规范,但其中的服务可以自由配置。,Spring最常用的特性,利用Spring来创建对象(JavaBean工厂) 利用Spring构建业务逻辑层 管理依赖关系 适应需求变更 利用Spring创建数据访问对象(DAO) 利用Spring进行事务处理,Spring的安装,下载并解压 http:/www.springframework.org/ 将相应的jar包加入类路径 spring.jar 配置Spring ApplicationContext.xml,I
3、oC/DI,控制反转(Inversion of Control,IoC)与依赖注入(Dependency Injection,DI)。由容器来管理对象之间的依赖关系(而不是对象本身来管理),就叫“控制反转”或“依赖注入” 前面的例子,已清楚阐述IoC/DI出现的原因,以及IoC的基本原理:抽象不依赖于现实,而是现实依赖于抽象。 Spring框架的基本思想就是IoC/DI,Spring就是一个IoC容器 IoC与DI,说的是一回事,但DI这个名词更能表达这种设计模式的思想,Spring架构,依赖注入的类型,构造器注入 通过类的构造方法注入依赖关系 使用 元素 设值方法注入 通过类的setter方
4、法注入依赖关系 使用元素,依赖注入的配置,注入基本数据类型,字符串等。 在或元素中使用 在或元素中加上value属性 注入依赖对象 在或元素中使用 在或元素中加上ref属性 注入null值 如果使用这种形式,Spring是作为空字符串来对待的。可以使用表示null值 内部Bean,在或元素中使用元素再定义一个Bean 内部Bean的scope、id、name属性会被忽略 内部Bean总是prototype(原型)模式 内部Bean不能在包含该内部Bean的Bean之外,依赖注入的配置,注入集合 通过、配置与Java Collection类型对应List、Set、Map、Properties,,
5、Bean的依赖模式1,用ref属性指定依赖。 local模式Bean与被参考引用的Bean在同一个XML文件中,而且被参考 应用的Bean是指定id属性。Spring的XML解析器会在解析时匹配,如果没有匹配的元 素,XML解析器会产生一个错误。,Bean的依赖模式2,bean模式 (可找id,也可找name命名的别名)Bean与被参考引用的Bean可以在不同的XML文件中。ApplicationContext context = new ClassPathXmlApplicationContext (new String“beans1.xml“,“beans2.xml“);bean-dao.
6、xml bean-po.xml bean-service.xml bean-.xml,Bean的依赖模式3,parent模式,表示被参考引用的Bean可以是当前BeanFactory或ApplicationContext的父BeanFactory或ApplicationContext中的Bean。表示继承的父类 如果有很多继承同一个父类的BEAN 那么在配置文件中实例那些BEAN时候可以省略掉父类已经注入的属性 bean定义继承父bean定义,它可以覆盖父bean的一些值,或者它需要的值。,三种实例化Bean的方式,使用类构造器实例化,也就是没有参数的构造函数来建立Bean的实例 使用静态工厂
7、方法实例化public PersonFactory public static Person getPerson()return new Person(); ,使用实例工厂方法实例化,Bean的作用域,Singleton。在Spring中取得的实例被默认为Singleton (单例)Prototype。在每次对该bean请求时创建出一个新的bean对象(原型)其他作用域:request、session、global session,延迟初始化Bean,默认的情况下在容器启动时会初始化Bean。但可以通过指定元素中的lazy-init属性来延迟初始化Bean,这样将会在第一次获取Bean的时候初
8、始化Bean 如果想对所有的Bean都延迟初始化,可以修改元素,Bean的生命周期,Bean的生命周期包括:Bean的定义、Bean的初始化、Bean的使用、Bean的销毁。 Bean的初始化可以通过指定init-method属性来完成或者通过实现org.springframework.beans.factory.InitializingBean接口,实现afterPropertiesSet()方法来完成 Bean的销毁可以通过指定destory-method属性来完成或者通过实现org.springframework.beans.factory.DisposableBean接口,实现dest
9、ory()方法来完成,Bean的自动装配模式,Spring提供了5种自动装配的模式,从而减少一些属性的设置。在元素中设置autowire属性 byName模式,通过Bean的属性名字进行自动装配 byType模式,通过在配置文件查找一个属性类型一样的Bean来进行自动装配 constructor模式,是指根据构造函数的参数尽心自动装配 autodetect模式,通过对Bean检查类的内部来选择是constructor还是byType模式 no模式,不使用自动装配 在企业应用开发过程中,是不主张使用自动装配模式的,Bean的依赖检查,Spring允许Bean在初始化之前强制执行其他Bean的初始
10、化。通过的元素中指定depends-on属性设置通过在元素中指定dependency-check属性来检查Bean的每个属性是否设定完成。 simple模式,对基本类型、字符串、集合进行依赖检查 object模式,对依赖的对象进行依赖检查 all模式,对全部属性进行依赖检查 none模式,不进行依赖检查,基于注解的依赖注入,基于注解(Annotation)的配置有越来越流行的趋势,Spring 2.5 顺应这种趋势,提供了完全基于注释配置 Bean、装配 Bean 的功能,学员可以使用基于注解的 Spring IoC 替换原来基于 XML 的配置。 注解配置相对于 XML 配置具有很多的优势:
11、 它可以充分利用 Java 的反射机制获取类结构信息,这些信息可以有效减少配置的工作。 注释和 Java 代码位于一个文件中,而 XML 配置采用独立的配置文件,大多数配置信息在程序开发完成后都不会调整,如果配置信息和 Java 代码放在一起,有助于增强程序的内聚性。而采用独立的 XML 配置文件,程序员在编写一个功能时,往往需要在程序文件和配置文件中不停切换,这种思维上的不连贯会降低开发效率。 因此在很多情况下,注解配置比 XML 配置更受欢迎,注解配置有进一步流行的趋势。Spring 2.5 的一大增强就是引入了很多注释类,现在我们已经可以使用注解配置完成大部分 XML 配置的功能。,基于
12、注解的依赖注入,spring注解的使用 1、要使用注解来代替xml的配置,要引入如下jar包:%spring_home%libj2eecommon-annotations.jar。而且在applicationContext.xml中要加入的命名空间。 2、引入spring头文件 3、写 开头 注解 Resource注入接口,配置文件修改,基于注解的依赖注入,Resource注解 以前我们使通过配置xml文件方式来表示Bean之间的依赖关系,而现在我们可以通过Resource方式来表示Bean之间的依赖关系,package com.fendou; import javax.annotation.
13、Resource; public class User /通过Resource注解把配置文件中id为user1的bean注入给属性user1Resource(name=“user1“)private User1 user1;Resource(name=“user2“)private User2 user;/省略了getter和setter方法 ,基于注解的依赖注入,PostConstruct 和 PreDestroy注解 Spring 容器中的 Bean 是有生命周期的,Spring 允许在 Bean 在初始化完成后以及 Bean 销毁前执行特定的操作,您既可以通过实现 Initializin
14、gBean/DisposableBean 接口来定制初始化之后/销毁之前的操作方法,也可以通过元素的 init-method/destroy-method 属性指定初始化之后 / 销毁之前调用的操作方法。 关于 Spring 的生命周期已经在前面的章节详细讲解过了,现在我们用 PostConstruct 和PreDestroy这两个注释从新测试spring的生命周期。标注了 PostConstruct 的方法将在类实例化后调用,而标注了 PreDestroy 的方法将在类销毁之前调用。,请看User.java类 package com.fendou; import javax.annotati
15、on.PostConstruct; import javax.annotation.PreDestroy; public class User PostConstructpublic void init()System.out.println(“init“);PreDestroypublic void destory()System.out.println(“destory“); 下面是spring的配置,基于注解的依赖注入,Component注解 虽然我们可以通过Resource 在 Bean 类中使用自动注入功能,但是 Bean 还是在 XML 文件中通过 进行定义,也就是说,在 XML
16、配置文件中定义 Bean,通过Resource 为 Bean 的成员变量、方法入参或构造函数入参提供自动注入的功能。能否也通过注解定义 Bean,从 XML 配置文件中完全移除 Bean 定义的配置呢?答案是肯定的,我们通过 Spring 2.5 提供的 Component 注释就可以达到这个目标了。 下面,我们完全使用注释定义 Bean 并完成 Bean 之间装配: 使用Component注解的User1,仅需要在类定义处,使用 Component 注解就可以将一个类定义了 Spring 容器中的 Bean。 方法: 1、加入spring配置文件中加入 ,用Component方法注入到spr
17、ing中.,Component public class User1 public void print()System.out.println(“我是User1“); ,基于注解的依赖注入,使用Component注解的User2,Component public class User2 public void print()System.out.println(“我是User2“); 使用Component注解的User package com.fendou; import javax.annotation.Resource; import org.springframework.stere
18、otype.Component;Component(“user“) public class User Resource(name=“user1“)private User1 user1;Resource(name=“user2“)private User2 user2;/省略了getter和setter方法 ,基于注解的依赖注入,Scope注解 默认情况下通过 Component 定义的 Bean 都是 singleton 的,如果需要使用其它作用范围的 Bean,可以通过 Scope 注释来达到目标,如以下代码所示:,package com.fendou; import org.sprin
19、gframework.context.annotation.Scope; import org.springframework.stereotype.Component; Component Scope(“prototype“) public class User1 public void print()System. out.println(“我是User1“); ,其他注解 Repository 持久层 Service 业务层 Controller 控制层(Web 层) Component 对那些比较中立的类进行注解。 这 3 个注解和 Component 是等效的 和 Component
20、 相比没有什么新意,但 Spring 将在以后的版本中为它们添加特殊的功能,AOP,面向切面(方面)编程(Aspect Oriented Programming,AOP) 在实际应用中,常常会写一些与具体业务无关的代码,例如日志、权限、异常处理、事务处理等。在编写的过程中,将这样的代码编写到一起,所以处处都有重复的代码。使用AOP,就是将这种和业务逻辑关系不大的代码分离出来,达到重用的目的。 AOP是一种思想,和具体的实现技术无关。任何一种符合AOP思想的技术实现,都可以看作AOP的实现。 Spring的AOP是建立在Java的动态代理机制之上的。,Java的反射机制,什么是动态语言?基本的定
21、义是程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言。在这样的定义与分类下Java不是动态语言,它却有着一个非常突出的动态相关机制:Reflection(反射)Java的反射机制:Java程序可以加载一个运行时才得知名称的class ,获悉其完整构造,并生成其对象实体、或对其fields设值、或调用其methods。这种机制也可以称为introspection(内省)通过java.lang.Class和java.lang.reflect包中的Method、Field、Constructor等实现。,Java的动态代理,普通代理模式:生成一个和类相同接口的代理类,用户通过使用代理类来
22、封装某个实现类。 Java的动态代理:动态代理中的代理类是由java.lang.reflect.Proxy类在运行期时根据接口定义,采用Java反射机制动态生成的。结合java.lang.reflect.InvocationHandler接口,加强现有类的方法实现 。,使用CGLIB代理,AOP的概念,连接点(Join Point),指程序运行中的某个阶段点,如某个方法的调用,异常的抛出等。 切入点(Pointcut)是连接点的集合,它是程序中需要注入Advice的位置的集合,指明Advice要在什么样的条件下才能触发。 通知(Advice),指某个连接点所采用的处理逻辑,前例中输出日志的代码
23、就是一个通知。 Advisor,是切入点和通知之间的配置器。,Spring AOP,首先我们要加入如下jar文件 %spring_home%libaspectjaspectjrt.jar %spring_home%libaspectjaspectjweaver.jarSpring配置文件的头要有如下内容 xmlns:aop=“http:/www.springframework.org/schema/aop“ http:/www.springframework.org/schema/aop http:/www.springframework.org/schema/aop/spring-aop-2
24、.5.xsd一个例子:我们用spring实现事务,事务不是硬编码,而是通过spring aop完成,Spring AOP,BookFacade.java代码如下:,package com.fendou; public class BookFacadeImpl implements BookFacadepublic void addBook() System.out.println(“增加图书实际的方法“); ,BookFacadeImpl .java代码如下:,package com.fendou; public interface BookFacade public void addBook
25、(); ,Spring AOP,现在我们定义一个普通的类,里面有个方法用来开启事务,代码如下 :,package com.fendou; public class Transaction public void beginTransaction()System.out.println(“开启事务“); ,Spring配置文件如下,expression=“execution(* com.fendou.BookFacade.*()“ /,Spring AOP,expression=“execution(* com.fendou.BookFacade.*()“ /,Spring配置文件如下,Spri
26、ng AOP,对一些切入点的说明 任意公共方法: execution(public * *() 任意一个名字以set开始的方法: execution(* set*() AccountService接口定义的任意方法: execution(* com.xyz.service.AccountService.*() 在service包中定义的任意方法: execution(* com.xyz.service.*.*() 在service包或其子包中定义的任意方法: execution(* com.xyz.service*.*(),Spring AOP,对于通知的一些说明 Before 前置通知 Af
27、terReturning 后置通知 AfterThrowing 异常通知:在方法抛出异常后执行 After 最终通知:不论一个方法是如何结束的,最终通知都运行 Around 环绕通知(做权限使用)通知的第一个参数必须是ProceedingJoinPoint类型。在通知体内调用它的proceed()方法会导致后台连接点方法的执行,基于AspectJ的AOP,AspectJ是AOP的一种实现,spring集成了它 还是刚才的例子BookFacade .java和BookFacadeImpl.java的代码不变 Transaction.java代码有改动如下:,/通过注解定义切面 Aspect pu
28、blic class Transaction /定义切入点及其表达式Pointcut(“execution(* com.fendou.BookFacade.*()“)public void pointCutXxx();/定义通知类型Before(“pointCutXxx()“)public void beginTransaction()System.out.println(“开启事务“); ,Spring与Hibernate的集成,加入hibernate相关内容 Hibernate的包 Hiberanate.cfg.xml 实体类与*.hbm.xml文件的建立 加入spring相关内容 引入s
29、pring的包 引入spring的配置文件application.xml,Spring与Hibernate的集成,让spring管理hibernate的sessionFactory,classpath:hibernate.cfg.xml,配置事务管理 大多数的应用程序,事务管理被分配到业务逻辑方法上,即每个业务逻辑方法是一个事务 在Spring中,所有的业务逻辑对象,均是普通的POJO Spring最强大的功能在于,它可以在普通的POJO上面实现声明式的事务管理(它使用AOP来完成这样的任务) 步骤如下: 定义一个事务管理器 配置事务的传播特性,Spring与Hibernate的集成,定义一个
30、事务管理器,Spring与Hibernate的集成,配置事务的传播特性,Spring与Hibernate的集成,Spring的事务级别,Spring提供7种事务级别 REQUIRED,如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。 SUPPORTS,支持当前事务,如果当前没有事务,就以非事务方式执行。 MANDATORY,使用当前的事务,如果当前没有事务,就抛出异常。 REQUIRES_NEW,新建事务,如果当前存在事务,把当前事务挂起。 NOT_SUPPORTED,以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 PROPAGATIO
31、N_NEVER,以非事务方式执行,如果当前存在事务,则抛出异常。 PROPAGATION_NESTED,如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。,创建可以支持Hibernate的DAO对象,HibernateDaoSupport 这是Spring提供的集成Hibernate的基类,所有用Hibernate实现的DAO,均需要继承它 从这个类中,可以获取Hibernate的各种核心接口,如Session、SessionFactory等 这个类的两个重要方法getSession()和getSessionFactory()
32、HibernateTemplate HibernateTemplate是Spring封装的Hibernate操作接口,类似于Session接口 可以调用HibernateDaoSupport提供的getHibernateTemplate()方法获取HibernateTemplate对象,Template模式:在父类定义一个操作中算法的骨架或操作顺 序,而将一些步骤的具体实现延迟到子类中。,DAO的配置,Dao的配置示例 必须注入sessionFactory或dataSource的定义,配置Service,Service配置示例,Spring与struts的集成,加入struts相关内容 str
33、uts的包 struts-config.xml 加入spring相关内容 引入spring的包 引入spring的配置文件application.xml,Spring与struts的集成,让系统启动的时候加载ApplicationContext.xml(在web.xml中增加如下内容),contextConfigLocation/WEB-INF/classes/applicationContext-*.xml,classpath*:applicationContext-*.xmlorg.springframework.web.context.ContextLoaderListener,Spri
34、ng与struts的集成,代理Action:在原来的Action配置中,type属性,直接指向的Action类(即Action类的全路径),现在需要将这些Action类的创建,交给Spring去完成 修改struts中元素的type属性,由原来的Action类,改为:org.springframework.web.struts.DelegatingActionProxy。其他不变 在Spring配置文件中,添加对Action类的定义,如:,注意:元素中的name属性值必须和元素中的path属性值一样。 这是因为DelegatingActionProxy会使用path属性值在Spring上下文中
35、查找真正的Action,Spring与struts的集成,使用DelegatingActionProxy代理Action有一个不足之处就是配置复杂了些。可对这种集成方案做进一步的改进:使用请求委托, Spring提供了DelegatingRequestProcessor作为请求处理器 需要在struts-config.xml中做如下配置 : Struts中元素的type属性,就可以直接指向的Action类。 Spring的配置不变,Struts+Hibernate+Spring,Struts+Hibernate+Spring的集成 注意使用OpenSessionInView模式,这是使用Hib
36、ernate的web项目最需要注意的一个问题,Spring为此提供了专门的解决方案 这是为了避免Hibernate的延迟加载异常而创建的解决方案 它是一个过滤器,能够让Session在请求解释完成之后再关闭(所以才能够避免延迟加载异常) 配置方式是,在web.xml中定义过滤器即可:,hibernateFilterorg.springframework.orm.hibernate3.support.OpenSessionInViewFilterhibernateFilter/*,CharacterEncodingFilter,Spring character encoding filterorg.springframework.web.filter.CharacterEncodingFilterencodingGBKSpring character encoding filter/*,Spring提供了专门的针对Encoding的过滤器 配置方法如下:,