- 拦截器的由来
由于动态代理比较难理解, 所以一般都会将他封装为一个接口来使用, 即拦截器, 开发者只要知道拦截器的接口方法、含义和作用即可, 无需知道动态代理的代码是如何实现的。
- 代码实现
包结构如下
我们用JDK动态代理来实现一个拦截器的逻辑, 为此先定义拦截器接口Interceptor, 如下
Interceptor.java
package interceptor;
import java.lang.reflect.Method;
public interface Interceptor {
public boolean before(Object proxy, Object target, Method method, Object[] args);
public void around(Object proxy, Object target, Method method, Object[] args);
public void after(Object proxy, Object target, Method method, Object[] args);
}
定义了三个方法, before, around, after, 含义如下
- 三个参数为: proxy 代理对象, target 真实对象, method 代理方法, args 代理方法的参数列表
- before 返回 boolean 值, 他在真实对象被代理前调用. 为 true 时, 则反射真实的对象方法, 反之则反射around 方法
- 在 before 方法返回 false 的情况下, 调用 around 方法
- 在反射方法, 或者 around 方法执行后, 调用 after 方法
新建 MyInterceptor 类并实现 Interceptor 接口
MyInterceptor.java
package interceptor;
import java.lang.reflect.Method;
public class MyInterceptor implements Interceptor {
@Override
public boolean before(Object proxy, Object target, Method method, Object[] args) {
System.out.println("反射方法前逻辑..");
return true; // 不反射被代理对象的原有方法
}
@Override
public void around(Object proxy, Object target, Method method, Object[] args) {
System.out.println("取代了被代理对象的方法..");
}
@Override
public void after(Object proxy, Object target, Method method, Object[] args) {
System.out.println("反射方法后的逻辑...");
}
}
使用 JDK 动态代理, 并在适当时调用接口逻辑, 新建 InterceptorJdkProxy 类
InterceptorJdkProxy .java
package interceptor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class InterceptorJdkProxy implements InvocationHandler {
private Object target; // 真实对象
private String interceptorClass = null; // 拦截器的全限定名
public InterceptorJdkProxy(Object target, String interceptorClass)
{
this.target = target;
this.interceptorClass = interceptorClass;
}
/**
* 绑定委托对象并返回一个代理
*
* @param target 真实对象
* @param interceptorClass 拦截器类全路径名
* @return 代理对象
*/
public static Object bind(Object target, String interceptorClass)
{
// 取得代理对象
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InterceptorJdkProxy(target, interceptorClass));
}
/**
* 通过代理对象进入方法, 首先进入这个方法
*
* @param proxy 代理对象
* @param method 方法, 真实对象被调用的方法
* @param args 方法的参数
* @throws Throwable 异常
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (interceptorClass == null) {
return method.invoke(target, args);
}
Object result = null;
// 通过反射生成拦截器
Interceptor interceptor = (Interceptor) Class.forName(interceptorClass).newInstance();
// 调用前置方法
if (interceptor.before(proxy, target, method, args)) {
// 反射原有对象方法
result = method.invoke(target, args);
} else { // 返回 false 执行 around 方法
interceptor.around(proxy, target, method, args);
}
// 调用后置方法
interceptor.after(proxy, target, method, args);
return result;
}
}
这里有两个属性, 一个是 target 真实对象, 另一个是字符串 interceptorClass, 它是一个拦截器的全路径名。代理的步骤如下:
- 在 bind 方法中使用 JDK 动态代理绑定了一个对象, 然后返回代理对象
- 如果没有设置拦截器, 则直接反射真实对象的方法, 然后结束, 否则执行第三步
- 通过反射实例化拦截器, 并准备使用它
- 调用拦截器的 before 方法, 如果返回 true, 反射原来的方法, 反之运行拦截器的 around 方法
- 调用拦截器的 after 方法
- 返回结束
工作流程如下图
创建真实对象的方法接口 Say
Say.java
package interceptor;
public interface Say {
void sayHello(String hello);
}
创建真实对象并实现方法接口
Hello.java
package interceptor;
public class Hello implements Say{
@Override
public void sayHello(String name) {
System.out.println("Hello: " + name);
}
}
新建测试类 Test
Test.java
package interceptor;
public class Test {
public static void main(String[] args)
{
Say proxy = (Say) InterceptorJdkProxy.bind(new Hello(), "interceptor.MyInterceptor");
proxy.sayHello("123");
}
}
- 程序运行效果如下
- 拦截器的好处
- 开发者只需要知道拦截器的作用就可以编写拦截器了
- 设计者只会把拦截器的接口暴露给开发者, 让动态代理的逻辑在开发者的视野中消失