一、代理模式
代理模式的英文叫做Proxy或Surrogate,中文都可译为”代理“,所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
以简单模拟事务的执行过程说明各种代理区别
1.1 静态代理
由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
public interface PersonDao { void savePerson(); }
public class PersonDaoImpl implements PersonDao { @Override public void savePerson() { System.out.println("save person"); } }
public class Transaction { void beginTransaction(){ System.out.println("begin Transaction"); } void commit(){ System.out.println("commit"); } }
接下来编写静态代理类---实现PersonDao接口
/** * 静态代理类 * @author qjc */ public class PersonDaoProxy implements PersonDao{ PersonDao personDao; Transaction transaction; public PersonDaoProxy(PersonDao personDao, Transaction transaction) { this.personDao = personDao; this.transaction = transaction; } @Override public void savePerson() { this.transaction.beginTransaction(); this.personDao.savePerson(); this.transaction.commit(); } }
/** * 测试静态代理 * @author qjc */ public class TestPersonProxy { @Test public void testSave(){ PersonDao personDao = new PersonDaoImpl(); Transaction transaction = new Transaction(); PersonDaoProxy proxy = new PersonDaoProxy(personDao, transaction); proxy.savePerson(); } }
总结:
1、静态代理模式并没有做到事务的重用
2、假设dao有100个类,100个proxy,接口中有多少方法,在proxy层就得实现多少方法,有多少方法就要开启和提交多少事务
3、如果一个proxy实现了多个接口,如果其中的一个接口发生变化(添加了一个方法),那么proxy也要做相应改变
1.2 JDK动态代理
动态代理类:在程序运行时,运用反射机制动态创建而成。
JDK的动态代理必须具备四个条件:1、目标接口 2、目标类 3、拦截器 4、代理类
使用上个例子的PersonDao接口、PersonDaoImpl类及Transaction类
编写拦截器
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * 拦截器 * 1、目标类导入进来 * 2、事物导入进来 * 3、invoke完成:开启事务、调用目标对象的方法、事务提交 * * @author qjc */ public class Interceptor implements InvocationHandler { private Object target; // 目标类 private Transaction transaction; public Interceptor(Object target, Transaction transaction) { this.target = target; this.transaction = transaction; } /** * @param proxy 目标对象的代理类实例 * @param method 对应于在代理实例上调用接口方法的Method实例 * @param args 传入到代理实例上方法参数值的对象数组 * @return 方法的返回值,没有返回值是null * @throws Throwable */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName(); if ("savePerson".equals(methodName) || "deletePerson".equals(methodName) || "updatePerson".equals(methodName)) { this.transaction.beginTransaction(); // 开启事务 method.invoke(target); // 调用目标方法 this.transaction.commit(); // 提交事务 } else { method.invoke(target); } return null; } }
/** * 测试jdk动态代理 * @author qjc */ public class TestJDKProxy { @Test public void testSave(){ /** * 1、创建一个目标对象 * 2、创建一个事务 * 3、创建一个拦截器 * 4、动态产生一个代理对象 */ Object target = new PersonDaoImpl(); Transaction transaction = new Transaction(); Interceptor interceptor = new Interceptor(target, transaction); /** * 参数一:设置代码使用的类加载器,一般采用跟目标类相同的类加载器 * 参数二:设置代理类实现的接口,跟目标类使用相同的接口 * 参数三:设置回调对象,当代理对象的方法被调用时,会调用该参数指定对象的invoke方法 */ PersonDao personDao = (PersonDao) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), interceptor); personDao.savePerson(); } }
总结:
1、因为利用JDKProxy生成的代理类实现了接口,所以目标类中所有的方法在代理类中都有。
2、生成的代理类的所有的方法都拦截了目标类的所有的方法。而拦截器中invoke方法的内容正好就是代理类的各个方法的组成体。
3、利用JDKProxy方式必须有接口的存在。
4、invoke方法中的三个参数可以访问目标类的被调用方法的API、被调用方法的参数、被调用方法的返回类型。
缺点:
1、在拦截器中除了能调用目标对象的目标方法以外,功能是比较单一的,在这个例子中只能处理事务
2、拦截器中的invoke方法的if判断语句在真实的开发环境下是不靠谱的,因为一旦方法很多if语句需要写很多。
1.3 CGLIB动态代理
使用上个例子的PersonDaoImpl类和Transaction类(不用接口)
编写拦截器类
import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; /** * CGLIB代理 拦截器 * @author qjc */ public class Interceptor implements MethodInterceptor { private Object target; // 代理的目标类 private Transaction transaction; public Interceptor(Object target, Transaction transaction) { this.target = target; this.transaction = transaction; } /** * 创建目标对象的代理对象 * * @return */ public Object createProxy() { // 代码增强 Enhancer enhancer = new Enhancer(); // 该类用于生成代理对象 enhancer.setCallback(this); // 参数为拦截器 enhancer.setSuperclass(target.getClass());// 设置父类 return enhancer.create(); // 创建代理对象 } /** * @param obj 目标对象代理类的实例 * @param method 代理实例上 调用父类方法的Method实例 * @param args 传入到代理实例上方法参数值的对象数组 * @param methodProxy 使用它调用父类的方法 * @return * @throws Throwable */ public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { this.transaction.beginTransaction(); method.invoke(target); this.transaction.commit(); return null; } }
/** * 测试cglib动态代理 * 通过cglib产生的代理对象,代理类是目标类的子类 * @author qjc */ public class TestCglibProxy { @Test public void testSave(){ Object target = new PersonDaoImpl(); Transaction transaction = new Transaction(); Interceptor interceptor = new Interceptor(target, transaction); PersonDaoImpl personDaoImpl = (PersonDaoImpl) interceptor.createProxy(); personDaoImpl.savePerson(); } }
总结:
1、CGlib是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。
2、用CGlib生成代理类是目标类的子类。
3、用CGlib生成 代理类不需要接口
4、用CGLib生成的代理类重写了父类的各个方法。
5、拦截器中的intercept方法内容正好就是代理类中的方法体
CGLIB和JDK动态代理区别:
JDK:
目标类和代理类实现了共同的接口
拦截器必须实现InvocationHandler接口,而这个接口中invoke方法体的内容就是代理对象方法体的内容
CGLIB:
目标类 是代理类的父类
拦截器必须实现MethodInterceptor接口,而接口中的intercept方法就是代理类的方法体,使用字节码增强机制创建代理对象的.
二、面向切面编程
OOP(面向对象编程):封装、继承、多态、抽象
封装,对代码进行基本的管理、模块化的管理。每个类可能都有自己的职能,出了问题就是论事找人就行了。从修改角度讲,直接修改代码可能有风险,这不是个长远之计,最自然的是从类型封装变化。但是新的类型和旧的体系之间怎么去融合,所以说需要在类与类之间建立一种血缘关系。那么这就是继承的需求,通过继承就可以发现这些类之间是有关联的,它们之间是有父子关系的。然后在继承基础之上多态起决定性的特征。所以说一般认为面向对象最核心的特征,其实是多态。前面几个都是在做铺垫的。多态才是它最核心的特征。子类中通过重写方法,代表了扩展这个层面的东西,而它能融入老的体系中能够正常工作,这是重用这个层面的东西,新的方法、旧的体系、扩展和重用。
AOP(面向切面编程):
面向切面编程,是一种通过预编译方式运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术.
OOP与AOP区别:
OOP:针对业务处理过程的实体及其属性和行为进行抽象封装,以获得更加清楚的逻辑单元划分。
AOP:针对业务处理过程中的横切逻辑 进行提取,它所面对的是处理过程中的某个步骤或者阶段,以获得逻辑过程中各部分之间低耦合的隔离效果。这两种设计思想在目标上有着本质的差异。AOP做到了代码块的重用。
spring AOP代理机制:
1、若目标对象实现了若干接口,spring使用JDK的java.lang.reflect.Proxy类代理。
优点:因为有接口,所以使系统更加松耦合
缺点:为每一个目标类创建接口
2、若目标对象没有实现任何接口,spring使用CGLIB库生成目标对象的子类。
优点:因为代理类与目标类是继承关系,所以不需要有接口的存在。
缺点:因为没有使用接口,所以系统的耦合性没有使用JDK的动态代理好。
使用第一个例子的 PersonDao接口、PersonDaoImpl类和Transaction类
编写spring配置
<bean id="personDao" class="cn.qjc.aop.xml.PersonDaoImpl"></bean> <bean id="transaction" class="cn.qjc.aop.xml.Transaction"></bean> <aop:config> <!-- 切入点表达式 确定目标类 --> <aop:pointcut expression="execution(* cn.qjc.aop.xml.PersonDaoImpl.*(..))" id="perform"/> <!-- ref指向对象就是切面 --> <aop:aspect ref="transaction"> <aop:before method="beginTransaction" pointcut-ref="perform"/> <aop:after-returning method="commit" pointcut-ref="perform"/> </aop:aspect> </aop:config> </beans>
/** * 测试spring动态代理 * @author qjc */ public class TransactionTest { @Test public void testSave(){ ApplicationContext context = new ClassPathXmlApplicationContext("cn/qjc/aop/xml/applicationContext.xml"); PersonDao personDao = (PersonDao) context.getBean("personDao"); personDao.savePerson(); } }
spring AOP原理
1、当spring容器启动的时候,加载两个bean,对像个bean进行实例化
2、当spring容器对配置文件解析到<aop:config>的时候,把切入点表达式解析出来,按照切入点表达式匹配spring容器内容的bean
3、如果匹配成功,则为该bean创建代理对象
4、当客户端利用context.getBean获取一个对象时,如果该对象有代理对象,则返回代理对象,如果没有代理对象,则返回对象本身
相关推荐
在Spring中,AOP主要通过两种动态代理技术实现:JDK动态代理和CGLIB动态代理。 首先,让我们详细了解一下JDK动态代理。JDK动态代理基于Java的接口实现,它适用于目标对象实现了至少一个接口的情况。在运行时,JDK...
Spring框架中的AOP模块使用了动态代理来实现AOP概念。Spring AOP允许开发者定义切面,并在这些切面中指定拦截的方法。Spring AOP支持不同的代理策略,包括JDK动态代理和CGLIB代理。如果被代理的类没有实现接口,...
AOP(Aspect Oriented Programming,面向切面编程)是一种编程范式,旨在提供一种方法来组织和模块化系统中的...通过阅读《AOP动态代理(反射机制)》这本书,你可以深入理解这些概念,并通过丰富的示例掌握其实现方法。
Spring AOP通过代理模式实现了这一概念,允许开发者在不修改源代码的情况下插入额外的功能。 JDK动态代理是Java提供的一种创建代理对象的方式,它在运行时根据接口生成一个实现了这些接口的代理类。Spring AOP可以...
Spring AOP则是在Spring框架中对AOP概念的实现,它利用了JDK动态代理或CGLIB(字节码增强)来实现。Spring AOP的主要目标是分离关注点,将非业务逻辑(如日志、事务管理)从核心业务代码中解耦出来。以下是Spring ...
动态代理和AOP是Java和Spring框架中的重要概念,它们为开发者提供了强大的代码复用和模块化设计的能力。本文将深入解析这两个主题,并结合提供的源码进行详细讲解。 首先,让我们了解一下动态代理。在Java中,动态...
这些代码可能涉及到如何创建分页对象,如何与数据库交互获取分页数据,以及如何在AOP中使用动态代理进行拦截和处理。 总的来说,Java分页、动态代理和AOP是Java开发中的关键技术,它们能帮助我们构建出更加高效、可...
### Spring AOP面向方面编程原理:AOP概念详解 #### 一、引言 随着软件系统的日益复杂,传统的面向对象编程(OOP)逐渐暴露出难以应对某些横切关注点(cross-cutting concerns)的问题。为了解决这一挑战,面向方面编程...
这篇博客的文章链接虽然没有给出具体内容,但我们可以根据Java动态代理和Spring AOP的基本概念来深入探讨相关知识点。 首先,Java动态代理允许我们在运行时创建一个实现了特定接口的新类。这个新类会代理原始类,并...
动态代理是实现AOP的一种方式,而在Java中,CGLIB(Code Generation Library)是一个常用的库,专门用于创建子类动态代理。下面我们将详细探讨AOP、动态代理以及CGLIB的相关知识点。 首先,AOP的核心概念是“切面”...
主要对Spring AOP的相关概念和简单的静态代理、动态代理以及常见的几种AOP配置方式做总结学习。主要包括:1. AOP的常见概念 2. 静态代理 3. jdk动态代理 4. Aspectj and Aspectjweaver 5. **aop-config** 6. CGLIB ...
动态代理是实现AOP的一种常见手段,尤其在Java中应用广泛。 动态代理主要分为JDK动态代理和CGLIB动态代理两种方式: 1. **JDK动态代理**: JDK动态代理基于接口实现,它通过`java.lang.reflect.Proxy`类和`java....
4. **AOP概念**: - 切面(Aspect):是AOP的核心,它封装了横切关注点,可以看作是跨越多个对象的行为或责任。 - 切点(Join Point):程序执行中的某个特定点,如方法的调用或异常的抛出。 - 通知(Advice):...
Spring框架是Java中实现AOP的一个流行工具,它通过动态代理机制实现了这一功能。本文将深入探讨Spring AOP的实现原理,以及如何使用反射来实现动态代理模式。 首先,我们需要了解AOP的基本概念。AOP的核心思想是切...
动态代理和Spring AOP(面向切面编程)是两个关键的设计概念,它们在实现高效、模块化的系统中起着至关重要的作用。本文将深入探讨这两个概念,并结合实际应用进行解析。 首先,让我们理解什么是动态代理。动态代理...
在 Spring 中,AOP 的实现主要依赖于代理模式,有两种代理方式:JDK 动态代理和 CGLIB 动态代理。 JDK 动态代理是基于接口的,它要求被代理的目标对象必须实现至少一个接口。Spring 使用 `java.lang.reflect.Proxy`...
本篇文章将详细探讨如何通过Java的动态代理机制来模拟Spring AOP的核心概念。 首先,让我们了解什么是动态代理。在Java中,动态代理主要由`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口...
### AOP概念详解 #### 一、AOP概述 面向切面编程(Aspect-Oriented Programming,简称AOP)是一种编程范式,旨在通过将横切关注点与业务逻辑分离,增强代码的可读性和可维护性。在企业级应用中,事务管理、日志...
在IT行业中,Spring AOP(面向切面编程)是一个重要的概念,它允许程序员定义横切关注点,并将这些关注点与业务逻辑分离。本篇文章将深入探讨Spring AOP中的动态代理、责任链模式以及注解的使用。 首先,动态代理是...
总的来说,结合使用Castle IOC和AOP动态代理,开发者可以构建出松散耦合、模块化的系统,提高代码的复用性和可测试性,同时还能优雅地处理系统中的横切关注点。在处理如WebService这样的远程服务时,这种能力尤为...