上一篇中我们使用接口方式,利用虚函数动态绑定机制实现了一个代理模式,来进行方法的拦截(AOP)处理。
本篇换成使用JDK内置的方式来进行方法(AOP)拦截
- 同前篇,定义IGreet接口:
package blf_aop_demo;
/*
1. 从java语言的角度来演示aop的两种实现(基于接口实现和基于类实现)
2. spring
*/
public interface IGreet {
void sayHello(String name);
void sayGoodBye(String name);
}
- 同前篇,实现IGreet接口:
package blf_aop_demo;
public class GreetImp implements IGreet {
public void sayHello(String name) {
System.out.println("Hello " + name);
}
public void sayGoodBye(String name) {
System.out.println("GoodBye " + name);
}
}
- 不同前篇,而是实现JDK中的java.lang.reflect.InvocationHandler接口:
package blf_aop_demo;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
//JDKProxy
public class ReflectGreetProxy implements InvocationHandler {
//注意: 这里使用了Object类型,提升到java类结构体系的最高层
//java中一切都是Object,万物之源!
private Object target;// 真实的,被代理的对象
// 私有够着方法,用于限制new出本对象
// 只能被下面的工厂方法使用
private ReflectGreetProxy(Object target) {
this.target = target;
}
public static Object newInstance(Object obj) {
//使用Proxy静态方法
//Proxy是java reflect包中的一个静态类(全部是静态方法)
//Proxy作用是利用反射,自动生成target类的代理类一切必要的内容
//很关键一点,obj.getClass().getInterfaces(),意味着使用JDK中的反射Proxy只能基于接口继承的对象
return java.lang.reflect.Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),
new ReflectGreetProxy(obj));
}
// Method method:調用的方法
// Object[] args:方法要傳入的參數
// invoke实现对GreetImpl中方法的调用,同时也可以在这里加入自己想要实现的操作
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
Object result;
try
{
//自定義的處理
System.out.println("--before method " + method.getName());
//調用GreetImpl中方法
result = method.invoke(target, args);
}catch(InvocationTargetException e)
{
throw e.getTargetException();
}catch(Exception e)
{
throw new RuntimeException("unexpected invocation exception: " + e.getMessage());
}finally
{
System.out.println("--after method " + method.getName());
}
return result;
}
}
4.测试代码:
public static void testReflectGreet(){
//生成一个真实对象
IGreet real = new GreetImp();
//从真实对象生成一个代理对象
IGreet greet = (IGreet)ReflectGreetProxy.newInstance(real);
//此时调用的是代理对象上的say系列方法
//代理对象内部会调用public Object invoke(Object proxy, Method method, Object[] args)
//对其所有方法进行拦截
greet.sayHello("jackyBu");
greet.sayGoodBye("jackyBu");
}
public static void main(String[] args) {
System.out.println("blf_aop_demo_test");
testReflectGreet();
}
- 测试结果:
blf_aop_demo_test
--before method sayHello
Hello jackyBu
--after method sayHello
--before method sayGoodBye
GoodBye jackyBu
--after method sayGoodBye
-
我们会看到,代理对象会对真实对象的所有方法进行拦截,如果我有选择性的拦截,那就可以通过过滤被拦截方法的名称就可以了,例如你只想拦截sayHello,而不想拦截sayGoodBye,则进行方法名判定就可以了。
-
相对于自己实现,使用JDK反射Proxy方式更加简单,特别是在真实对象有很多方法时,优势就显示出来了
-
唯一的限制:
很关键一点,obj.getClass().getInterfaces(),意味着使用JDK中的反射Proxy只能代理基于接口继承的对象
JDK代理要求被代理的类必须实现接口,有很强的局限性
从上面这句注释可以了解到,jdk反射Proxy只能对接口进行方法拦截,不能对类的方法进行拦截
下一篇我们来解决如何实现类的动态代理
网友评论