AOP的前世今生之代理模式
1. 概述
什么是代理模式呢???
在不修改原有代码 或是 无法修改原有代码的情况下,增强对象功能,替代原来的对象去完成功能,从而达成了拓展的目的。
先给大家看下 JavaScript中实现方式
直接代理window.open
函数,在调用window.open
之前之后做一些事情
const open = window.open;
window.open = function(...args) {
// before todo
open.call(null, ...args);
// after todo
}
接下来我们看下Java中是如何实现的???
-
JDK 动态代理
JDK Proxy 动态代理面向接口的动态代理 一定要有接口和实现类的存在 代理对象增强的是实现类 在实现接口的方法重写的方法生成的代理对象只能转换成 接口的不能转换成 被代理类
-
gclib 动态代理
面向父类进行动态代理
2. JDK 动态代理
接口定义
public interface Animal {
void eat();
void say();
}
实现类定义
public class Cat implements Animal {
@Override
public void eat() {
System.out.println("猫要吃饭了");
}
@Override
public void say() {
System.out.println("有一个动物 开始说话了");
}
}
接下来我们有一个需求,我要代理eat
方法,但是不代理say
方法。在执行eat
方法之前之后 都要执行对应的逻辑。
public class TestJdkProxy {
@Test
public void testJdkProxy() {
Animal cat = new Cat();
/**
* ClassLoader loader => 通过实例获取Class。 再通过Class来获取对应的loader
* Class<?>[] interfaces => 通过实例获取Class。 再通过Class来获取定义的接口
* InvocationHandler h
*/
Animal animal = (Animal) Proxy.newProxyInstance(cat.getClass().getClassLoader(), cat.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/**
* proxy 被代理的对象
* method 代理的方法
* args 代理传递的参数
*/
Object o;
if (method.getName() == "eat") {
System.out.println("start ----------------");
o = method.invoke(cat, args);
System.out.println("end ----------------");
} else {
o = method.invoke(cat, args);
}
return o;
}
});
animal.eat();
animal.say();
}
}
- 通过代码
Proxy.newProxyInstance
来获取代理后的实例,我们后续调用方法eat
,say
都是基于代理对象的 - 需要获取
getClassLoader
,getInterfaces
我们都可以通过实例.getClass()
来获取 - 最重要的就是要实现接口
InvocationHandler
. 我们一切行为都是基于接口中invoke
的方法。
其实JDK 动态代理核心在于:代理实现类,所以我们在接口中所有需要重写的方法都会被代理,然后我们调用的方法就是代理的方法(其实就是方法invoke
)
3. gclib 动态代理
gclib动态代理
是基于父类来进行动态代理的。其实就是在运行时生成子类,继承提供的父类。 而我们其实我们手动调用的方法是子类的方法,调用时调用父类方法,从而实现代理。
代码实现逻辑
public class TestCgLib {
@Test
public void testCglib() {
Person person = new Person();
// 1. 获取Enhancer 对象
Enhancer enhancer = new Enhancer();
// 2. 设置父类字节码
enhancer.setSuperclass(person.getClass());
// 3. 获取MethodInterceptor对象 用于定义增强规则
MethodInterceptor methodInterceptor = new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
/**
* Object o 生成之后的代理对象
* Method method 父类中原本要执行的方法
* Object[] objects 传递的参数对象
* MethodProxy methodProxy 生成的代理的子类
*/
Object res;
if ("eat".equals(method.getName())) {
System.out.println("准备开始吃饭...");
res = methodProxy.invokeSuper(o, objects);
System.out.println("已经吃饭结束...");
} else {
res = methodProxy.invokeSuper(o, objects);
}
return res;
}
};
// 4. 设置执行代理回调函数
enhancer.setCallback(methodInterceptor);
// 5. 获取代理对象
Person person1 = (Person) enhancer.create();
person1.eat();
person1.say();
}
}
4. 结论
代理模式是学习AOP的基础,所以理解代理模式的作业方式还是很重要的。Demo源码位置