什么是拦截器?有什么作用(应用)?
简单点说就是对执行方法请求的拦截,即在执行请求方法前做相应的拦截逻辑处理。
当对象A的a1方法调用B的b1方法时,使用某种技术(大部分是通过代理proxy),使其先调用某个其他方法,然后再去调用b1方法。
拦截器的实现原理是啥?怎么自定义拦截器?
技术原理
大部分是通过代理方式实现的,代理又分 静态代理 、动态代理(大部分)。
动态代理的基础是反射。
自定义拦截器
1.拦截器类Interceptor
public interface Interceptor {
boolean before(Object proxy, Object target, Method method, Object[] args);
void around(Object proxy, Object target, Method method, Object[] args);
void after(Object proxy, Object target, Method method, Object[] args);
}
public class LoginInterceptor implements Interceptor {
@Override
public boolean before(Object proxy, Object target, Method method, Object[] args) {
System.out.println(method.getName() + "\tbefore: do something");
return true; // or false
}
@Override
public void around(Object proxy, Object target, Method method, Object[] args) {
System.out.println(method.getName() + "\taround:do something");
}
@Override
public void after(Object proxy, Object target, Method method, Object[] args) {
System.out.println(method.getName() + "\tafter:do something");
}
}
2. 代理类Proxy
public class InterceptorJdkProxy implements InvocationHandler {
private Object target; // 代理目标
private Class interceptorClass; // 拦截器类
/**
* 构造器 - 指定拦截目标和拦截器
*
* @param target
* @param interceptorClass
*/
public InterceptorJdkProxy(Object target, Class interceptorClass) {
this.target = target;
this.interceptorClass = interceptorClass;
}
/**
* 绑定代理目标对象 和 拦截器类
* @param target
* @param interceptorClass
* @return
*/
public static Object bind(Object target, Class interceptorClass) {
return Proxy.newProxyInstance( target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InterceptorJdkProxy(target, interceptorClass));
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/*拦截器未指定 直接执行 不作拦截*/
if (interceptorClass == null){
return method.invoke(target, args);
}
/* 反射生成拦截器对象*/
Interceptor interceptor = (Interceptor)interceptorClass.newInstance();
/*拦截器前置方法*/
if (interceptor.before(proxy, target,method,args)){
/*拦截器环绕方法*/
interceptor.around(proxy, target,method,args);
}
/*拦截器后置方法*/
interceptor.after(proxy, target,method,args);
return method.invoke(target, args);
}
}
3. 测试
public interface UserLoginService {
boolean doLogin(User user);
boolean doLoginVersion2(User user);
}
public class Test {
public static void main(String[] args) throws Throwable {
UserLoginService userLoginService = (UserLoginService)
InterceptorJdkProxy.bind(new UserLoginServiceImpl(), LoginInterceptor.class);
userLoginService.doLogin(new User());
userLoginService.doLoginVersion2(new User());
}
深究
JDK动态代理和CGLib动态代理
拦截器栈
Spring web拦截器