Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著做Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而建立的。(能够增长辅助理解:让代码更加趋于“高内聚、低耦合”)框架的主要优点之一就是其分层架构,分层架构容许使用者选择使用哪个组件,同时为 J2EE 应用程序开发提供集成的框架。Spring使用基本的JavaBean来完成之前只可能由EJB完成的事情。然而,Spring的用途不只限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用均可以从Spring中受益。Spring的核心是控制反转(IoC)和面向切面(AOP)。简单来讲,Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。java
Spring以前是引用EJB的,简单对EJB了解一下:mysql
小结:a.EJB实现原理: 就是把原来放到客户端实现的代码放到服务器端,并依靠RMI进行通讯。web
b.RMI实现原理 :就是经过Java对象可序列化机制实现分布计算。spring
c.服务器集群: 就是经过RMI的通讯,链接不一样功能模块的服务器,以实现一个完整的功能。sql
EJB组件:能够理解为:把你编写的软件中那些须要执行制定的任务的类,不放到客户端软件上了,而是给他打成包放到一个服务器上了express
EJB 就是将那些"类"放到一个服务器上,用C/S 形式的软件客户端对服务器上的"类"进行调用。编程
理解RMI 以前,须要理解两个名词:
对象的序列化
分布式计算与RPC数组
对象的序列化概念:对象的序列化过程就是将对象状态转换成字节流和从字节流恢复对象。相对于将对象转换为0与1的字节流汇编语言;缓存
RPC是 “”Remote Procedure Call“的缩写,也就是远程过程调用;简单理解就是调用远程计算机上的一个函数;”安全
两者结合就是RMI
RMI中文名称是远程方法调用,它就是利用Java 对象序列化的机制实现分布式计算,实现远程类对象的实例化以及调用的方法。说的更清楚些,就是利用对象序列化来实现远程调用,也就是上面两个概念的结合体,利用这个方法来调用远程的类的时候,就不须要编写Socket 程序了,也不须要把对象进行序列化操做,直接调用就好了很是方便。
优势:这种机制给分布计算的系统设计、编程都带来了极大的方便。只要按照RMI 规则设计程序,能够没必要再过问在RMI 之下的网络细节了。也就是说,能够将相似Java 哈西表这样的复杂类型做为一个参数进行传递。
缺点 :若是是较为简单的方法调用,其执行效率也许会比本地执行慢不少,即便和远程Socket机制的简单数据返回的应用相比,也会慢一些,缘由是,其在网络间须要传递的信息不只仅包含该函数的返回值信息,还会包含该对象序列化后的字节内容。
EJB 是以RMI 为基础的
EJB 所谓的"服务群集"的概念。就是将原来在一个计算机上运算的几个类,分别放到其余计算机上去运行,以便分担运行这几个类所须要占用的CPU 和内存资源。同时,也能够将不一样的软件功能模块放到不一样的服务器上,当须要修改某些功能的时候直接修改这些服务器上的类就好了,修改之后全部客户端的软件都被修改了。
方便解耦,简化开发 (高内聚低耦合)
Spring就是一个大工厂(容器),能够将全部对象建立和依赖关系维护,交给Spring管理
spring工厂是用于生成bean
AOP编程的支持
Spring提供面向切面编程,能够方便的实现对程序进行权限拦截、运行监控等功能
声明式事务的支持
只须要经过配置就能够完成对事务的管理,而无需手动编程
方便程序的测试
Spring对Junit4支持,能够经过注解方便的测试Spring程序
方便集成各类优秀框架
Spring不排斥各类优秀的开源框架,其内部提供了对各类优秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持
下降JavaEE API的使用难度
Spring 对JavaEE开发中很是难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大下降
为何要用Spring?像上面说的,高内聚低耦合;本身的理解是经过IOC模式能够完全解决这种耦合,它把耦合统一放入到xml中,经过一个容器在别的类须要的时候把这个依赖关系造成;即把须要的借口实现注入到须要它的类中,是对“依赖注入”的一种理解。还能够这样去理解,(我的理解)把IOC模式相似看作工厂模式的升级版,当作一个大工厂;即:大工厂要生产的对象都是在XML文件中给出定义,而后利用java的反射编程,再根据XML中给出的类名生成相应的对象:提升灵活性、可维护性;
优势:对象生成放入XML中,须要实现的子类变得很简单;
缺点:对象生成是使用反射编程,在效率上有些损耗;
缺乏IDE重构操做,若是在Eclipse或者其它的开发工具里面对类更名字,则须要手动改XML文件;
其中:IOC最大改变不是代码上,而是思想上,“主从换位”,使得程序的整个体系变得灵活;也能够理解为:IOC的实现必须依赖抽象,而不是依赖实现;对象不写死;
Spring控制反转是解决对象建立问题(对象建立交给别人);依赖注入是对象关系的处理(经过set方法依赖注入,设置了value值)
一、 Spring的体系结构(借鉴图片)
二、 导入jar包
4 + 1 : 4个核心(beans、core、context、expression) + 1个依赖(commons-loggins…jar)必需要引入的5个!若是缺乏,会报错:找不到bean对象;
(具体的运用参考例子代码)
三、依赖注入装配Bean 基于注解
这是从容器中获取Bean的方式之一;注解一个类,使用@注解去取代 xml配置文件。
@Component("id") 取代 <bean id="" class="">
在web开发中,@Component注解提供3种(@功能是同样的)
@Repository :dao层
@Service: service层
@Controller: web层
用set方法注入,能够用:@Value(" 引用值"),里面的引用值能够按照 类型、名称 去注入;
4.生命周期(我的以为容易忽略的点)
初始化:@PostConstruct 销毁:@PreDestroy
5.做注解使用前提
要添加命名空间,让spring扫描含有注解类;相对于组件扫描,扫描含有注解的类
<!-- 组件扫描,扫描含有注解的类 -->
<context:component-scan basepackage="包名">
</context:component-scan>
一、什么是Aop?
AOP是OOP(面向对象编程)的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP能够对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度下降,提升程序的可重用性,同时提升了开发的效率。
AOP采起横向抽取机制,取代了传统纵向继承体系重复性代码
经典应用:事务管理、性能监视、安全检查、缓存 、日志等
Spring AOP使用纯Java实现,不须要专门的编译过程和类加载器,在运行期经过代理方式向目标类织入加强代码
AspectJ是一个基于Java语言的AOP框架,Spring2.0开始,Spring AOP引入对Aspect的支持,AspectJ扩展了Java语言,提供了一个专门的编译器,在编译时提供横向代码的织入;
2、AOP实现原理
aop底层将采用代理机制进行实现。
接口 + 实现类 :spring采用 jdk 的动态代理Proxy。
实现类:spring 采用 cglib字节码加强。
3 AOP术语【掌握】
1.target:目标类,须要被代理的类。例如:UserService
2.Joinpoint(链接点):所谓链接点是指那些可能被拦截到的方法。例如:全部的方法
3.PointCut 切入点:已经被加强的链接点。例如:addUser()
4.advice 通知/加强,加强代码。例如:after、before
5. Weaving(织入):是指把加强advice应用到目标对象target来建立新的代理对象proxy的过程.
6.proxy 代理类
7. Aspect(切面): 是切入点pointcut和通知advice的结合
一个线是一个特殊的面。 一个切入点和一个通知,组成成一个特殊的面。
(具体的理解看例子代码)
一、概述:
Spring框架,能够解决对象建立以及对象之间依赖关系的一种框架。且能够和其余框架一块儿使用;Spring与Struts, Spring与hibernate(起到整合(粘合)做用的一个框架)
Spring提供了一站式解决方案:
1) Spring Core spring的核心功能: IOC容器, 解决对象建立及依赖关系
2) Spring Web Spring对web模块的支持。
- 能够与struts整合,让struts的action建立交给spring
- spring mvc模式
3) Spring DAO Spring 对jdbc操做的支持 【JdbcTemplate模板工具类】
4) Spring ORM spring对orm的支持:
既能够与hibernate整合,【session】
也可使用spring的对hibernate操做的封装
5)Spring AOP 切面编程
6)SpringEE spring 对javaEE其余模块的支持
二、核心配置文件: applicationContext.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" 6 xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 7 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd 8 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd 9 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> 10 <!--此处添加其它标签--> 11 </beans>
三、获取IOC容器对象的方法以下:(核心代码)
从IOC容器中获取对象有两种方法:@注解 和 <bean> 标签
1 public class TestApp { 2 //通常使用第二种方法,第一中方法了解一下; 3 // 1. 经过工厂类获得IOC容器建立的对象 4 @Test 5 public void testIOC(){ 6 // 原先把拿到另一个类的对象,通常的方法是:User user = new User(); 7 8 // 如今,把对象的建立交给spring的IOC容器 9 Resource resource = new ClassPathResource("applicationContext.xml"); 10 // 而后,建立容器对象(Bean的工厂),能够理解为: IOC容器 = 工厂类 + applicationContext.xml 11 BeanFactory factory = new XmlBeanFactory(resource); 12 // 获得容器建立的对象,下面以获取User类中的对象为例子; 13 User user = (User) factory.getBean("user"); 14 // 再user去调用方法,此处省略 15 16 } 17 18 //2. (方便)直接获得IOC容器对象 19 @Test 20 public void test2(){ 21 // 获得IOC容器对象 22 ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); 23 // 从容器中获取bean,也是获取User类中对象的例子 24 User user = (User) ac.getBean("user"); 25 // 再user去调用方法,此处省略 26 } 27 }
四、bean对象建立的细节(代码中解释,具体结合下面的 5 、 spring IOC 容器去理解)
1 /** 2 * 1) 对象建立: 单例/多例 3 * scope="singleton", 默认值, 即 默认是单例 【service/dao/工具类】 4 * scope="prototype", 多例; 【Action对象】 5 * 6 * 2) 何时建立? 7 * scope="prototype" 在用到对象的时候,才建立对象。 8 * scope="singleton" 在启动(容器初始化以前), 就已经建立了bean,且整个应用只有一个。 9 * 3)是否延迟建立 10 * lazy-init="false" 默认为false, 不延迟建立,即在启动时候就建立对象 11 * lazy-init="true" 延迟初始化, 在用到对象的时候才建立对象 12 * (只对单例有效) 13 * 4) 建立对象以后,初始化/销毁 14 * init-method="xx" 【对应对象的xx方法,在对象建立爱以后执行 】 15 * destroy-method="xx" 【在调用容器对象的xx方法时候执行,(容器用实现类)】 16 */ 17 @Test 18 public void testIOC2(){ 19 // 获得IOC容器对象 【用实现类,由于要调用销毁的方法】 20 ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); 21 //容器建立,从容器中获取bean;同样以User类为例子; 22 23 User user1 = (User) ac.getBean("user"); 24 User user2 = (User) ac.getBean("user"); 25 26 System.out.println(user1); 27 System.out.println(user2); 28 29 // 销毁容器对象 30 ac.destroy(); 31 }
五、SpringIOC容器
SpringIOC容器是spring核心内容,它的做用主要解决对象的建立和处理对象的依赖关系
建立对象, 有几种方式:
1) 调用无参数构造器
2) 带参数构造器
3) 工厂建立对象
工厂类,静态方法建立对象
工厂类,非静态方法建立对象
理解以下:(工厂的实例方法简单来讲就是调用的思想)
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:p="http://www.springframework.org/schema/p" 5 xmlns:context="http://www.springframework.org/schema/context" 6 xsi:schemaLocation=" 7 http://www.springframework.org/schema/beans 8 http://www.springframework.org/schema/beans/spring-beans.xsd 9 http://www.springframework.org/schema/context 10 http://www.springframework.org/schema/context/spring-context.xsd"> 11 12 <!--对象建立的方法以下:(结合上面的获取IOC容器中对象的代码一块儿看,以User类对象被获取为例) --> 13 14 <!-- 1. 默认无参数构造器 15 <bean id="user1" class="包名.User"></bean> 16 --> 17 18 <!-- 2. 带参数构造器 --> 19 <!-- index能够来控制value输出的顺序 --> 20 <bean id="user2" class="包名.User"> 21 <constructor-arg index="0" type="int" value="100"></constructor-arg> 22 <constructor-arg index="1" type="java.lang.String" value="Jack"></constructor-arg> 23 </bean> 24 25 <!-- 建立字符串,值是"Jack",让其它bean区调用 --> 26 <bean id="str" class="java.lang.String"> 27 <constructor-arg value="Jack"></constructor-arg> 28 </bean> 29 <bean id="user3" class="包名.User"> 30 <constructor-arg index="0" type="int" value="100"></constructor-arg> 31 <constructor-arg index="1" type="java.lang.String" ref="str"></constructor-arg> 32 </bean> 33 34 35 <!-- 3. 工厂类建立对象 --> 36 <!-- # 3.1 工厂类,实例方法(用工厂去调用方法) --> 37 <!-- 先建立工厂 --> 38 <bean id="factory" class="包名.类名"></bean> 39 <!-- 在建立user对象,用factory方的实例方法 --> 40 <bean id="user4" factory-bean="factory" factory-method="实例方法名"></bean> 41 42 43 <!-- # 3.2 工厂类: 静态方法 --> 44 <!-- 45 class 引用工厂对象 46 factory-method 必定是工厂里面的“静态方法” 47 --> 48 <bean id="user" class="包名.类名" factory-method="静态方法名"></bean>
5.1 对象依赖关系
Spring中,如何给对象的属性赋值? 【DI, 依赖注入】
a、 经过构造函数
b、 经过set方法给属性注入值
c、 p名称空间
d、自动装配(了解)
e、 注解
(经常使用)Set方法注入值
1 <!-- 2 构造函数 3 <bean id="xx" class="包名.类名"> 4 <constructor-arg value="xx"></constructor-arg> 5 </bean> 6 --> 7 <!-- 8 set方法注入值 9 <bean id="xx" class="包名.类名"> 10 <property name="xx" value="xx"></property> 11 </bean> 12 --> 13 <!--对象的注入: name是对象 ref去引用,实例化对象 --> 14 <!-- dao 插入 --> 15 <bean id="xxdao" class="包名. UserDao"></bean> 16 17 <!-- service 插入 --> 18 <bean id="xxService" class="包名.UserService"> 19 <property name="userDao" ref="xxDao"></property> 20 </bean> 21 22 <!-- action 插入 --> 23 <bean id="xxAction" class="包名.UserAction"> 24 <property name="userService" ref="xxService"></property> 25 </bean>
或者另一种方式去注入对象:内部bean方法
1 <bean id="xx" class="包名.类名"> 2 <property name="xxService"> 3 <bean class="包名.类名"> 4 <property name="xxDao"> 5 <bean class="包名.类名"></bean> 6 </property> 7 </bean> 8 </property> 9 </bean>
p 名称空间注入属性值
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:p="http://www.springframework.org/schema/p" 5 xmlns:context="http://www.springframework.org/schema/context" 6 xsi:schemaLocation=" 7 http://www.springframework.org/schema/beans 8 http://www.springframework.org/schema/beans/spring-beans.xsd 9 http://www.springframework.org/schema/context 10 http://www.springframework.org/schema/context/spring-context.xsd"> 11 12 13 <!-- 14 给对象属性注入值:p 名称空间(方式) 15 (spring3.0以上版本才支持) 16 --> 17 <bean id="xx" class="包名.类名"></bean> 18 19 <bean id="xx2" class="包名.类名" p:name-ref="xx"></bean> 20 21 <bean id="xx3" class="包名.类名" p:name-ref="xx2"></bean> 22 23 24 <!-- 传统的注入: 25 <bean id="xx" class="包名.类名" > 26 <property name="name" value="xxx"></property> 27 </bean> 28 --> 29 <!-- p名称空间优化后 --> 30 <bean id="xx" class="包名.类名" p:name="xx"></bean> 31 32 </beans>
自动装配(通常不使用)
根据名称自动装配:autowire="byName"
- 自动去IOC容器中找与属性名同名的引用的对象,并自动注入
也能够定义到全局, 这样就不用每一个bean节点都去写autowire=”byName”
根据类型自动装配:autowire="byType"
必须确保改类型在IOC容器中只有一个对象;不然报错。
总结:
Spring提供的自动装配主要是为了简化配置; 可是不利于后期的维护。(通常不推荐使用)
<!-- 自动装配 --> <bean id="xxDao" class="包名.类名"></bean> <bean id="xxService" class="包名.类名" autowire="byName"></bean> <!-- 根据“名称”自动装配: userAction注入的属性,会去Ioc容器中自动查找与属性同名的对象 --> <bean id="xxAction" class="包名.类名" autowire="byName"></bean>
1 <!--定义全局,就不用每一个bean节点写上 autowire="byName"--> 2 <?xml version="1.0" encoding="UTF-8"?> 3 <beans xmlns="http://www.springframework.org/schema/beans" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xmlns:p="http://www.springframework.org/schema/p" 6 xmlns:context="http://www.springframework.org/schema/context" 7 xsi:schemaLocation=" 8 http://www.springframework.org/schema/beans 9 http://www.springframework.org/schema/beans/spring-beans.xsd 10 http://www.springframework.org/schema/context 11 http://www.springframework.org/schema/context/spring-context.xsd" default-autowire="byName"> 12 <!--根据名称自动装配(全局)--> 13 <!-- 自动装配 --> 14 <bean id="xx" class="包名.类名"></bean> 15 <bean id="xx2" class="包名.类名"></bean> 16 <bean id="xx3" class="包名.类名"></bean> 17 </beans>
1 <!--必须确保改类型在IOC容器中只有一个对象;不然报错--> 2 <?xml version="1.0" encoding="UTF-8"?> 3 <beans xmlns="http://www.springframework.org/schema/beans" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xmlns:p="http://www.springframework.org/schema/p" 6 xmlns:context="http://www.springframework.org/schema/context" 7 xsi:schemaLocation=" 8 http://www.springframework.org/schema/beans 9 http://www.springframework.org/schema/beans/spring-beans.xsd 10 http://www.springframework.org/schema/context 11 http://www.springframework.org/schema/context/spring-context.xsd" default-autowire="byType"> 12 <!-- 自动装配 --> 13 14 <!-- 若是根据类型自动装配: 必须确保IOC容器中只有一个该类型的对象 --> 15 <bean id="xx" class="包名.类名"></bean> 16 17 18 <!-- 报错: 由于上面已经有一个该类型的对象,且使用了根据类型自动装配 19 <bean id="xx" class="包名.类名" autowire="byType"></bean> 20 --> 21 </beans>
注:相对于id不一样,有相同的class;
六、注解(从IOC容器中获取对象的另一种方式:@注解)(推荐使用,方便些,简化容器的配置)
使用注解步骤:
a、先引入context名称空间
xmlns:context="http://www.springframework.org/schema/context"
b、开启注解扫描
<context:component-scan base-package="包名"></context:component-scan>
c、使用注解
经过注解的方式,把对象加入Ioc容器。
建立对象以及处理对象依赖关系,相关的注解:
@Component 指定把一个对象加入IOC容器
@Repository : 在持久层使用
@Service 做用同:在业务逻辑层使用
@Controller 做用同:在控制层使用
@Resource 属性注入
总结:
一、使用注解,能够简化配置,且能够把对象加入IOC容器,及处理依赖关系(DI)
二、注解能够和XML配置一块儿使用。
一、Java的代理模式(3种)(Spring中是动态代理对象)
理解:代理对象与目标对象的关系,能够看作代理对象是对目标对象的扩展,并调用出目标对象;关系以下图:
1.1 静态代理
使用静态代理时,代理对象和被代理对象须要实现相同的接口,反过来理解就是须要先定义接口或者父类;代码例子以下:
接口:Dao.java
1 /** 2 * 接口 3 */ 4 public interface Dao { 5 void save(); 6 }
目标对象:sonDao.java
1 /** 2 * 接口实现 3 * 目标对象 4 */ 5 public class sonDao implements Dao { 6 public void save() { 7 System.out.println("----接口的实现----"); 8 } 9 }
代理对象:DaoProxy.java
1 /** 2 * 代理对象,静态代理 3 */ 4 public class DaoProxy implements Dao{ 5 //接收保存目标对象 6 private Dao target; 7 public DaoProxy(Dao target){ 8 this.target=target; 9 } 10 11 public void save() { 12 System.out.println("开始事务..."); 13 target.save();//执行目标对象的方法 14 System.out.println("提交事务..."); 15 } 16 }
测试类:Test.java
1 /** 2 * 测试类 3 */ 4 public class Test { 5 public static void main(String[] args) { 6 //目标对象 7 sonDao target = new sonDao(); 8 9 //代理对象,把目标对象传给代理对象,创建代理关系 10 DaoProxy proxy = new DaoProxy(target); 11 12 proxy.save();//执行的是代理的方法 13 } 14 }
小结:优势就是在不修改目标对象的基础上对目标功能的一些扩展;
缺点是代理对象和目标对象都要写同样的接口,后续可能会形成代理类太多;
2.2 动态代理
也叫JDK代理,接口代理;其中代理对象,不须要实现接口,它的生成,是利用JDK的API,在动态的内存中构建代理对象;
理解:
首先JDK的proxy方式实现的动态代理,目标对象必须有接口;
代理对象:
1 package XX; 2 3 4 import java.lang.reflect.InvocationHandler; 5 import java.lang.reflect.Method; 6 import java.lang.reflect.Proxy; 7 8 public class ProxyTest2 { 9 10 public static void main(String[] args) { 11 12 final Target target = new Target(); 13 14 //动态建立代理对象 15 //JDK的API中存在一个生成动态代理的方法:newProxyInstance 16 公共接口类 proxy = (公共接口类) Proxy.newProxyInstance( 17 //参数:loader 18 target.getClass().getClassLoader(), 19 //目标对象实现全部接口字节码数组:interfaces 20 target.getClass().getInterfaces(), 21 //具体代理接口: InvocationHandler 22 new InvocationHandler() { 23 @Override 24 //被执行几回?------- 看代理对象调用方法几回 25 //代理对象调用接口相应方法 都是调用invoke 26 /* 27 * proxy:是代理对象 28 * method:表明的是目标方法的字节码对象 29 * args:表明是调用目标方法时参数 30 */ 31 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 32 //反射知识点 33 Object invoke = method.invoke(target, args);//目标对象的相应方法 34 //retrun返回的值给代理对象 35 return invoke; 36 } 37 } 38 ); 39 40 //调用invoke---Method:目标对象的method1方法 args:null 返回值null 41 proxy.method1(); 42 //调用invoke---Method:目标对象的method2方法 args:null 返回值method2 43 String method2 = proxy.method2(); 44 //调用invoke-----Method:目标对象的method3方法 args:Object[]{100} 返回值100 45 int method3 = proxy.method3(100); 46 47 System.out.println(method2); 48 System.out.println(method3); 49 50 } 51 52 }
代码还能够加上一个加强方法的过滤器
1 package XX; 2 3 4 import java.io.IOException; 5 import java.io.UnsupportedEncodingException; 6 import java.lang.reflect.InvocationHandler; 7 import java.lang.reflect.Method; 8 import java.lang.reflect.Proxy; 9 10 import javax.servlet.Filter; 11 import javax.servlet.FilterChain; 12 import javax.servlet.FilterConfig; 13 import javax.servlet.ServletException; 14 import javax.servlet.ServletRequest; 15 import javax.servlet.ServletResponse; 16 import javax.servlet.http.HttpServletRequest; 17 import javax.servlet.http.HttpServletRequestWrapper; 18 19 import com.sun.corba.se.impl.protocol.giopmsgheaders.ReplyMessage_1_0; 20 21 public class XX implements Filter{ 22 23 @Override 24 public void init(FilterConfig filterConfig) throws ServletException { 25 // TODO Auto-generated method stub 26 27 } 28 29 @Override 30 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 31 throws IOException, ServletException { 32 HttpServletRequest req = (HttpServletRequest) request; 33 34 HttpServletRequest enhanceRequset = (HttpServletRequest) Proxy.newProxyInstance( 35 req.getClass().getClassLoader(), 36 req.getClass().getInterfaces(), 37 new InvocationHandler() { 38 39 @Override 40 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 41 //对getParameter进行加强 42 if(method.getName().equals("getParameter")){ 43 String invoke = (String) method.invoke(req, args);//乱码 44 invoke = new String(invoke.getBytes("iso8859-1"),"UTF-8");//转码 45 return invoke; 46 } 47 return method.invoke(req, args); 48 } 49 }); 50 chain.doFilter(enhanceRequset, response);//放行 51 } 52 53 @Override 54 public void destroy() { 55 // TODO Auto-generated method stub 56 57 } 58 59 60 }
其中还有一个静态方法:
Class<?>[ ] interfaces :目标对象实现的接口的类型,使用泛型方式确认类型
测试类 App.java
1 /** 2 * 测试类 3 */ 4 public class App { 5 public static void main(String[] args) { 6 // 目标对象 7 接口类 target = new 目标对象类(); 8 // 【原始的类型 class 包名.类名】 9 System.out.println(target.getClass()); 10 11 // 给目标对象,建立代理对象 12 接口类 proxy = (接口类) new ProxyFactory(target).getProxyInstance(); 13 // class $Proxy0 内存中动态生成的代理对象 14 System.out.println(proxy.getClass()); 15 16 // 执行方法 【代理对象】 17 proxy.save(); 18 } 19 }
查看生产的代理类(代码):
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true" );
1.3 Cglib 代理
实现的方法是继承,其中要2个jar包:asm-x.x.jar 、 cglib-x.x.x.jar
相对于静态和动态代理比较,它们都须要实现一个接口的目标对象,若是对象只是一个单独的对象,其中没有任何接口的实现,那么这种状况就能够用目标子类的方式去实现代理,这种方式也叫Cglib代理;简称子类代理,从内存中构建子类对象从而实现对目标对象的功能扩展;
Cglib是一个强大的高性能的代码生成包,它的底层是经过使用一个小而块的字节码处理框架ASM来转换字节码并生成新的类。(通常不使用ASM,由于要对JVM内部结构掌握精通)它能在运行期扩展java类与实现java接口;如:Spring AOP和synaop,为他们提供方法的interception(拦截);
Cglib子类代理的实现
先要引入jar包,如:spring-core-3.2.5.jar , 而后在内存中动态构建子类;其中代理的类不能为final,不然报错;目标对象的方法若是为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法;方法是final/static则没法进行代理。
目标对象类(没有接口)
1 /** 2 * 目标对象,没有实现任何接口 3 */ 4 public class XX { 5 6 public void save() { 7 System.out.println("XXXXXX"); 8 } 9 }
代理工厂类
1 /** 2 * Cglib子类代理工厂 3 * 在内存中动态构建一个子类对象 4 */ 5 public class XX implements MethodInterceptor{ 6 //维护目标对象 7 private Object target; 8 9 public XX(Object target) { 10 this.target = target; 11 } 12 13 //给目标对象建立一个代理对象 14 public Object getProxyInstance(){ 15 //1.工具类 16 Enhancer en = new Enhancer(); 17 //2.设置父类 18 en.setSuperclass(target.getClass()); 19 //3.设置回调函数 20 en.setCallback(this); 21 //4.建立子类(代理对象) 22 return en.create(); 23 24 } 25 26 @Override 27 public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { 28 System.out.println("开始事务..."); 29 30 //执行目标对象的方法 31 Object returnValue = method.invoke(target, args); 32 33 System.out.println("提交事务..."); 34 35 return returnValue; 36 } 37 }
测试类
1 /** 2 * 测试类 3 */ 4 public class Test{ 5 6 @Test 7 public void test(){ 8 //目标对象 9 XX target = new XX(); 10 11 //代理对象 12 XX proxy = (XX)new 代理工厂类(target).getProxyInstance(); 13 14 //执行代理对象的方法 15 proxy.save(); 16 } 17 }
DefaultAopProxyFactory的源码(有兴趣可看)
1 // Source code recreated from a .class file by IntelliJ IDEA 2 // (powered by Fernflower decompiler) 3 4 package org.springframework.aop.framework; 5 6 import java.io.Serializable; 7 import java.lang.reflect.Proxy; 8 import org.springframework.aop.SpringProxy; 9 10 public class DefaultAopProxyFactory implements AopProxyFactory, Serializable { 11 public DefaultAopProxyFactory() { 12 } 13 14 public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { 15 if (!config.isOptimize() && !config.isProxyTargetClass() && !this.hasNoUserSuppliedProxyInterfaces(config)) { 16 return new JdkDynamicAopProxy(config); 17 } else { 18 Class<?> targetClass = config.getTargetClass(); 19 if (targetClass == null) { 20 throw new AopConfigException("TargetSource cannot determine target class: Either an interface or a target is required for proxy creation."); 21 } else { 22 return (AopProxy)(!targetClass.isInterface() && !Proxy.isProxyClass(targetClass) ? new ObjenesisCglibAopProxy(config) : new JdkDynamicAopProxy(config)); 23 } 24 } 25 } 26 27 private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) { 28 Class<?>[] ifcs = config.getProxiedInterfaces(); 29 return ifcs.length == 0 || ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0]); 30 } 31 }
小结:加入容器的目标对象有实现接口,用JDK代理
目标对象没有实现接口,用Cglib代理
目标对象实现了接口,且强制使用cglib代理,则会使用cglib代理。
二、程序中事务控制
2.1 流程
通常是先用户访问,而后Action到Service到Dao;若是调用service执行成功,则说明业务是成功的,由于事务应该在service层统一控制;
2.2 事务控制的初步了解
编程式事务控制:本身手动控制的事务;
Jdbc代码:Conn.setAutoCommite(false); // 设置手动控制事务
Hibernate代码:Session.beginTransaction(); // 开启一个事务
【细粒度的事务控制: 能够对指定的方法、指定的方法的某几行添加事务控制】
(比较灵活,但开发起来比较繁琐: 每次都要开启、提交、回滚.)
声明式事务控制
声明式事务管理就是Spring提供了对事务的管理。
Spring提供了对事务控制的实现。用户若是想用Spring的声明式事务管理,只须要在配置文件中配置便可; 不想使用时直接移除配置。这个实现了对事务控制的最大程度的解耦。
Spring声明式事务管理的核心实现就是基于Aop。
【粗粒度的事务控制: 只能给整个方法应用事务,不能够对方法的某几行应用事务。】(由于aop拦截的是方法。)
Spring声明式事务管理器类:
Jdbc技术:DataSourceTransactionManager
Hibernate技术:HibernateTransactionManager
三、声明式事务管理的实现
首先要引入spring-aop相关的4个jar文件,再引入aop名称空间,由于XML配置方法须要引入,最后引入tx名称空间(事务方式必须引入);
XML去实现
Dao.java类
1 public class Dao { 2 3 // 容器注入JdbcTemplate对象 4 private JdbcTemplate jdbcTemplate; 5 public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { 6 this.jdbcTemplate = jdbcTemplate; 7 } 8 9 public void save(Dept dept){ 10 String sql = "insert into t_dept (deptName) values(?)"; 11 jdbcTemplate.update(sql,dept.getDeptName()); 12 } 13 }
service类
1 public class Service { 2 3 // 容器注入dao对象 4 private Dao deptDao; 5 public void setDao(Dao deptDao) { 6 this.deptDao = deptDao; 7 } 8 9 /* 10 * 事务控制 11 */ 12 public void save(Dept dept){ 13 // 第一次调用 14 deptDao.save(dept); 15 16 int i = 1/0; // 异常: 整个Service.save()执行成功的要回滚 17 18 // 第二次调用 19 deptDao.save(dept); 20 } 21 }
测试类
1 @Test 2 public void test() throws Exception { 3 //容器对象 4 ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); 5 6 // 模拟数据 7 Dept dept = new Dept(); 8 dept.setDeptName("测试"); 9 10 Service Service = (Service) ac.getBean("deptService"); 11 Service.save(dept); 12 13 }
bean.xmk (Spring管理配置)
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:p="http://www.springframework.org/schema/p" 5 xmlns:context="http://www.springframework.org/schema/context" 6 xmlns:aop="http://www.springframework.org/schema/aop" 7 xmlns:tx="http://www.springframework.org/schema/tx" 8 xsi:schemaLocation="http://www.springframework.org/schema/beans 9 http://www.springframework.org/schema/beans/spring-beans.xsd 10 http://www.springframework.org/schema/context 11 http://www.springframework.org/schema/context/spring-context.xsd 12 http://www.springframework.org/schema/aop 13 http://www.springframework.org/schema/aop/spring-aop.xsd 14 http://www.springframework.org/schema/tx 15 http://www.springframework.org/schema/tx/spring-tx.xsd"> 16 17 18 <!-- 数据源对象: C3P0链接池 --> 19 <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> 20 <property name="XX" value="com.mysql.jdbc.Driver"></property> 21 <property name="jdbcUrl" value="jdbc:mysql:XX"></property> 22 <property name="user" value="root"></property> 23 <property name="password" value="root"></property> 24 <property name="initialPoolSize" value="XX"></property> 25 <property name="maxPoolSize" value="XX"></property> 26 <property name="maxStatements" value="XX"></property> 27 <property name="acquireIncrement" value="XX"></property> 28 </bean> 29 30 <!-- JdbcTemplate工具类实例 --> 31 <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> 32 <property name="dataSource" ref="dataSource"></property> 33 </bean> 34 35 <!-- dao实例 --> 36 <bean id="deptDao" class="XX"> 37 <property name="jdbcTemplate" ref="jdbcTemplate"></property> 38 </bean> 39 40 <!-- service实例 --> 41 <bean id="deptService" class="XX"> 42 <property name="deptDao" ref="deptDao"></property> 43 </bean> 44 45 <!-- Spring声明式事务管理配置:配置事务管理器类 --> 46 47 <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 48 <property name="dataSource" ref="dataSource"></property> 49 </bean> 50 51 <!-- 配置事务加强 --> 52 <tx:advice id="txAdvice" transaction-manager="txManager"> 53 <tx:attributes> 54 <tx:method name="get*" read-only="true"/> 55 <tx:method name="find*" read-only="true"/> 56 <tx:method name="*" read-only="false"/> 57 </tx:attributes> 58 </tx:advice> 59 60 <!--Aop配置: 拦截哪些方法(切入点表表达式) + 应用上面的事务加强配置 --> 61 <aop:config> 62 <aop:pointcut expression="execution(* cn.itcast.a_tx.DeptService.*())" id="pt"/> 63 <aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/> 64 </aop:config> 65 66 </beans>
还有一种方法:注解(推荐使用,更简单)
先引入Aop相关的jar包文件,再在 bean.xml中指定注解方式实现声明式事务管理及管理器,最后在须要添加事务控制的地方写上:@Transactional ;例如:
应用事务的注解
定义到方法上: 当前方法应用spring的声明式事务
定义到类上: 当前类的全部的方法都应用Spring声明式事务管理;
定义到父类上: 当执行父类的方法时候应用事务。
bean.xml(核心代码)
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:p="http://www.springframework.org/schema/p" 5 xmlns:context="http://www.springframework.org/schema/context" 6 xmlns:aop="http://www.springframework.org/schema/aop" 7 xmlns:tx="http://www.springframework.org/schema/tx" 8 xsi:schemaLocation="http://www.springframework.org/schema/beans 9 http://www.springframework.org/schema/beans/spring-beans.xsd 10 http://www.springframework.org/schema/context 11 http://www.springframework.org/schema/context/spring-context.xsd 12 http://www.springframework.org/schema/aop 13 http://www.springframework.org/schema/aop/spring-aop.xsd 14 http://www.springframework.org/schema/tx 15 http://www.springframework.org/schema/tx/spring-tx.xsd"> 16 17 18 <!-- C3P0链接池 --> 19 <bean id="dataSource" class="xx"> 20 <property name="driverClass" value="com.mysql.jdbc.Driver"></property> 21 <property name="jdbcUrl" value="jdbc:mysql:xx"></property> 22 <property name="user" value="root"></property> 23 <property name="password" value="root"></property> 24 <property name="initialPoolSize" value="xx"></property> 25 <property name="maxPoolSize" value="xx"></property> 26 <property name="maxStatements" value="xx"></property> 27 <property name="acquireIncrement" value="xx"></property> 28 </bean> 29 30 <!--JdbcTemplate工具类实例 --> 31 <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> 32 <property name="dataSource" ref="dataSource"></property> 33 </bean> 34 35 <!-- 事务管理器类 --> 36 <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 37 <property name="dataSource" ref="dataSource"></property> 38 </bean> 39 40 <!-- 开启注解扫描 --> 41 <context:component-scan base-package="cn.itcast.b_anno"></context:component-scan> 42 43 <!-- 注解方式实现事务: 指定注解方式实现事务 --> 44 <tx:annotation-driven transaction-manager="txManager"/> 45 </beans>
事务传播行为
Propagation.REQUIRED:指定当前的方法必须在事务的环境下执行,若是当前运行的方法,已经存在事务, 就会加入当前的事务;
Propagation.REQUIRED_NEW:必须在事务的环境下执行的方法,若是当前运行的方法,已经存在事务: 事务会挂起; 会始终开启一个新的事务,执行完后; 刚才挂起的事务才继续运行。
Class Log{ Propagation.REQUIRED insertLog(); } Propagation.REQUIRED Void saveDept(){ insertLog(); // 加入当前事务 .. 异常, 会回滚 saveDept(); } Class Log{ Propagation.REQUIRED_NEW insertLog(); } Propagation.REQUIRED Void saveDept(){ insertLog(); // 始终开启事务 .. 异常, 日志不会回滚 saveDept(); }
end...