拦截器和拦截器链
本文中的拦截器是使用 JDK 动态代理来实现的
前文须知:JDK的动态代理☆★☆
1. 拦截器
invoke
方法中真实对象调用
method.invoke()
之前或之后加上拦截器,这样就会起到拦截作用。
Interceptor
,我们需要把拦截的处理逻辑都放在这里边,为了简单起见,我们这里只有一个简单的打印信息的方法:
package com.eric.proxy;
public interface Interceptor {
void printInfo();
}
接着我们来设计一个拦截器的实现类,InterceptorImpl.java
:
package com.eric.proxy;
public class InterceptorImpl implements Interceptor {
@Override
public void printInfo() {
System.out.println("执行拦截器中的方法");
}
}
invoke
方法中,由此我们需要稍微修改一下
JDKProxy.java
的内容。我们可以把设置拦截器设计的更灵活一点,在使用动态代理时选择使用拦截器,也可以选择不使用拦截器,下面我们来看一下修改后的内容:
package com.eric.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKProxy implements InvocationHandler {
private Object target;
// 定义拦截器,使用全限定名
private String interceptorClass;
public JDKProxy(Object target, String interceptorClass) {
this.target = target;
this.interceptorClass = interceptorClass;
}
// 绑定带有拦截器的代理对象
public static Object bind(Object target, String interceptorClass) {
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), new JDKProxy(target, interceptorClass));
}
// 绑定不带有拦截器的代理对象
public static Object bind(Object target) {
return JDKProxy.bind(target, null);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 如果未设置拦截器,则直接返回原方法调用
if (interceptorClass == null) {
return method.invoke(target, args);
}
// 否则就是使用了拦截器
Interceptor interceptor = (Interceptor) Class.forName(interceptorClass).newInstance();
// 则先执行拦截器之中的处理逻辑
interceptor.printInfo();
// 然后执行原方法调用或者由拦截器决定不执行原方法的调用
return method.invoke(target, args);
// 原方法调用后也可以再次使用拦截器进行结果处理
}
}
interceptorClass
、构造方法、重载的
bind
方法,另外在
invoke
中也成功使用了拦截器。下面我们来一个一个分析一下:
私有变量 interceptorClass
:它是字符串类型,用来存储某个具体拦截器的全限定名称,这样就可以利用反射机制构建出其实例对象并使用。构造方法:为两个成员变量赋值。 bind
方法:这里设计了两个重载的bind
方法:bind(Object target, String interceptorClass)
方法是为真实对象绑定代理对象,同时使用拦截器,需要提供具体的拦截器全限定名;bind(Object target)
方法则是为真实对象绑定代理对象,并不使用拦截器。修改后的 invoke
方法:在方法中新增了处理逻辑,首先需要判断是否使用了拦截器,如果没有使用,则直接返回真实对象的方法调用;如果使用了拦截器,则首先利用反射构建出拦截器实例,然后再处理拦截器中的处理逻辑,最后由拦截器再决定是否要返回真实对象中的方法调用,这样就实现了拦截器的过滤作用。
package com.eric.proxy;
public class JDKProxyTest {
public static void main(String[] args) {
System.out.println("设置拦截器的代理执行结果:");
// 生成指定拦截器的代理对象
SayHello proxy = (SayHello) JDKProxy.bind(new SayHelloImpl(), "com.eric.proxy.InterceptorImpl");
proxy.sayHello("Eric");
System.out.println("\n不设置拦截器的执行结果:");
// 生成未设置拦截器的代理对象
proxy = (SayHello) JDKProxy.bind(new SayHelloImpl());
proxy.sayHello("Jack");
}
}
执行结果:
设置拦截器的代理执行结果:
执行拦截器中的方法
Hello Eric不设置拦截器的执行结果:
Hello Jack
2. 拦截器链
Interceptor
创建多个实现类,如下:
InterceptorImpl2.java
package com.eric.proxy;
public class InterceptorImpl2 implements Interceptor {
@Override
public void printInfo() {
System.out.println("执行拦截器2");
}
}
InterceptorImpl3.java
package com.eric.proxy;
public class InterceptorImpl3 implements Interceptor {
@Override
public void printInfo() {
System.out.println("执行拦截器3");
}
}
package com.eric.proxy;
public class JDKProxyTest {
public static void main(String[] args) {
System.out.println("设置拦截器链,执行结果:");
// 设计具有拦截器链的代理,注意每个bind方法中的真实对象的改变
SayHello proxy = (SayHello) JDKProxy.bind(new SayHelloImpl(),
"com.eric.proxy.InterceptorImpl");
SayHello proxy2 = (SayHello) JDKProxy.bind(proxy,
"com.eric.proxy.InterceptorImpl2");
SayHello proxy3 = (SayHello) JDKProxy.bind(proxy2,
"com.eric.proxy.InterceptorImpl3");
// 由最终的代理进行调用方法
proxy3.sayHello("Eric");
}
}
执行结果:
设置拦截器链,执行结果:
执行拦截器3
执行拦截器2
执行拦截器中的方法
Hello Eric
new SayHelloImpl()
对象生成了一个使用
InterceptorImpl
拦截器的代理对象
proxy
,然后我们又对此代理对象
proxy
继续使用
InterceptorImpl2
拦截器生成代理对象
proxy2
,最终再生成
proxy2
的代理对象
proxy3
,它使用的是
InterceptorImpl3
拦截器。执行的时候,需要由最外层的代理也就是
proxy3
先调用接口方法,然后再一层代理一层代理的往里执行,最后执行真实对象中的方法,其执行结果也就如上所示。
「分享、点赞、在看」
文章转载自CoderGeshu,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。