手把手教你用java实现aop-亚博电竞手机版

介绍

众所周知,aop(面向切面编程)是spring框架的特色功能之一。通过设置横切关注点(cross cutting concerns),aop提供了极高的扩展性。那aop在spring中是怎样运作的呢?当你只能使用core java,却需要aop技术时,这个问题的解答变得极为关键。不仅如此,在高级技术岗位的面试中,此类问题也常作为考题出现。这不,我的朋友最近参加了一个面试,就被问到了这样一个棘手的问题——如何在不使用spring及相关库,只用core java的条件下实现aop。因此,我将在本文中提供一份大纲,帮助大家了解如何只用core java实现一个aop(当然啦,这种aop在功能上有一定的局限性)。注意,本文不是一篇有关spring aop与java aop的对比研究,而是有关在core java中借助固有的设计模式实现aop的教程。

想必读者已经知道aop是什么,也知道在spring框架中如何使用它,因此本文只着眼于如何在不用spring的前提下实现aop。首先,我们得知道,spring是借助了jdk proxy和cglib两种技术实现aop的。jdk dynamic proxy提供了一种灵活的方式来hook一个方法并执行指定的操作,但执行操作时得有一个限制条件:必须先提供一个相关的接口以及该接口的实现类。实践出真知,让我们透过一个案例来理解这句吧!现在有一个计算器程序,用于完成一些数学运算。让我们来考虑下除法功能,此时的问题是:如果core framework 已经具备了一份实现除法的代码,我们能否在代码执行时劫持(highjack)它并执行额外的校验呢?答案是肯定的,我将用下面提供的代码片段来证明这点。首先来看基础接口的代码:

 public interface calculator {     public int calculate( int a , int b); }

该接口实现类的代码如下:

 public class calculatorimpl implements calculator {     @override     public int calculate(int a, int b) {         return a/b;     } }

假设我们既不能修该上面的代码,也不能对核心库进行任何改动,怎样才能完美地实现校验功能呢?不如试下jdk dynamic proxy的功能吧。

public class somehandler implements invocationhandler {  // code omitted for simplicity…..      @override     public object invoke(object proxy, method method, object[] params) throws throwable { // your complex business validation and logic         object result = method.invoke(targetobject ,params);         return result;     }  }

让我们通过测试类来看看由jdk dynamic proxy实现的校验功能的效果如何。

public static void main(string[] args) {         calculatorimpl calcimpl = new calculatorimpl();         calculator proxied = (calculator)proxyfactory.getproxy (calculator.class, calcimpl,                  new somehandler(calcimpl));         int result = proxied.calculate(20, 10);         system.out.println("final result :::"   result);     }

从结果可以看出,简单地实现功能强大的invocationhandler接口,我们便能得到一个hooking implementation。按照jdk文档的描述,invocationhandler接口是借助一个代理实例(proxy instance)来处理一个方法调用的。

现在我们已经知道,invocationhandler的invoke()方法能够帮助我们解决问题。那么再来解决一个新问题——怎样才能在方法执行的前后执行操作呢?说的更具体一些,我们能通过添加多个aop(before、after、around)来hook一个方法吗(译注:原文为add multiple aops,但我认为handler是充当aspect的角色)?答案同样是肯定的。按照以下的步骤建立一个精简的代码模板便能满足这样的需求:

  1. 创建一个抽象类,用于将aop应用于目标对象上。
  2. 创建名为beforehandler 和 afterhandler的两个aop。前者在方法执行之前工作,而后者则在方法执行结束后工作。
  3. 创建一个代理类,使所有的aop handler和目标对象只需作为参数传入,就能创建一个hook。
  4. 加入你自己的业务逻辑或者横切关注点。
  5. 最后,通过传入相关的参数创建代理对象(proxy object)。

技术实现概要

(译注:此处是核心代码片段,如果想运行该实例,需进入下方提供的链接下载完整代码)

创建一个handler的抽象类:

public abstract class abstracthandler implements invocationhandler {  	private object targetobject;  	public void settargetobject(object targetobject) { 		this.targetobject = targetobject; 	} }

创建名为beforehandler和afterhandler的两个易扩展的handler抽象类:

public abstract class beforehandler extends abstracthandler { 	public abstract void handlebefore(object proxy, method method, object[] args); 	public object invoke(object proxy, method method, object[] args) throws throwable { 		handlebefore(proxy, method, args); 		return method.invoke(gettargetobject(), args); 	} }
public abstract class afterhandler extends abstracthandler { 	public abstract void handleafter(object proxy, method method, object[] args); 	public object invoke(object proxy, method method, object[] args) throws throwable { 		object result = method.invoke(gettargetobject(), args); 		handleafter(proxy, method, args); 		return result; 	} }

创建proxy的工厂类:

public class proxyfactory {  	public static object getproxy(object targetobject, 			list handlers) { 			//code to get the proxy 			return proxyobject; 		} else { 			return targetobject; 		} 	} }

以下为测试代码:

calculatorimpl calcimpl = new calculatorimpl(); beforehandler before = new beforehandlerimpl(); afterhandler after = new afterhandlerimpl(); list handlers = new arraylist(); handlers.add(before); handlers.add(after); calculator proxy = (calculator) proxyfactory.getproxy(calcimpl, 				handlers); int result = proxy.calculate(20, 10);

配置

以上的代码片段简明扼要地解释了aop在结构上的实现(structural implementation)。当然,如果能通过实际的测试将其运用到现实中去,那就再好不过了。读者可在下面的链接中获取完整的工程文件,并在java编辑器中配置它们,最后通过其中的测试类来检验效果。

  • https://github.com/debjava/aopusingjdkdynamicproxy

总结

希望这篇简短的有关aop文章能够帮助到大家。需说明的是,本文只实现了before和after两种aop,而另外两种,即“around”和“throw”,则希望读者自行完成。

展开全文
内容来源于互联网和用户投稿,文章中一旦含有亚博电竞手机版的联系方式务必识别真假,本站仅做信息展示不承担任何相关责任,如有侵权或涉及法律问题请联系亚博电竞手机版删除

最新文章

网站地图