利用JAVA的动态属性之反射原理实现一个简单AOP容器 - AOP的实现原理分析

AOP:Aspect Oriented Programming,意为面向切面/局部的程序设计。它是面向对象的程序设计的一种延伸。

本文试图通过使用Java本身的动态属性,来实现一个具有简单的AOP功能的容器。

开始理解起来可能比较费劲,但我们可以通过一个通俗说明来这样理解AOP的概念,就是使用AOP可以不用修改原有的代码,而可以追加新的功能。

比如,我们用AOP实现了用户登陆(判断ID与密码是否正确)功能,现在我们要求在用户登陆时用LOG记录用户登陆的情况。一般的做法是直接修改已有的登陆逻辑代码,但使用AOP,可以不用修改原有的代码而完成此功能。

本文试图通过使用Java本身的动态代理功能,来实现一个具有简单的AOP功能的容器。从而帮助大家对AOP有个大概的认识。

Java动态代理功能

首 先,我们简单介绍一下Java动态代理功能。JAVA的动态代理功能主要通过java.lang.reflect.Proxy类与 java.lang.reflect.InvocationHandler接口完成,这里正是通过它们实现一个简单的AOP容器的。其实,像JBoss AOP等其他动态AOP框架也都是通过Proxy和InvocationHandler来实现的。

  • Java从JDK1.3开始提供动态代理(Java Proxy)功能。
  • 所谓动态代理,即通过代理类:Proxy的代理,接口和实现类之间可以不直接发生联系,而可以在运行期(Runtime)实现动态关联。
  • AOP(Aspect Oriented Programming):面向切面编程,其中的一种实现方法便是用Proxy来实现的。
  • Java Proxy只能代理接口,不能代理类。
  • Java Proxy功能主要通过java.lang.reflect.Proxy类与java.lang.reflect.InvocationHandler接口实现。
  • java.lang.reflect.Proxy (代理类) > ProxyInterface(被代理的接口)> InvocationHandler(关联类)> Class(可以在InvocationHandler中被调用)。它们之间的关系可以用下面的流程图来表示:
动态代理类:Proxy 《利用JAVA的动态属性之反射原理实现一个简单AOP容器 - AOP的实现原理分析》 被代理的接口《利用JAVA的动态属性之反射原理实现一个简单AOP容器 - AOP的实现原理分析》 InvocationHandler实现类《利用JAVA的动态属性之反射原理实现一个简单AOP容器 - AOP的实现原理分析》 代理类

实际上的调用关系可以用下面的流程图来表示:

Proxy.newProxyInstance
《利用JAVA的动态属性之反射原理实现一个简单AOP容器 - AOP的实现原理分析》
XxxxInterface xx = $ProxyN(N=0,1,2…)
《利用JAVA的动态属性之反射原理实现一个简单AOP容器 - AOP的实现原理分析》
XxxxInterface.calledMethod
《利用JAVA的动态属性之反射原理实现一个简单AOP容器 - AOP的实现原理分析》
$ProxyN.calledMethod
《利用JAVA的动态属性之反射原理实现一个简单AOP容器 - AOP的实现原理分析》
InvocationHandler.invoke
《利用JAVA的动态属性之反射原理实现一个简单AOP容器 - AOP的实现原理分析》
method.invoke(obj, args)
《利用JAVA的动态属性之反射原理实现一个简单AOP容器 - AOP的实现原理分析》
obj.calledMethod
  1. Proxy. newProxyInstance的参数:必须传送以下3个参数给Proxy. newProxyInstance方法:ClassLoader,Class[],InvocationHandler。其中参数2为被代理的接口 Class,参数3为实现InvocationHandler接口的实例。
  2. 可以通过Proxy. newProxyInstance方法得到被代理的接口的一个实例(instance),该实例由newProxyInstance方法动态生成,并实现了该接口。
  3. 当程序显示调用接口的方法时,其时是调用该实例的方法,此方法又会调用与该实例相关联InvocationHandler的invoke方法。
  4. 这样我们可以在InvocationHandler.invoke方法里调用某些处理逻辑或真正的逻辑处理实现类。

用Java Proxy实现AOP容器

面我们使用Java Proxy来实现一个简单的AOP容器。

文件列表:

文件名说明
AopInvocationHandlerImpl.java该类实现了java.lang.reflect.InvocationHandler接口,我们通过它记录LOG信息
AopContainer.java简单的AOP容器,通过它把IDoBusiness与AopInvocationHandlerImpl关联起来
IDoBusiness.java逻辑处理接口
DoBusiness.java逻辑处理实现类
TestAop.java测试类

