@
사용자 정의 인터셉터를 가지고하지 않은 경우, 당신은 나의 볼 수 있습니다 이전 기사를 . 당신은 JDK 동적 프록시를 사용하는 방법을 모르는 경우,이 볼 수있는 기사를 . 책임의 디자인 패턴의 체인이 이해하기 매우 간단합니다, 당신은 예를 찾을 수 온라인으로 볼 수 있습니다.
mybatis
달성하기 위해 동적 에이전트 및 책임의 체인을 사용하는 원리 플러그.
어느 한 방법을 인터셉트 할
에서 앞에 말했다, 당신은 코멘트 수 Intecepts
와 Signature
어떤 방법 차단을 지정할 수 있습니다. 그러나, 모든 방법이 차단 될 수 있음을 의미하지 않는다.
메소드의 MyBatis 인터셉터는 다음과 같은 종류가 있습니다, 가로 :
1. Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
2. ParameterHandler (getParameterObject, setParameters)
3. ResultSetHandler (handleResultSets, handleOutputParameters)
4. StatementHandler (prepare, parameterize, batch, update, query)
왜 이러한 방법을 가로 챌 수있다?
에서 mybatis
위의 여러 클래스입니다 SqlSession
네 개의 객체. SqlSession
이러한 개체는 데이터베이스, 처리 결과의 조작에 의해 달성된다. 따라서, 그 과정에서, 방법은 이러한 개체를 차단하는 매우 중요한 역할이다.
그리고이 소스 코드에 반영됩니다에서 Configuration
클래스,이 클래스의 중요성이 너무 많은 설명을하지 않는다, 당신은 이전 기사를 볼 수 있습니다.
XML은 총에 구문 분석 Configuration
과정, 몇 가지 새로운 클래스 이상이 필요. 상기는 몇 가지 클래스에 다시 호출 interceptorChain#pluginAll
하는 방법.
이 방법은 에이전트
public class InterceptorChain {
/**
* 拦截器列表
*/
private final List<Interceptor> interceptors = new ArrayList<>();
public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target);
}
return target;
}
/**
* 添加拦截器
*
* @param interceptor
*/
public void addInterceptor(Interceptor interceptor) {
interceptors.add(interceptor);
}
/**
* 获取拦截器列表
*
* @return
*/
public List<Interceptor> getInterceptors() {
return Collections.unmodifiableList(interceptors);
}
}
이 인터셉터는 모든 호출을 알 수있다 plugin
에이전트의 마지막 층 후 프록시 개체를 반환하는 방법을. 여기에 에이전트의 층에주의를 기울이십시오.
A, B, C 세 인터셉터 (동일한 서명),이 경우, 층이 봉입되어있는 경우. 실행될 때, 마지막으로는 A> B> C> target.proceed ()> C> B> A.이며
3 프록시 객체
InterceptorChain
각 인터셉터는 호출 plugin
방법. 이 방법은 해당 프록시 개체를 반환합니다.
/**
* 拦截器接口
*
* @author Clinton Begin
*/
public interface Interceptor {
/**
* 执行拦截逻辑的方法
*
* @param invocation 调用信息
* @return 调用结果
* @throws Throwable 异常
*/
Object intercept(Invocation invocation) throws Throwable;
/**
* 代理
*
* @param target
* @return
*/
Object plugin(Object target);
/**
* 根据配置来初始化 Interceptor 方法
* @param properties
*/
void setProperties(Properties properties);
}
어떤 plugin
우리가 달성해야 할 것입니다. 의 MyBatis는 매우 편리한 방법으로 우리를 제공합니다.
public static Object wrap(Object target, Interceptor interceptor) {
// 获取类型及对应的方法信息
Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
Class<?> type = target.getClass();
// 获取所有需要拦截的接口
Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
if (interfaces.length > 0) {
// 创建代理对象
return Proxy.newProxyInstance(
type.getClassLoader(),
interfaces,
new Plugin(target, interceptor, signatureMap));
}
return target;
}
우리가 방법을 플러그인 재 작성하는 경우, 단순히 위의 방법이 될 수 호출합니다. 그것은 반환 Plugin
이 클래스의 객체를.
public class Plugin implements InvocationHandler
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
// 获取方法所在类中, 可以被拦截的所有的方法
Set<Method> methods = signatureMap.get(method.getDeclaringClass());
// 如果需要被拦截, 则调用 interceptor.intercept
if (methods != null && methods.contains(method)) {
return interceptor.intercept(new Invocation(target, method, args));
}
// 没有被拦截则正常调用
return method.invoke(target, args);
} catch (Exception e) {
throw ExceptionUtil.unwrapThrowable(e);
}
}
JDK 동적 프록시 이후 인터페이스 레벨이다. 따라서, 에이전트 클래스 인터페이스의 모든 메소드가. 그러나 모든 방법은 노트에있는 정보에 의해 서명 프로세스를 구분하기 때문에, 프록시 할 수 있습니다.
책임의 디자인 패턴의 4 체인
플러그에 사용하는 과정에서, 책임 디자인 패턴의 체인 깊이 에이전트 향상 중첩 동적 프록시에 반영된다. 에 반영 interceptorChain#pluginAll
하는 방법. 그것은 프록시 층에 호출합니다. 원리의 MyBatis 플러그 - 책임과 동적 프록시의 체인을 반영