- 代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。这样就出现了大量的代码重复。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
- 代理对象只服务于一种类型的对象,如果要服务多类型的对象。势必要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了。
从JDK 1.3开始,Java提供了动态代理技术,允许开发者在运行时创建接口的代理实例,在java中有多种动态代理技术,比如JDK、CGLib、Javassist、ASM,其中最常用的动态代理技术有两种:一种是JDK动态代理,这是JDK自带的功能;一种是CGLib,这是第三方提供的一个技术。目前,Spring常用JDK和CGLib,而mybatis还使用了javassist,无论哪种代理技术,他们的理念都是相似的。
在JDK动态代理中,要实现代理逻辑类必须去实现 java.lang.reflect.InvocationHandler接口,它里面定义了一个invoke方法,并提供接口数组用于下挂代理对象,如下代码所示:
public class JDKProxyFactory implements InvocationHandler{
//目标对象
private Object target;
/**
* 建立代理对象和目标对象的代理关系,并返回代理对象
* @param target 目标对象
* @return 代理对象
*/
public Object createTargetProxyInstance(Object target) {
this.target = target;
/*
* 第1个参数为类加载器:采用了target本身的类加载器
* 第2个参数为把生成的动态代理对象下挂在哪些接口下,这个写法表示放在target实现的接口下
* 第3个表示实现方法逻辑的代理类,this表示当前对象,它必须实现InvocationHandler的invoke方法
*/
return Proxy.newProxyInstance(this.target.getClass().getClassLoader(),
this.target.getClass().getInterfaces(), this);
}
/**
* 代理方法逻辑
* @param proxy 代理对象
* @param method 当前调度方法
* @param args 当前方法参数
* @return 代理结果返回
* @throws Throwable 异常
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object ret = null;
System.out.println("进入代理逻辑方法,在调度真实对象之前的服务,比如记录日志");
ret = method.invoke(target, args);
System.out.println("调度真实对象之后的服务");
return ret;
}
}
使用Java的动态代理有一个局限性就是代理的类必须要实现接口,虽然面向接口编程是每个优秀的Java程序都知道的规则,但现实往往不尽如人意,对于没有实现接口的类如何为其生成代理呢?继承!继承是最经典的扩展已有代码能力的手段,虽然继承常常被初学者滥用,但继承也常常被进阶的程序员忽视。CGLib采用非常底层的字节码生成技术,通过为一个类创建子类来生成代理,它弥补了Java动态代理的不足,因此Spring中动态代理和CGLib都是创建代理的重要手段,对于实现了接口的类就用动态代理为其生成代理类,而没有实现接口的类就用CGLib通过继承的方式为其创建代理。
public class CGLibProxyFactory implements MethodInterceptor {
//目标对象
private Object target;
/**
* 生成CGLib代理对象
* @param target 目标对象
* @return 目标对象的CGLib代理对象
*/
public Object createProxyInstance(Object target) {
this.target = target;
// 增强类对象
var enhancer = new Enhancer();
//设置增强类型
enhancer.setSuperclass(target.getClass());
//定义代理逻辑对象为当前对象,要求当前对象实现MethodInterceptor接口
enhancer.setCallback(this);
//生成并返回代理对象
return enhancer.create();
}
/**
* 代理逻辑方法
* @param proxy 代理对象
* @param method 方法
* @param args 方法参数
* @param methodProxy方法 代理
* @return 代理逻辑返回
* @throws Throwable 异常
*/
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object ret = null;
if (权限判断) {//环绕通知(可以决定方法是否被调用(权限拦截))
try {
System.out.println("开启事务"); // 前置通知
//反射调用真实方法
ret = method.invoke(target, args);
//ret = methodProxy.invokeSuper(proxy, args);
System.out.println("提交事务");// 后置通知
} catch (Exception e) {
System.out.println("回滚事务");// 例外通知
} finally {
System.out.println("释放资源,最终操作"); // 最终通知
}
}
return ret;
}
}
Spring AOP中相关概念
连接点:程序执行的某个特定位置(如:某个方法调用前、调用后,方法抛出异常后)。一个类或一段程序代码拥有一些具有边界性质的特定点,这些代码中的特定点就是连接点。Spring仅支持方法的连接点。
切点:如果连接点相当于数据中的记录,那么切点相当于查询条件,一个切点可以匹配多个连接点。Spring AOP的规则解析引擎负责解析切点所设定的查询条件,找到对应的连接点。
增强:增强是织入到目标类连接点上的一段程序代码。Spring提供的增强接口都是带方位名的,如:BeforeAdvice、AfterReturningAdvice、ThrowsAdvice等。很多资料上将增强译为“通知”,这明显是个词不达意的翻译,让很多程序员困惑了许久。
引介:引介是一种特殊的增强,它为类添加一些属性和方法。这样,即使一个业务类原本没有实现某个接口,通过引介功能,可以动态的未该业务类添加接口的实现逻辑,让业务类成为这个接口的实现类。
织入:织入是将增强添加到目标类具体连接点上的过程,AOP有三种织入方式:
- 编译期织入:需要特殊的Java编译期(例如AspectJ)
- 类装载期织入:要求使用特殊的类加载器
- 动态代理织入:在运行时为目标类生成代理实现增强
Spring采用了动态代理织入,而AspectJ采用了编译期织入和类装载期织入的方式。
切面:切面是由切点和增强(引介)组成的,它包括了对横切关注功能的定义,也包括了对连接点的定义。
横切性关注点
通过对系统需求和实现的识别,我们可以将模块中的这些关注点分为:核心关注点和横切关注点。对于核心关注点而言,通常来说,实现这些关注点的模块是相互独立的,他们分别完成了系统需要的商业逻辑,这些逻辑与具体的业务需求有关。而对于日志、安全、持久化等关注点而言,他们却是商业逻辑模块所共同需要的,这些逻辑分布于核心关注点的各处。在AOP中,诸如这些模块,都称为横切关注点。应用AOP的横切技术,关键就是要实现对关注点的识别。
相关推荐
面向切面编程(Aspect-Oriented Programming,AOP)是...通过学习和掌握C#中的面向切面编程,我们可以更好地设计和维护复杂系统。在压缩包文件"AOP_Test"中,可能包含了更多复杂的AOP实现示例,供你进一步研究和学习。
【Spring 框架系列(4) - 深入浅出 Spring 核心之面向切面编程(AOP)】 面向切面编程(AOP),全称为 Aspect Oriented Programming,是Spring框架的重要特性之一,用于实现代码的解耦,提高可维护性和可复用性。AOP的...
Spring AOP(面向切面编程)是Spring框架的重要组成部分,它允许我们在不修改源代码的情况下对应用程序的行为进行统一管理和控制。在本实例中,我们将深入探讨如何使用AspectJ技术和XML配置来实现AOP。 首先,了解...
在IT行业中,Spring AOP(Aspect Oriented Programming,面向切面编程)是Spring框架的核心特性之一,它使得我们能够以一种声明式的方式处理系统中的横切关注点,如日志记录、事务管理、性能监控等。这个“spring-...
在Java世界中,Spring框架是企业级应用开发的首选,其中AOP(Aspect Oriented Programming,面向切面编程)是其重要特性之一。AOP提供了一种将关注点分离的技术,使得我们可以将一些通用功能如日志、事务管理、权限...
在Java开发中,动态代理和CGLIB代理是两种常见的面向切面编程(AOP)实现方式,它们都用于在不修改原有代码的情况下,增强或扩展对象的功能。本篇文章将深入探讨JDK动态代理和CGLIB代理的区别,以及它们在实际应用中...
通过以上步骤,我们成功地利用Java动态代理实现了面向切面编程(AOP)。这种方式不仅保持了原有业务逻辑的完整性,还使得日志记录等横切关注点能够被集中管理和配置。这对于提高软件的可维护性和扩展性具有重要意义...
JDK和CGLIB是Java中实现动态代理的两种主要方式,它们在Spring框架中扮演着关键角色,尤其是在AOP(面向切面编程)中。 1. **JDK动态代理**: JDK动态代理基于Java的接口机制实现,因此,要使用JDK动态代理,被...
- **AOP(面向切面编程)**:动态代理常用于实现切面,如事务管理、日志记录、性能分析等。 - **事件驱动编程**:在事件驱动系统中,动态代理可以用来拦截事件处理,添加额外的处理逻辑。 - **测试**:在单元测试...
- **AOP(面向切面编程)**:动态代理常用于实现切面编程,比如在方法调用前后插入日志或事务处理。 - **远程调用**:RMI(Remote Method Invocation)中的代理,允许本地对象调用远程服务器上的方法。 - **事件...
动态代理则可以在运行时生成代理对象,用于实现AOP(面向切面编程)等高级功能。 9. **设计模式**:设计模式是在特定场景下解决常见问题的最优解决方案。面向对象编程中常用的设计模式有单例模式、工厂模式、策略...
- **总结**:通过本书的学习,读者不仅能掌握面向切面编程的基本概念,还能深入了解如何在实际项目中运用AspectJ来解决复杂的编程挑战。 - **未来展望**:面向切面编程作为一种有效的编程范式,在未来的软件开发中将...
这种方式常用于AOP(面向切面编程)中,例如日志记录、性能监控、事务管理等场景。 具体实现步骤如下: 1. 定义接口:首先,你需要定义一个或多个接口,这些接口将被代理对象实现。 2. 创建InvocationHandler:实现...
- **AOP(面向切面编程)**:动态代理常用于实现切面编程,如在方法执行前后加入拦截逻辑,例如日志记录、权限检查等。 - **RPC(远程过程调用)**:在客户端和服务器之间,动态代理可以用来包装真实的服务调用,...
在Java编程领域,代理机制和面向切面编程(AOP)是两个重要的概念,它们在Spring框架中得到了广泛的应用。本文将深入探讨这两个主题,并结合JDK的反射和CGLIB库来阐述其实现原理。 首先,我们来看动态代理。动态...
在IT行业中,Spring AOP(面向切面编程)是一个重要的概念,它允许程序员定义横切关注点,并将这些关注点与业务逻辑分离。本篇文章将深入探讨Spring AOP中的动态代理、责任链模式以及注解的使用。 首先,动态代理是...
CGlib,全称为Code Generation Library,是一个强大的、高性能的代码生成库,被广泛应用于Java编程中,特别是面向切面...理解并掌握CGlib的工作原理和使用方式,对于提升Java开发中的面向切面编程能力具有重要意义。
这种技术常用于实现AOP(面向切面编程)或者为已有的接口添加额外的行为,如日志、事务管理等。Java的动态代理主要通过`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口来实现。当我们创建...
Spring AOP(面向切面编程)是Spring框架的重要组成部分,它提供了一种模块化和抽象化的方法来处理系统中的交叉关注点,如日志、事务管理、安全性等。本学习笔记将深入探讨Spring AOP的核心概念、工作原理以及实际...
例如,在AOP(面向切面编程)中,我们可以利用动态代理为业务对象添加拦截器,这些拦截器可以在方法调用前后执行额外的逻辑。同时,使用方法引用可以使得拦截器的定义更为简洁明了。 总结来说,Java动态代理和方法...