directorio de origen primavera AOP
Primavera AOP Fuente 01: Jdk proxy dinámico para la fuente subyacente
de primavera AOP Fuente 02: el ProxyFactory
primavera AOP Fuente 03: JdkDynamicAopProxy
primavera AOP Fuente 04: llamada MethodInvocation interceptor
primavera AOP Fuente 05: El DefaultAdvisorAutoProxyCreator
la primavera final de la pregunta del examen final: Cuando primavera AOP se reunió dependencias circulares
notas dirección de origen git: https: //github.com/chaitou/spring-framework-master.git
prefacio
A continuación, la unión segundo resorte AOP la fuente núcleo ProxyFactory , hay primavera AOP dinámico modo de generación de proxy 2, cuando los implementos objeto proxy la interfaz y no está obligado a utilizar la configuración cglib代理
se utiliza cuando JdkDynamicAopProxy
la generación de agente. A la inversa utilizado CglibAopProxy
para generar el proxy. En el primer capítulo proxy dinámico para la fuente subyacente Jdk conocido, agente dinámico Jdk por getProxy
la generación simultánea de un proxy, $proxy
el objeto proxy al llamar al método, se callback invoke
método. Así que para JdkDynamicAopProxy
, el código más importante es el análisis getProxy
y invoke
métodos. En cuanto a la agente generador de código fuente subyacente, un primer artículo se ha introducido, sin más explicaciones
análisis de código fuente
getProxy
El siguiente código en el primer capítulo Jdk proxy dinámico para el código fuente subyacente que escribió de nuevo manualmente, y luego ir por aquí
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
// 获取代理接口
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
// 判断接口是否又hashCode和equals方法
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// 使用JDK代理(classLoader, 接口, 当前JdkDynamicAopProxy对象:用于回调invoke和target对象方法)
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
classLoader
: El cargador de clases actualproxiedInterfaces
: La matriz actual de interfaces implementadas por la clase de proxythis
: El objeto de la auto-generado para la clase de proxy, las propiedades del agente como h, h propiedad se utiliza para desencadenar el método de devolución de llamadah.invoke
método para mejorada
invocar
En el principio invoke
antes de que el primer punto de referencia a un objetivo, con el fin de aprovechar el tronco, sólo está interesado en el tema 普通增强
, 引介增强
y así se saltará el otro un capítulo aparte a explicar, por lo que se encuentran con 引介增强
tal de ser el primero no pueden enredar
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
// 获取代理目标对象
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
// equals方法处理
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
// hashCode处理
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
// Advised接口或者其父接口中定义的方法,直接反射调用
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
// 目标对象内部调用是无法实现增强的,如果exposeProxy设置为true,需要暴露代理
// ThreadLocal<Object> currentProxy
// 对象是ThreadLocal,在finally后会清除currentProxy
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
// 以防target来自对象池,所以在创建代理前调用get获取target
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// Get the interception chain for this method.
// 1. 获取拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
// 拦截器为空,直接调用切点方法
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
// 2. 将拦截器统一封装成ReflectiveMethodInvocation
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
// 3. 执行拦截器链
retVal = invocation.proceed();
}
// Massage return value if necessary.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
// 如果自定义了TargetSource,释放target资源池由子类实现
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
1. Obtener cadena interceptor
Este método toma toda la corriente method
a juego advice
(mejora), el seguimiento getInterceptorsAndDynamicInterceptionAdvice
se encuentra código para ser utilizado caché primavera AOP para mejorar el rendimiento, si el proceso se ha adquirido a través del interceptor ha podido recuperar amortiguar directamente, o mediante advisorChainFactory
la adquisición de cadena interceptor
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
MethodCacheKey cacheKey = new MethodCacheKey(method);
// 从缓存中获取
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
// 获取拦截器链
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
// 设置缓存
this.methodCache.put(cacheKey, cached);
}
return cached;
}
Continuar con el getInterceptorsAndDynamicInterceptionAdvice
método
// DefaultAdvisorChainFactory.java
public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, @Nullable Class<?> targetClass) {
// This is somewhat tricky... We have to process introductions first,
// but we need to preserve order in the ultimate list.
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
Advisor[] advisors = config.getAdvisors();
List<Object> interceptorList = new ArrayList<>(advisors.length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
Boolean hasIntroductions = null;
// 循环所有切面
for (Advisor advisor : advisors) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
// 校验当前Advisor是否适用于当前对象
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
boolean match;
// 校验Advisor是否应用到当前方法上
if (mm instanceof IntroductionAwareMethodMatcher) {
if (hasIntroductions == null) {
hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
}
match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
}
else {
match = mm.matches(method, actualClass);
}
// 匹配成功
if (match) {
// 从advisor中获取拦截器数组
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
for (MethodInterceptor interceptor : interceptors) {
// 添加动态拦截器
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
// 添加普通拦截器
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
// 引介增强
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
// 其他类型的advisor
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
...
}
Corte transversal 引介增强
, 动态增强
que se preocupan 普通拦截器
. El código completo es un pensamiento muy claro, obtener toda la Advisor
(corte) a través de pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)
partidos Asesor comprobar el objeto proxy actual, y luego por pointcutAdvisor.getPointcut().getMethodMatcher()
la verificación de que coincide con la llamada actual method
. Si la comprobación después extrayendo advisor
el interceptors
interceptor, añadido a interceptorList
la
2. interceptor encapsula en ReflectiveMethodInvocation
Llamar a un constructor, centrándose en la siguiente llamada
protected ReflectiveMethodInvocation(
Object proxy, @Nullable Object target, Method method, @Nullable Object[] arguments,
@Nullable Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {
this.proxy = proxy;
this.target = target;
this.targetClass = targetClass;
this.method = BridgeMethodResolver.findBridgedMethod(method);
this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);
this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
}
3. Realizar la cadena interceptor
// 执行拦截器链
retVal = invocation.proceed();
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
// 动态匹配
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
// 不匹配,则跳过
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
// 普通拦截器,直接触发
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
Del mismo modo, sólo nos importa 普通拦截器
, pero vemos 普通拦截器
una sola línea de código
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
Esta línea de código puede hacer que los interceptores de acuerdo con el antes, después y orden definido por el usuario, incluso Orden se encadenó llamadas, esto es increíble, ¿verdad? La siguiente sección se distinguirá AspectJAfterAdvice
y MethodBeforeAdviceInterceptor
ordenó llamado interceptor antes de la investigación es cómo mejorar y método