Spring源代碼解析(四):Spring AOP獲取Proxy
下面我們來看看Spring的AOP的一些相關(guān)代碼是怎么得到Proxy的,讓我們我們先看看AOP和Spring AOP的一些基本概念:Advice:
通知,制定在連接點做什么,在Sping中,他主要描述Spring圍繞方法調(diào)用注入的額外的行為,Spring提供的通知類型有:
before advice,AfterReturningAdvice,ThrowAdvice,MethodBeforeAdvice,這些都是Spring AOP定義的接口類,具體的動作實現(xiàn)需要用戶程序來完成。
Pointcut:
切點,其決定一個advice應(yīng)該應(yīng)用于哪個連接點,也就是需要插入額外處理的地方的集合,例如,被某個advice作為目標的一組方法。Spring pointcut通常意味著標示方法,可以選擇一組方法調(diào)用作為pointcut,Spring提供了具體的切點來給用戶使用,比如正則表達式切點 JdkRegexpMethodPointcut通過正則表達式對方法名進行匹配,其通過使用 AbstractJdkRegexpMethodPointcut中的對MethodMatcher接口的實現(xiàn)來完成pointcut功能:
- public final boolean matches(Method method, Class targetClass) {
- //這里通過放射得到方法的全名
- String patt = method.getDeclaringClass().getName() + "." + method.getName();
- for (int i = 0; i < this.patterns.length; i++) {
- // 這里是判斷是否和方法名是否匹配的代碼
- boolean matched = matches(patt, i);
- if (matched) {
- for (int j = 0; j < this.excludedPatterns.length; j++) {
- boolean excluded = matchesExclusion(patt, j);
- if(excluded) {
- return false;
- }
- }
- return true;
- }
- }
- return false;
- }
在JDKRegexpMethodPointcut中通過JDK中的正則表達式匹配來完成pointcut的最終確定:
- protected boolean matches(String pattern, int patternIndex) {
- Matcher matcher = this.compiledPatterns[patternIndex].matcher(pattern);
- return matcher.matches();
- }
Advisor:
當我們完成額外的動作設(shè)計(advice)和額外動作插入點的設(shè)計(pointcut)以后,我們需要一個對象把他們結(jié)合起來,這就是通知器 - advisor,定義應(yīng)該在哪里應(yīng)用哪個通知。Advisor的實現(xiàn)有:DefaultPointcutAdvisor他有兩個屬性advice和 pointcut來讓我們配置advice和pointcut。
接著我們就可以通過ProxyFactoryBean來配置我們的代理對象和方面行為,在ProxyFactoryBean中有interceptorNames來配置已經(jīng)定義好的通知器-advisor,雖然這里的名字叫做interceptNames,但實際上是供我們配置advisor的地方,具體的代理實現(xiàn)通過JDK 的Proxy或者CGLIB來完成。因為ProxyFactoryBean是一個FactoryBean,在ProxyFactoryBean中我們通過getObject()可以直接得到代理對象:
- public Object getObject() throws BeansException {
- //這里初始化通知器鏈
- initializeAdvisorChain();
- if (isSingleton()) {
- //根據(jù)定義需要生成單件的Proxy
- return getSingletonInstance();
- }
- else {
- .......
- //這里根據(jù)定義需要生成Prototype類型的Proxy
- return newPrototypeInstance();
- }
- }
我們看看怎樣生成單件的代理對象:
- private synchronized Object getSingletonInstance() {
- if (this.singletonInstance == null) {
- this.targetSource = freshTargetSource();
- if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
- // 這里設(shè)置代理對象的接口
- setInterfaces(ClassUtils.getAllInterfacesForClass(this.targetSource.getTargetClass()));
- }
- // Eagerly initialize the shared singleton instance.
- super.setFrozen(this.freezeProxy);
- // 注意這里的方法會使用ProxyFactory來生成我們需要的Proxy
- this.singletonInstance = getProxy(createAopProxy());
- // We must listen to superclass advice change events to recache the singleton
- // instance if necessary.
- addListener(this);
- }
- return this.singletonInstance;
- }
- //使用createAopProxy放回的AopProxy來得到代理對象。
- protected Object getProxy(AopProxy aopProxy) {
- return aopProxy.getProxy(this.beanClassLoader);
- }
ProxyFactoryBean的父類是AdvisedSupport,Spring使用AopProxy接口把AOP代理的實現(xiàn)與框架的其他部分分離開來;在AdvisedSupport中通過這樣的方式來得到AopProxy,當然這里需要得到AopProxyFactory的幫助 - 下面我們看到Spring為我們提供的實現(xiàn),來幫助我們方便的從JDK或者cglib中得到我們想要的代理對象:
- protected synchronized AopProxy createAopProxy() {
- if (!this.isActive) {
- activate();
- }
- return getAopProxyFactory().createAopProxy(this);
- }
而在ProxyConfig中對使用的AopProxyFactory做了定義:
- //這個DefaultAopProxyFactory是Spring用來生成AopProxy的地方,
- //當然了它包含JDK和Cglib兩種實現(xiàn)方式。
- private transient AopProxyFactory aopProxyFactory = new DefaultAopProxyFactory();
其中在DefaultAopProxyFactory中是這樣生成AopProxy的:
- public AopProxy createAopProxy(AdvisedSupport advisedSupport) throws AopConfigException {
- //首先考慮使用cglib來實現(xiàn)代理對象,當然如果同時目標對象不是接口的實現(xiàn)類的話
- if (advisedSupport.isOptimize() || advisedSupport.isProxyTargetClass() ||
- advisedSupport.getProxiedInterfaces().length == 0) {
- //這里判斷如果不存在cglib庫,直接拋出異常。
- if (!cglibAvailable) {
- throw new AopConfigException(
- "Cannot proxy target class because CGLIB2 is not available. " +
- "Add CGLIB to the class path or specify proxy interfaces.");
- }
- // 這里使用Cglib來生成Proxy,如果target不是接口的實現(xiàn)的話,返回cglib類型的AopProxy
- return CglibProxyFactory.createCglibProxy(advisedSupport);
- }
- else {
- // 這里使用JDK來生成Proxy,返回JDK類型的AopProxy
- return new JdkDynamicAopProxy(advisedSupport);
- }
- }
于是我們就可以看到其中的代理對象可以由JDK或者Cglib來生成,我們看到JdkDynamicAopProxy類和Cglib2AopProxy都實現(xiàn)的是AopProxy的接口,在JdkDynamicAopProxy實現(xiàn)中我們可以看到Proxy是怎樣生成的:
- public Object getProxy(ClassLoader classLoader) {
- if (logger.isDebugEnabled()) {
- Class targetClass = this.advised.getTargetSource().getTargetClass();
- logger.debug("Creating JDK dynamic proxy" +
- (targetClass != null ? " for [" + targetClass.getName() + "]" : ""));
- }
- Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
- findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
- //這里我們調(diào)用JDK Proxy來生成需要的Proxy實例
- return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
- }
這樣用Proxy包裝target之后,通過ProxyFactoryBean得到對其方法的調(diào)用就被Proxy攔截了, ProxyFactoryBean的getObject()方法得到的實際上是一個Proxy了,我們的target對象已經(jīng)被封裝了。對 ProxyFactoryBean這個工廠bean而言,其生產(chǎn)出來的對象是封裝了目標對象的代理對象。