`
dragonxiangfu
  • 浏览: 156381 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

java动态代理实现AOP

 
阅读更多
java在java.lang.reflect中有自己的代理支持。利用这个类可以在运行时动态创建一个代理类,实现一个或多个接口,并将方法的调用转发到你指定的类。因为实际的代理类是在运行时创建的,我们称之为:动态代理。

下面是一个简单示意图:



RealSub是需要被代理的类。Proxy就是代理类。他们必须实现相同的接口。并且代理类中包含被代理的实例。工作时,客户端获得的是代理类的实例。调用接口中定义的方法时会去调用Proxy的具体方法。Proxy再通过自己内部的RealSub实例调用被代理类的方法。也就是说实际工作的还是RealSub类的实例。当然在RealSub实例方法调用的前后可以加一些用户定制的行为(例如可以输出一下日志)。这就是简单的AOP。

java已经为你创建了Proxy类,所以你要有办法来告诉Proxy类需要为你做什么。你不能像以前一样把代码放在proxy类中,因为它不是你直接实现的。这时我们的代码需要放在InvocationHander类中。InvocationHander类是自己的继承InvocationHander接口的实现类。它的工作是相应代理的任何调用。我们可以把InvocationHander想象成代理收到方法调用时,请求做实际工作的对象。实际上调用的对象行就是invoke()方法。

下面是一个来自网上的完整实例代码:

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class HelloAop {

public static void main(String[] args) {

Before before = new Before() {
public void before() {
System.out.println("...before...");
}
};

After after = new After() {
public void after() {
System.out.println("...after...");
}
};

Hello hello = null;

// 普通方法执行
System.out.println("-------------普通执行-------------");
hello = new HelloEnglish();
hello.sayHello("baybay");
hello.sayHi("baybay");
System.out.println();

// 切入方法执行前(前置增强)
System.out.println("-------------前置增强-------------");
hello = ProxyFactory.getHelloProxy(new HelloEnglish(), before);
// hello = ProxyFactory.getHelloProxy(new HelloChinese(), before);
hello.sayHello("baybay");
hello.sayHi("baybay"); // sayHi 方法没有标注 @Enhancement 所以不会进行代码切入

// 切入方法执行后(后置增强)
System.out.println("-------------后置增强-------------");
hello = ProxyFactory.getHelloProxy(new HelloEnglish(), after);
hello.sayHello("baybay");
hello.sayHi("baybay");
System.out.println();

// 切入方法执行前和执行后(环绕增强)
System.out.println("-------------环绕增强-------------");
hello = ProxyFactory.getHelloProxy(new HelloEnglish(), before, after);
hello.sayHello("baybay");
hello.sayHi("baybay");
System.out.println();
}
}

@Retention(RetentionPolicy.RUNTIME) //注释(Annotation)保留在class file,VM会进行处理
@interface Enhancement {
}

interface Hello {
@Enhancement
public void sayHello(String name);
public void sayHi(String name);
}

class HelloChinese implements Hello {
public void sayHello(String name) {
System.out.println(name + ",您好");
}
public void sayHi(String name) {
System.out.println("你好," + name);
}
}

class HelloEnglish implements Hello {
public void sayHello(String name) {
System.out.println("Hello, " + name);
}
public void sayHi(String name) {
System.out.println("hi, " + name);
}
}

class ProxyFactory {
private ProxyFactory(){
}

public static Hello getHelloProxy(Hello hello, Before before) {
return getHelloProxy(hello, before, null);
}

public static Hello getHelloProxy(Hello hello, After after) {
return getHelloProxy(hello, null, after);
}

public static Hello getHelloProxy(Hello hello, Before before, After after) {
HelloHandler handler = new HelloHandler();
if(before != null) {
handler.setBefore(before);
}
if(after != null) {
handler.setAfter(after);
}
return handler.bind(hello);
}
}

/**
* 前置增强接口
*/
interface Before {
public void before();
}

/**
* 后置增强接口
*/
interface After {
public void after();
}

class HelloHandler implements InvocationHandler {

/**
* 需要进行代理的实例
*/
private Hello hello = null;

/**
* 前置增强
*/
private Before before = null;

/**
* 后置增强
*/
private After after = null;

/**
* InvocationHandler 接口的实现方法,进行动态代理
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// 看看接口中方法是否标注了需要 Enhancement
boolean b = method.isAnnotationPresent(Enhancement.class);
if(!b){
// 没有标注的话,按原方法执行
return method.invoke(hello, args);
}
// 有标注的话,进行方法的前置和后置增强
if(before != null) {
before.before();
}
Object obj = method.invoke(hello, args);
if(after != null) {
after.after();
}
return obj;
}

/**
* 将传入的 Hello 与 InvocationHandler 进行绑定,以获得代理类的实例
* @param hello
* @return
*/
public Hello bind(Hello hello) {
this.hello = hello;
Hello helloProxy = (Hello)Proxy.newProxyInstance(
hello.getClass().getClassLoader(),
hello.getClass().getInterfaces(),
this
);
return helloProxy;
}

public void setAfter(After after) {
this.after = after;
}

public void setBefore(Before before) {
this.before = before;
}
}



分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics