上一篇演示了,Spring得前通知、后通知、环绕通知,仔细想来前通知、后通知和异常通知,都应该是居于环绕通知开发的,想想如果都能控制目标函数是否能执行,那么要在目标函数执行前后,或者目标函数执行过程中发生异常后进行一些处理,那不是太easy了吗?,按照猜想,前通知、后通知,异常通知 应该是重写invoke方法,在invoke方法里面先执行before在执行proceed就是前通知,先执行proceed在执行afterReturning就是后通知,用在try 里面执行invoke方法就是异常通知。我下面来看spring的源码进行验证
- /*
- * Copyright 2002-2007 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.springframework.aop.framework.adapter;
- import java.io.Serializable;
- import org.aopalliance.intercept.MethodInterceptor;
- import org.aopalliance.intercept.MethodInvocation;
- import org.springframework.aop.MethodBeforeAdvice;
- import org.springframework.util.Assert;
- /**
- * Interceptor to wrap am {@link org.springframework.aop.MethodBeforeAdvice}.
- * Used internally by the AOP framework; application developers should not need
- * to use this class directly.
- *
- * @author Rod Johnson
- */
- public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {
- private MethodBeforeAdvice advice;
- /**
- * Create a new MethodBeforeAdviceInterceptor for the given advice.
- * @param advice the MethodBeforeAdvice to wrap
- */
- public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
- Assert.notNull(advice, "Advice must not be null");
- this.advice = advice;
- }
- public Object invoke(MethodInvocation mi) throws Throwable {
- this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
- return mi.proceed();
- }
- }
- /*
- * Copyright 2002-2007 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.springframework.aop.framework.adapter;
- import java.io.Serializable;
- import org.aopalliance.intercept.MethodInterceptor;
- import org.aopalliance.intercept.MethodInvocation;
- import org.springframework.aop.AfterAdvice;
- import org.springframework.aop.AfterReturningAdvice;
- import org.springframework.util.Assert;
- /**
- * Interceptor to wrap am {@link org.springframework.aop.AfterReturningAdvice}.
- * Used internally by the AOP framework; application developers should not need
- * to use this class directly.
- *
- * @author Rod Johnson
- */
- public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {
- private final AfterReturningAdvice advice;
- /**
- * Create a new AfterReturningAdviceInterceptor for the given advice.
- * @param advice the AfterReturningAdvice to wrap
- */
- public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {
- Assert.notNull(advice, "Advice must not be null");
- this.advice = advice;
- }
- public Object invoke(MethodInvocation mi) throws Throwable {
- Object retVal = mi.proceed();
- this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
- return retVal;
- }
- }
- /*
- * Copyright 2002-2007 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.springframework.aop.framework.adapter;
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Method;
- import java.util.HashMap;
- import java.util.Map;
- import org.aopalliance.intercept.MethodInterceptor;
- import org.aopalliance.intercept.MethodInvocation;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import org.springframework.aop.AfterAdvice;
- import org.springframework.util.Assert;
- /**
- * Interceptor to wrap an after-throwing advice.
- *
- * <p>The signatures on handler methods on the <code>ThrowsAdvice</code>
- * implementation method argument must be of the form:<br>
- *
- * <code>void afterThrowing([Method, args, target], ThrowableSubclass);</code>
- *
- * <p>Only the last argument is required.
- *
- * <p>Some examples of valid methods would be:
- *
- * <pre class="code">public void afterThrowing(Exception ex)</pre>
- * <pre class="code">public void afterThrowing(RemoteException)</pre>
- * <pre class="code">public void afterThrowing(Method method, Object[] args, Object target, Exception ex)</pre>
- * <pre class="code">public void afterThrowing(Method method, Object[] args, Object target, ServletException ex)</pre>
- *
- * <p>This is a framework class that need not be used directly by Spring users.
- *
- * @author Rod Johnson
- * @author Juergen Hoeller
- */
- public class ThrowsAdviceInterceptor implements MethodInterceptor, AfterAdvice {
- private static final String AFTER_THROWING = "afterThrowing";
- private static final Log logger = LogFactory.getLog(ThrowsAdviceInterceptor.class);
- private final Object throwsAdvice;
- /** Methods on throws advice, keyed by exception class */
- private final Map exceptionHandlerMap = new HashMap();
- /**
- * Create a new ThrowsAdviceInterceptor for the given ThrowsAdvice.
- * @param throwsAdvice the advice object that defines the exception
- * handler methods (usually a {@link org.springframework.aop.ThrowsAdvice}
- * implementation)
- */
- public ThrowsAdviceInterceptor(Object throwsAdvice) {
- Assert.notNull(throwsAdvice, "Advice must not be null");
- this.throwsAdvice = throwsAdvice;
- Method[] methods = throwsAdvice.getClass().getMethods();
- for (int i = 0; i < methods.length; i++) {
- Method method = methods[i];
- if (method.getName().equals(AFTER_THROWING) &
- //m.getReturnType() == null &&
- (method.getParameterTypes().length == 1 || method.getParameterTypes().length == 4) &
- Throwable.class.isAssignableFrom(method.getParameterTypes()[method.getParameterTypes().length - 1])
- ) {
- // Have an exception handler
- this.exceptionHandlerMap.put(method.getParameterTypes()[method.getParameterTypes().length - 1], method);
- if (logger.isDebugEnabled()) {
- logger.debug("Found exception handler method: " + method);
- }
- }
- }
- if (this.exceptionHandlerMap.isEmpty()) {
- throw new IllegalArgumentException(
- "At least one handler method must be found in class [" + throwsAdvice.getClass() + "]");
- }
- }
- public int getHandlerMethodCount() {
- return this.exceptionHandlerMap.size();
- }
- /**
- * Determine the exception handle method. Can return null if not found.
- * @param exception the exception thrown
- * @return a handler for the given exception type
- */
- private Method getExceptionHandler(Throwable exception) {
- Class exceptionClass = exception.getClass();
- if (logger.isTraceEnabled()) {
- logger.trace("Trying to find handler for exception of type [" + exceptionClass.getName() + "]");
- }
- Method handler = (Method) this.exceptionHandlerMap.get(exceptionClass);
- while (handler == null && !exceptionClass.equals(Throwable.class)) {
- exceptionClass = exceptionClass.getSuperclass();
- handler = (Method) this.exceptionHandlerMap.get(exceptionClass);
- }
- if (handler != null && logger.isDebugEnabled()) {
- logger.debug("Found handler for exception of type [" + exceptionClass.getName() + "]: " + handler);
- }
- return handler;
- }
- public Object invoke(MethodInvocation mi) throws Throwable {
- try {
- return mi.proceed();
- }
- catch (Throwable ex) {
- Method handlerMethod = getExceptionHandler(ex);
- if (handlerMethod != null) {
- invokeHandlerMethod(mi, ex, handlerMethod);
- }
- throw ex;
- }
- }
- private void invokeHandlerMethod(MethodInvocation mi, Throwable ex, Method method) throws Throwable {
- Object[] handlerArgs;
- if (method.getParameterTypes().length == 1) {
- handlerArgs = new Object[] { ex };
- }
- else {
- handlerArgs = new Object[] {mi.getMethod(), mi.getArguments(), mi.getThis(), ex};
- }
- try {
- method.invoke(this.throwsAdvice, handlerArgs);
- }
- catch (InvocationTargetException targetEx) {
- throw targetEx.getTargetException();
- }
- }
- }
通过spring的源码可以确定刚刚的想法。现在明白了前通知和后通知,异常通知是怎么实现的了,但是问题又来了,怎么在我调用业务方法的前去执行invoke方法呢?看来还要继续研究一下^_^