SpringAOPソース解析の実行編
91867 ワード
注意事項を読む Springソースバージョン:4.3.8 文章の中で/*/注釈を使う方法は深く分析することができます.
本文
前の記事で分析したSpring AOPエージェントの作成過程において、JDKダイナミックエージェントにはもう一つの重要な役割がInvocationHandlerであり、代理人を作成する時にthisが入ってきました.だから、JdkDynamicAopProxyは必ずInvocationHandlerインターフェースを実現し、そのinvoke方法を分析したと確信します.
本文
前の記事で分析したSpring AOPエージェントの作成過程において、JDKダイナミックエージェントにはもう一つの重要な役割がInvocationHandlerであり、代理人を作成する時にthisが入ってきました.だから、JdkDynamicAopProxyは必ずInvocationHandlerインターフェースを実現し、そのinvoke方法を分析したと確信します.
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Class<?> targetClass = null;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
return equals(args[0]); // equals
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
return hashCode(); // hashCode
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
return AopProxyUtils.ultimateTargetClass(this.advised); // DecoratingProxy
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
// expose-proxy this
if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
target = targetSource.getTarget();
if (target != null) {
targetClass = target.getClass();
}
/* */
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
if (chain.isEmpty()) { //
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
/* */
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();
}
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
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()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
AopContext.setCurrentProxy(oldProxy);
}
}
}
AdviedSupport:public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, 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;
}
DefaultAdvisor ChanFactory:public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, Class<?> targetClass) {
List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
for (Advisor advisor : config.getAdvisors()) {
if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
/* */
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
if (mm.isRuntime()) {
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));
}
}
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
DefaultAdvisoorAdapterRegistry:public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3);
Advice advice = advisor.getAdvice();
if (advice instanceof MethodInterceptor) {
interceptors.add((MethodInterceptor) advice);
}
/* */
for (AdvisorAdapter adapter : this.adapters) {
if (adapter.supportsAdvice(advice)) {
//
interceptors.add(adapter.getInterceptor(advisor));
}
}
if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
}
return interceptors.toArray(new MethodInterceptor[interceptors.size()]);
}
DefaultAdvisoorAdapterRegistry:private final List<AdvisorAdapter> adapters = new ArrayList<AdvisorAdapter>(3);
public DefaultAdvisorAdapterRegistry() {
registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
registerAdvisorAdapter(new AfterReturningAdviceAdapter());
registerAdvisorAdapter(new ThrowsAdviceAdapter());
}
DefaultAdvisor AdapterRegistry初期化時に3つのアダプターを初期化しました.ここではMethodBefore Advice Adviceを例にして、@Before注解に対応して作成されたadviceのアダプターです.public MethodInterceptor getInterceptor(Advisor advisor) {
MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
return new MethodBeforeAdviceInterceptor(advice);
}
ここではブースターを方法ブロックに封入しました.次にブロックチェーンの呼び出しを見てみます.Reflective MethodInvocation:public Object proceed() throws Throwable {
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint(); //
}
//
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
//
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
// ,
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
return proceed();
}
}
else {
/* this */
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
ここでは私たちはちょうど似合うMethodBefore Adviice Interceptorを例にとってブロックの実行過程を分析します.public Object invoke(MethodInvocation mi) throws Throwable {
/* before */
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
return mi.proceed(); //
}
ここではまずブロックのbefore方法を実行して、上記のプロceed方法を再度実行して、次のブロッキング方法の呼び出しを行います.ここでのadviceは候補ブースターを取得した時に発生したAsppectJMethodBeforAdviceです.public void before(Method method, Object[] args, Object target) throws Throwable {
/* */
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
AbstractAspectJAdvice:protected Object invokeAdviceMethod(JoinPointMatch jpMatch, Object returnValue, Throwable ex) throws Throwable {
/* */
return invokeAdviceMethodWithGivenArgs(argBinding(getJoinPoint(), jpMatch, returnValue, ex));
}
AbstractAspectJAdvice:protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
Object[] actualArgs = args;
if (this.aspectJAdviceMethod.getParameterTypes().length == 0) {
actualArgs = null;
}
try {
ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
//
return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
}
catch (IllegalArgumentException ex) {
throw new AopInvocationException("Mismatch on arguments to advice method [" +
this.aspectJAdviceMethod + "]; pointcut expression [" +
this.pointcut.getPointcutExpression() + "]", ex);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
ここのaspectJAdvice Methodは私達のアプリケーションの中で@Beforeの注釈の方法です.私達はもう一つ@Afterコメント対応のadviceを見にきました.実行すれば、AspectJAfter Adviceをロックします.public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
finally {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
Finallyブロックにおいてブロッキング方法を実行したということです.つまり@After注解の方法は目標方法の実行後に実行されることが分かりました.CGLOIBエージェントの方式を見てみます.ここでは、CGLOIBとその作成代理の方式を知る読者が必要です.CglibAopProxy:public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());
}
try {
Class<?> rootClass = this.advised.getTargetClass();
Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
Class<?> proxySuperClass = rootClass;
if (ClassUtils.isCglibProxyClass(rootClass)) {
proxySuperClass = rootClass.getSuperclass();
Class<?>[] additionalInterfaces = rootClass.getInterfaces();
for (Class<?> additionalInterface : additionalInterfaces) {
this.advised.addInterface(additionalInterface);
}
}
validateClassIfNecessary(proxySuperClass, classLoader);
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
enhancer.setSuperclass(proxySuperClass);
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
/* */
Callback[] callbacks = getCallbacks(rootClass);
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
/* */
return createProxyClassAndInstance(enhancer, callbacks);
}
catch (CodeGenerationException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of class [" +
this.advised.getTargetClass() + "]: " +
"Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (IllegalArgumentException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of class [" +
this.advised.getTargetClass() + "]: " +
"Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (Throwable ex) {
throw new AopConfigException("Unexpected AOP exception", ex);
}
}
CglibAopProxy:private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
boolean exposeProxy = this.advised.isExposeProxy();
boolean isFrozen = this.advised.isFrozen();
boolean isStatic = this.advised.getTargetSource().isStatic();
/* DynamicAdvisedInterceptor */
Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
Callback targetInterceptor;
if (exposeProxy) {
targetInterceptor = isStatic ?
new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource());
}
else {
targetInterceptor = isStatic ?
new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
new DynamicUnadvisedInterceptor(this.advised.getTargetSource());
}
Callback targetDispatcher = isStatic ?
new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp();
Callback[] mainCallbacks = new Callback[] {
aopInterceptor,
targetInterceptor,
new SerializableNoOp(),
targetDispatcher, this.advisedDispatcher,
new EqualsInterceptor(this.advised),
new HashCodeInterceptor(this.advised)
};
Callback[] callbacks;
if (isStatic && isFrozen) {
Method[] methods = rootClass.getMethods();
Callback[] fixedCallbacks = new Callback[methods.length];
this.fixedInterceptorMap = new HashMap<String, Integer>(methods.length);
for (int x = 0; x < methods.length; x++) {
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass);
fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
this.fixedInterceptorMap.put(methods[x].toString(), x);
}
callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);
this.fixedInterceptorOffset = mainCallbacks.length;
}
else {
callbacks = mainCallbacks;
}
return callbacks;
}
ここでは、インターロックチェーンをDynamicAdviedInterceptorに封入し、Callbackに加入しました.DynamicAdvided Interceptorは、CGLOIBのMethodInterceptorを実現しました.そのコアロジックはintercept方法の中にあります.CglibAopProxy.DynamicAdvided Interceptor:public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Class<?> targetClass = null;
Object target = null;
try {
if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
target = getTarget();
if (target != null) {
targetClass = target.getClass();
}
//
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
//
retVal = methodProxy.invoke(target, argsToUse);
}
else {
//
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null) {
releaseTarget(target);
}
if (setProxyContext) {
AopContext.setCurrentProxy(oldProxy);
}
}
}
ここではJDKダイナミックエージェントと同じブロックチェーンを取得する過程を見ました.また、CglibMethodInvocationはJDKダイナミックエージェントで見たReflectveMethodInvocationを引き継いでいます.しかし、そのプロシージャー方法を書き換えていません.実行目標方法の論理アルバムを書き直しましたので、全体的には大同小異です.CglibAopProxy:protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
enhancer.setInterceptDuringConstruction(false);
enhancer.setCallbacks(callbacks);
return (this.constructorArgs != null ?
enhancer.create(this.constructorArgTypes, this.constructorArgs) :
enhancer.create());
}
ここに来て、Spring全体の動的なAOPのソースコードは分析済みで、Springはまだ静的なAOPを支持しています.