声明:本文取材于《精通Spring2.x》上的经典例子。
要了解Spring AOP,建议先熟悉一下设计模式中的代理模式(不基于编程语言的代理模式,关键是理解其思想)。
场景:在各个业务方法中添加进行方法性能测试的逻辑,输出测试方法性能信息(比如运行所花费的时间)。
本例假设业务为ForumServiceImpl,它实现了ForumService接口,该接口提供两个业务操作,见代码:
interface ForumService{
void removeTopic(int topicId);
void removeForum(int forumId);
}
public class ForumServiceImpl implements ForumService{
public void removeTopic(int topicId){
PerformanceMonitor.begin("removeTopic");//性能测试代码
System.out.println("模拟删除Topic记录:"+topicId);
try{
Thread.currentThread().sleep(20);
}catch(Exception e){
e.printStackTrace();
}
PerformanceMonitor.end();//性能测试代码
}
public void removeForum(int forumId){
PerformanceMonitor.begin("removeForum");//性能测试代码
System.out.println("模拟删除Forum记录..."+forumId);
try{
Thread.currentThread().sleep(400);
}catch(Exception e){
e.printStackTrace();
}
PerformanceMonitor.end();//性能测试代码
}
}
所有注视了“性能测试代码”的代码行,都是用于进行性能测试的附加代码,跟真正的业务逻辑没有太大关系。一、跟真正业务无关的代码,二,零散在业务逻辑各个角落中的代码,对于满足这两个特性的代码,正是
Spring AOP所要解决的问题,即把零散在业务逻辑各个角落中零散的非业务逻辑代码抽取出来进行统一管理,使得开发人员只需集中精力在真正的业务逻辑代码。
代码中的PerformanceMonitor是用于性能监测的工具类,它通过ThreadLocal保存一个MethodPerformance实例,见代码:
class MethodPerformance{
private long begin;
private String monitorMethod;//监控的方法
public MethodPerformance(String method){
this.monitorMethod = method;
this.begin = System.currentTimeMillis();
}
public void printPerformance(){
System.out.println("End Monitor...");
System.out.println(monitorMethod+" took "+(System.currentTimeMillis()-this.begin)+" milli seconds!");
}
}
class PerformanceMonitor{
private static ThreadLocal<MethodPerformance> performanceRecord = new ThreadLocal<MethodPerformance>();
public static void begin(String method){
System.out.println("Begin Monitor...");
MethodPerformance performance = new MethodPerformance(method);
performanceRecord.set(performance);
}
public static void end(){
MethodPerformance methodPerformance = performanceRecord.get();
methodPerformance.printPerformance();
}
}
下面看测试代码:
ForumService forumService = new ForumServiceImpl();
forumService.removeForum(10);
forumService.removeTopic(1);
运行结果:
Begin Monitor...
模拟删除Forum记录...10
End Monitor...
removeForum took 400 milli seconds!
Begin Monitor...
模拟删除Topic记录:1
End Monitor...
removeTopic took 20 milli seconds!
当然,各位看官眼明早就看出了程序中的问题了吧:把非业务逻辑操作混杂于业务逻辑!我们的目标是:将性能测试代码从业务逻辑中剔除。实现方法是动态代理,有基于JDK的动态代理和给予cglib的动态代理,本文先讲讲JDK Dynamic Delegate。
为了更好的理解,看客需要了解以下两个个名词:目标对象,代理对象。
Java本身支持动态代理,提供了两个接口:InvocationHandler和Proxy。InvocationHandler包含invoke方法,用于调用代理对象的目标方法,Proxy充当工厂角色,用于封装代理对象。先看代码再解释,先注释掉业务方法中用于性能测试的四行代码:
public class ForumServiceImpl implements ForumService{
public void removeTopic(int topicId){
//PerformanceMonitor.begin("removeTopic");
System.out.println("模拟删除Topic记录:"+topicId);
try{
Thread.currentThread().sleep(20);
}catch(Exception e){
e.printStackTrace();
}
//PerformanceMonitor.end();
}
public void removeForum(int forumId){
//PerformanceMonitor.begin("removeForum");
System.out.println("模拟删除Forum记录..."+forumId);
try{
Thread.currentThread().sleep(400);
}catch(Exception e){
e.printStackTrace();
}
//PerformanceMonitor.end();
}
}
然后,增加一个调用处理器,即InvocationHandler接口的实现,它用于封装目标对象的方法调用,在invoke方法中我们可以加入所有附加的业务逻辑。在这里,我们将性能测试的代码加到其中,而不是直接加到业务类中与业务逻辑混杂:
class PerformanceHandler implements InvocationHandler{
private Object target;//目标对象
public PerformanceHandler(){}
public PerformanceHandler(Object target){
this.target = target;//用于指定目标对象
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
/*proxy:代理对象,method:目标类的方法,此例中即ForumService提供的两个的业务方法*/
PerformanceMonitor.begin(target.getClass().getName()+"."+method.getName()+"()");//在业务逻辑方法之前加入性能测试代码
Object obj = method.invoke(target, args);//使用反射调用目标类中的方法
PerformanceMonitor.end();//在业务逻辑方法之后加入性能测试代码
return obj;
}
}
这样就实现了性能测试代码和业务逻辑代码的分离,测试代码为:
ForumService target = new ForumServiceImpl();
PerformanceHandler handler = new PerformanceHandler(target);
ForumService proxyForum = (ForumService)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), handler);
proxyForum.removeForum(1);
proxyForum.removeTopic(200);
此处,Proxy.getProxyInstance方法根据目标类的类加载器和所实现的接口,实现了基于特定InvocationHandler的代理对象,后面的操作中我们就可以透明的使用代理对象进行业务逻辑操作了。
问题总结:
- 动态代理对目标类中所有的方法都进行了拦截!如果此时ForumService加入了一个简单方法无需进行性能测试,
也逃不过InvocationHandler的拦截。当然,可以在invoke方法中加入简单判断:if(method.getName().equals(targetMethod)){...},
这样就可以对目标对象的目标方法进行区别对待。另外,AOP对此提供了更好的解决办法:IntroductionInterceptor。
- 从target.getClass().getInterfaces()可以看出,JDK动态代理需要目标对象必须实现一定的接口,如果此例中我们ForumServiceImpl不实现ForumService接口呢?
那么通过Proxy获得代理对象的代码将出现异常,异常描述类似于:$Proxy0 can't be cast to...即类型转换错误。这点cglib做得很成功。
- JDK动态代理是每次在使用代理对象时动态的改变目标类的信息,因此使用代理对象时执行效率受到了影响,这点cglib占有优势。
分享到:
相关推荐
本篇将详细讲解Spring中的AOP实现,特别是JDK动态代理的应用。 首先,我们要了解什么是AOP(Aspect Oriented Programming,面向切面编程)。AOP是一种编程范式,旨在解决应用程序中分散的、横切关注点的问题,如...
现在让我们深入探讨JDK动态代理和Spring AOP的原理。 首先,JDK动态代理基于Java的反射机制,通过`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口来实现。Proxy类用于创建一个代理对象,...
在Spring中,AOP主要通过两种动态代理技术实现:JDK动态代理和CGLIB动态代理。 首先,让我们详细了解一下JDK动态代理。JDK动态代理基于Java的接口实现,它适用于目标对象实现了至少一个接口的情况。在运行时,JDK...
本文将深入探讨Spring AOP中的JDK动态代理机制。 首先,我们要理解什么是动态代理。动态代理是在运行时创建一个实现了一组给定接口的代理类,这个代理类可以拦截并处理方法调用,从而实现一些额外的功能。JDK的动态...
Spring框架是AOP实现的一个典范,它提供了两种主要的动态代理方式:JDK动态代理和CGLib动态代理。 **JDK动态代理**: JDK动态代理基于Java的反射API实现,适用于接口代理。当目标对象实现了至少一个接口时,Spring...
Spring AOP 的底层实现技术 --- Jdk 动态代理原理 JDK 动态代理是 Spring AOP 的底层实现技术,允许开发者在运行期创建接口的代理实例。在 JDK 1.3 以后,JDK 动态代理技术提供了实现 AOP 的绝好底层技术。JDK 动态...
Spring 框架中 JDK 动态代理和 CGLIB 动态代理是 Spring AOP 中一个非常重要的知识点。Spring AOP 框架会根据实际情况选择使用 JDK 的动态代理还是 CGLIB 的动态代理。 JDK 动态代理是 Java 自带的动态代理机制,它...
在Java中,我们可以使用JDK的动态代理或者Spring AOP来实现代理模式。 JDK动态代理主要依赖于`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口。Proxy类是生成代理对象的工厂,而...
我们还提供了实际示例,演示如何在Spring AOP中使用JDK动态代理。 CGLib动态代理: 我们将深入研究CGLib动态代理,它允许您在不需要接口的情况下创建代理对象。您将了解CGLib的工作原理,以及如何生成子类来实现...
本篇将详细探讨JDK动态代理和Spring AOP,以及它们在实际应用中的作用。 首先,JDK动态代理是Java提供的一种在运行时创建代理对象的技术。它允许我们在不修改原有类的基础上,为已有接口添加额外的功能。动态代理的...
1. **JDK动态代理**:Spring在没有CGLIB库的情况下,会使用Java的反射API创建动态代理。动态代理类会实现目标接口,并在调用接口方法时插入通知。因此,使用JDK动态代理的目标类必须实现至少一个接口。 2. **CGLIB...
Spring AOP允许我们通过代理来实现横切关注点,如日志、事务管理等,而JDK动态代理则是Spring AOP实现的一种方式。本文将深入探讨Spring如何利用JDK动态代理技术来实现这一功能,并通过实例解析其底层实现。 首先,...
在Spring框架中,当我们的目标对象实现了至少一个接口时,Spring默认会使用JDK动态代理来实现面向切面编程(AOP)。通过调用`Proxy.newProxyInstance()`方法,我们可以传入目标接口、InvocationHandler和类加载器来...
Spring AOP主要通过动态代理机制实现,根据目标对象是否实现了接口,它会使用JDK动态代理或CGLIB代理。当目标对象是接口类型时,Spring会使用JDK的Proxy类生成一个实现了该接口的代理对象;若目标对象没有接口,...
在 Spring 中,AOP 的实现主要依赖于代理模式,有两种代理方式:JDK 动态代理和 CGLIB 动态代理。 JDK 动态代理是基于接口的,它要求被代理的目标对象必须实现至少一个接口。Spring 使用 `java.lang.reflect.Proxy`...
你可能会看到如何通过Spring AOP自定义代理类,以及如何利用JDK动态代理和CGLIB来拦截并增强方法的执行。 3. **第六章_cache-demo.zip**:此示例可能进一步扩展了缓存相关的实现,包括不同类型的缓存策略、缓存更新...
Spring AOP支持不同的代理策略,包括JDK动态代理和CGLIB代理。如果被代理的类没有实现接口,Spring AOP会采用CGLIB来生成代理对象。CGLIB(Code Generation Library)是一个开源的代码生成库,它允许运行时在内存中...
Spring AOP提供了两种代理方式:JDK动态代理和CGLIB代理。JDK动态代理用于目标对象实现接口的情况,而CGLIB代理则用于目标对象没有实现接口的情况。Spring默认使用JDK动态代理,但如果目标对象没有实现接口,它会...
在"通过Configuration文件实现AOP.docx"文档中,可能会详细讲述如何在Spring配置文件中配置AOP代理,包括如何选择使用JDK动态代理还是CGLIB。 总结来说,JDK动态代理简单且高效,适合接口驱动的设计,而CGLIB适用于...
本篇文章将探讨如何通过JDK动态代理实现Spring AOP的基础知识。 首先,我们要理解什么是JDK动态代理。在Java中,动态代理机制允许我们在运行时创建一个实现了特定接口的新类。这个新类的实例可以代理目标对象,执行...