简单的AOP容器:

《利用JAVA的动态属性之反射原理实现一个简单AOP容器 - AOP的实现原理分析》AopContainer.java

package com.test.aop.framework;

import java.lang.reflect.Proxy;

/**
* A Simple AOP Container
*
*/

public class AopContainer {
public static <T> T getBean(Class<T> interfaceClazz, final T obj) {
assert interfaceClazz.isInterface();

return (T) Proxy.newProxyInstance(interfaceClazz.getClassLoader(),
new Class[] { interfaceClazz }, new AopInvocationHandlerImpl(obj));
}

public static Object getBean( final Object obj) {
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(), new AopInvocationHandlerImpl(obj));
}
}

第一个getBean方法通过2个参数(第一个参数为被代理的接口,第二个参数为被代理的类实例)

第二个getBean方法只有一个参数,就是类的实例。该类必须实现1个以上的接口。本文的例子并没有使用到该方法,所以这里顺便介绍一下它的使用方法。比如有一个类HelloWorld实现了接口IHelloWorld1和IHelloWorld2,那么可以通过

HelloWorld helloWorld = new HelloWorld();
IHelloWorld1 helloWorld1 = (IHelloWorld1)AopContainer.getBean(helloWorld);
//或
IHelloWorld2 helloWorld2 = (IHelloWorld2)AopContainer.getBean(helloWorld);

调用。当然很多时候都不会直接用new HelloWorld()生成HelloWorld实例,这里为了简便,就直接用new生成HelloWorld实例了。

实现InvocationHandler接口的中间类:

《利用JAVA的动态属性之反射原理实现一个简单AOP容器 - AOP的实现原理分析》AopInvocationHandlerImpl.java

package com.test.aop.framework;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class AopInvocationHandlerImpl implements InvocationHandler {
private Object bizPojo;

public AopInvocationHandlerImpl(Object bizPojo) {
this.bizPojo = bizPojo;
}

/*
* (non – Javadoc)
*
* @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object,
*java.lang.reflect.Method, java.lang.Object[])
*/

public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object o = null;
try {
System.out.println(“Start:” + method.getName());
o = method.invoke(bizPojo, args);
System.out.println(“End:” + method.getName());
} catch (Exception e) {
e.printStackTrace();
System.out.println(“Exception Occured!” + e.getMessage());
// excetpion handling.
}
return o;
}
}

AopInvocationHandlerImpl.invoke方法的第一个参数为代理类,在我们这个例子里为 java.lang.reflect.Proxy类的一个实例。第二个参数Method,为被代理的接口的方法调用(实际上是自动生成代理类的方法调 用),第三个方法为方法调用的参数。

我们通过在AopInvocationHandlerImpl.invoke方法里的method.invoke(bizPojo, args)来调用bizPojo类的与被代理接口的同名方法。这里,bizPojo必须实现了被代理的接口。

在我们的例子里,我们在实际上被调用的业务逻辑方法的前后输出了日志信息。

实际上的逻辑处理类。该类实现了被代理的接口:IDoBusiness。

《利用JAVA的动态属性之反射原理实现一个简单AOP容器 - AOP的实现原理分析》DoBusiness.java

package com.test.aop.framework;

/**
* A business class
*
*/

public class DoBusiness implements IDoBusiness {
public void printNothing() {
System.out.println(“Just Say Hello!“);
}

public void throwException() {
throw new RuntimeException(“throw Exception from DoBusiness.throwException()“);
}

}

被代理的接口定义:

《利用JAVA的动态属性之反射原理实现一个简单AOP容器 - AOP的实现原理分析》IDoBusiness.java

package com.test.aop.framework;

/**
* interface for business logic process
*
*/

public interface IDoBusiness {
public void printNothing();
public void throwException();
}

测试类:

《利用JAVA的动态属性之反射原理实现一个简单AOP容器 - AOP的实现原理分析》TestAop.java

package com.test.aop.framework;

/**
* Test AOP
*
*/

public class TestAop {

/**
* @param args
*/

public static void main(String[] args) {
DoBusiness doBusiness = new DoBusiness();
IDoBusiness idoBusiness = AopContainer.getBean(IDoBusiness.class, doBusiness);
idoBusiness.printNothing();

idoBusiness.throwException();
}

}

总结:

本文通过Java Proxy实现了一个简单地AOP容器。也简单地展示了AOP的基本实现原理,实际上可以以此为基础实现一个功能完善的AOP容器。

    原文作者:AOP
    原文地址: https://blog.csdn.net/xiang_fu/article/details/84154933
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