Spring AOP的實現與設計

1、代理對象是怎麼生成的

ProxyFactoryBean是SpringAOP實現的核心,先經過代碼使用ProxyFactoryBean完成一次AOP調用java

public class App {
    public static void main(String[] args) {

        //1.建立ProxyFactoryBean,用以建立指定對象的Proxy對象
        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();

        proxyFactoryBean.setInterfaces(TicketService.class);
        proxyFactoryBean.setTarget(new RailwayStation());
        proxyFactoryBean.setProxyTargetClass(true);

        //2.添加Advice攔截器
        proxyFactoryBean.addAdvice(new TicketServiceAfterReturningAdvice());
        proxyFactoryBean.addAdvice(new TicketServiceAroundAdvice());
        proxyFactoryBean.addAdvice(new TicketServiceBeforeAdvice());
        proxyFactoryBean.addAdvice(new TicketServiceThrowsAdvice());

        //3.獲取代理對象
        TicketService ticketService = (TicketService)proxyFactoryBean.getObject();
        ticketService.sellTicket();
    }
}

public class RailwayStation implements TicketService {
    @Override
    public void sellTicket() {
        System.out.println("售票............");
    }

    @Override
    public void inquire() {
        System.out.println("查詢............");
    }

    @Override
    public void withdraw() {
        System.out.println("退票............");
    }
}

public interface TicketService {
    //售票
    void sellTicket();

    //問詢
    void inquire();

    //退票
    void withdraw();
}

分別建立Before、AfterReturn、Around、Throw四個Advice數據結構

public class TicketServiceAfterReturningAdvice implements AfterReturningAdvice {
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("AFTER_RETURNING:本次服務已結束....");
    }
}

public class TicketServiceAroundAdvice implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("AROUND_ADVICE:BEGIN....");
        Object returnValue = invocation.proceed();
        System.out.println("AROUND_ADVICE:END.....");
        return returnValue;
    }
}

public class TicketServiceBeforeAdvice implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("BEFORE_ADVICE: 歡迎光臨代售點....");
    }
}

public class TicketServiceThrowsAdvice implements ThrowsAdvice {
    public void afterThrowing(Exception ex) {
        System.out.println("AFTER_THROWING....");
    }

    public void afterThrowing(Method method, Object[] args, Object target, Exception ex) {
        System.out.println("afterThrowing調用過程出錯啦!!!!!");

    }
}

運行結果以下:ide

使用過程當中主要圍繞ProxyFactoryBean,從類圖中發現它繼承了AdvisedSupport,AdvisedSupport數據結構以下:ui

  • List<Advisor> advisors:Advice集合,若是執行 proxyFactoryBean.addAdvice(afterReturningAdvice); afterReturningAdvice會被包裝成Advisor添加進來。
  • List<Class<?>> interfaces:代理集合,代理對象須要實現的接口,對應proxyFactoryBean.setInterfaces(TicketService.class)
  • TargetSource targetSource:對TargetClass對象的封裝,對應 proxyFactoryBean.setTarget(railwayStation)

經過ProxyFactoryBean配置完接口、真正被調用目標、Advice以後,使用proxyFactoryBean.getObject()生成代理對象,關鍵步驟是getProxy(createAopProxy())this

【ProxyFactoryBean】
private synchronized Object getSingletonInstance() {
		if (this.singletonInstance == null) {
			this.targetSource = freshTargetSource();
			if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
				// Rely on AOP infrastructure to tell us what interfaces to proxy.
				Class<?> targetClass = getTargetClass();
				if (targetClass == null) {
					throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
				}
				setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
			}
			// Initialize the shared singleton instance.
			super.setFrozen(this.freezeProxy);
            //建立CglibProxy 或 JdkProxy
			this.singletonInstance = getProxy(createAopProxy());
		}
		return this.singletonInstance;
	}

createAopProxy()具體作了什麼呢,主要涉及到DefaultAopProxyFactory 、ObjenesisCglibAopProxy、JdkDynamicAopProxy、AopProxyFactory結合工廠+單例模式完成。spa

獲取到具體的AopProxy以後,再經過aopProxy.getProxy執行準備工做,例如把Advice轉換成MethodInterceptor等。3d

2、Advice鏈(即攔截器鏈)的構造過程以及執行機制

JdkDynamicAopProxy 和CglibAopProxy只是建立代理方式的兩種方式而已,實際上咱們爲方法調用添加的各類Advice的執行邏輯都是統一的。在Spring的底層,會把咱們定義的各個Adivce分別包裹成一個 MethodInterceptor,這些Advice按照加入Advised順序,構成一個AdivseChain。代理

例如示例代碼中添加四個Advice,在CglibProxy中分別使用AfterReturningAdviceAdapter、MethodBeforeAdviceAdapter、ThrowsAdviceAdapter.getInterceptor(Advisor advisor)包裝成新的MethodInterceptor。因爲TicketServiceAroundAdvice繼承了MethodInterceptor,因此不用適配。例如ThrowsAdviceAdaptercode

class ThrowsAdviceAdapter implements AdvisorAdapter, Serializable {

	@Override
	public boolean supportsAdvice(Advice advice) {
		return (advice instanceof ThrowsAdvice);
	}

	@Override
	public MethodInterceptor getInterceptor(Advisor advisor) {
		return new ThrowsAdviceInterceptor(advisor.getAdvice());
	}

}

再看看每一個攔截器作了什麼。對象

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;
	}
 
	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		//在調用方法以前,先執行BeforeAdvice
		this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
		return mi.proceed();
	}
}

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;
	}
 
	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		//先調用invocation
		Object retVal = mi.proceed();
		//調用成功後,調用AfterReturningAdvice
		this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
		return retVal;
	}
}
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; 

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		//使用大的try,先執行代碼,捕獲異常
		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();
		}
	}
 
}

每一個攔截器會在不一樣時刻執行本身的攔截邏輯,依據上圖的攔截器順序(After——Around——Before——Throw),圖示說明調用關係。

3、pointcut是如何工做的

若是隻想攔截某個方法,能夠手動建立PointcutAdvisor

//手動建立一個pointcut,專門攔截inquire方法
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("execution( * inquire(..))");
proxyFactoryBean.addAdvisor(new FilteredAdvisor(pointcut,beforeAdvice));

private static class FilteredAdvisor implements PointcutAdvisor {
        private Pointcut pointcut;
        private Advice advice;

        public FilteredAdvisor(Pointcut pointcut, Advice advice) {
            this.pointcut = pointcut;
            this.advice = advice;
        }

        @Override
        public Pointcut getPointcut() {
            return pointcut;
        }

        @Override
        public Advice getAdvice() {
            return advice;
        }

        @Override
        public boolean isPerInstance() {
            return false;
        }
    }

Spring處理該PointcutAdvisor是在DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice方法中

首先會獲取FilterAdvisor裏PointCut的MethodMatcher,這裏包含"execution( * inquire(..))"表達式,和入參裏的method比較是否一致,因爲TicketService有sellTicket、inquire、withdraw,因此MethodMatcher會比較三次,只有inquire能經過,組裝成一個InterceptorAndDynamicMethodMatcher,交給ReflectiveMethodInvocation。因此只有執行inquire方法會出現before攔截,其餘方法正常執行。

相關文章
相關標籤/搜索