Spring切面AOP目標類被多次代理導致通知被多次執行

1.首先寫了一個環繞通知

package com.nstc.aims.interceptor;

import java.io.PrintStream;
import java.lang.reflect.Method;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class EntityHistoryInterceptor
  implements MethodInterceptor
{
  public Object invoke(MethodInvocation methodInvocation)
    throws Throwable
  {
    Method method = methodInvocation.getMethod();
    System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
    System.out.println(methodInvocation.toString());
    System.out.println(Integer.toHexString(methodInvocation.hashCode()));
    System.out.println(method.getDeclaringClass());
    System.out.println(method.toString());
    System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
    String methodName = method.toGenericString();
    String xmlName = methodName.substring(methodName.lastIndexOf(" ") + 1);
    System.out.println(xmlName);
    
    Object object = methodInvocation.proceed();
    return object;
  }
}

配置文件,由於公司使用的是Spring1.2.9,配置文件沒有aop標籤。:

	<bean
		class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
		<property name="beanNames">
			<list>
				<value>AIMS.accountBasicSetService</value>
				<value>AIMS.accountService</value>
				<value>AIMS.associateBankService</value>
				<value>AIMS.associateBankService</value>
				<value>AIMS.accountBalanceService</value>
				<value>AIMS.accountRecordService</value>
				<value>AIMS.bizFlowService</value>
				<value>AIMS.bp3CallBackService</value>
				<value>AIMS.bp3ConnectService</value>
				<value>AIMS.commonService</value>
				<value>AIMS.umFormService</value>
				<value>AIMS.accountSynchroService</value>
				<value>AIMS.cfbRemoteService</value>
				<value>AIMS.attachService</value>
				<value>AIMS.recordMouldService</value>
			</list>
		</property>
		<property name="interceptorNames">
			<list>
 				<value>AIMS.transactionInterceptor</value> //這個是公司原有的配置
 				<value>AIMS.entityHistoryAdvisor</value> //這個是我加的切面
			</list>
		</property>
	</bean>

執行結果如圖:

原因是:

Proxy$285代理了Bean,Proxy$286代理了Proxy$285,我寫的切面代理了Proxy$286,

所以導致執行了三次。

考慮是配置文件使用的spring的bean有問題,於是換了一種實現方式:

	<bean id="AIMS.entityHistoryAdvice" class="com.nstc.aims.interceptor.EntityHistoryInterceptor" />

	<bean id="AIMS.entityHistoryPointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
		<property name="pattern" value=".*RecordMouldService\..*"></property>
	</bean>
	
	<bean id="AIMS.entityHistoryAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
		<property name="pointcut" ref="AIMS.entityHistoryPointcut" />
		<property name="advice" ref="AIMS.entityHistoryAdvice"></property>
	</bean>

結果和一開始一樣,也是被代理了三次,改變位置也沒辦法。

考慮不使用環繞通知,使用後置通知,並且把切面放到最上面試一下。如果不行的話,就要考慮在方法中判斷target了。

Interceptor:

public class EntityHistoryAfterAdvice implements AfterReturningAdvice {

    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
        System.out.println(target);
    }
}

配置文件

	<bean
		class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
		<property name="beanNames">
			<list>
				<value>AIMS.accountBasicSetService</value>
				<value>AIMS.accountService</value>
				<value>AIMS.associateBankService</value>
				<value>AIMS.associateBankService</value>
				<value>AIMS.accountBalanceService</value>
				<value>AIMS.accountRecordService</value>
				<value>AIMS.bizFlowService</value>
				<value>AIMS.bp3CallBackService</value>
				<value>AIMS.bp3ConnectService</value>
				<value>AIMS.commonService</value>
				<value>AIMS.umFormService</value>
				<value>AIMS.accountSynchroService</value>
				<value>AIMS.cfbRemoteService</value>
				<value>AIMS.attachService</value>
				<value>AIMS.recordMouldService</value>
			</list>
		</property>
		<property name="interceptorNames">
			<list>
 				<value>AIMS.entityHistoryAdvisor</value>
 				<value>AIMS.transactionInterceptor</value>
			</list>
		</property>
	</bean>
	
	
    <bean id="AIMS.entityHistoryAfterAdvice" class="com.nstc.aims.interceptor.EntityHistoryAfterAdvice" />

    <bean id="AIMS.entityHistoryAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <property name="advice">
            <ref bean="AIMS.entityHistoryAfterAdvice" />
        </property>
        <!--指定要代理的方法 -->
        <property name="patterns">
            <value>.*RecordMouldService.*</value>
        </property>
    </bean>

結果:

執行了6次,分析應該是這樣的。應該執行5次,最後多的那一次是最後的代理類的順序導致。

應當把後置通知放到最後,執行了5次。

後面考慮是實現的接口不對:

換成了Cglib的接口MethodInterception,結果直接報錯。

 

代理那個類的方法在本模塊沒有找到,有可能是公司框架的封裝。無權修改。

 

實在沒辦法了,只有去invoke方法中判斷target了。

最終代碼如下:

package com.nstc.aims.interceptor;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.framework.ReflectiveMethodInvocation;

import com.nstc.aims.service.impl.RecordMouldServiceImpl;

/**
 * <p>Title: EntityHistoryAroundAdvice.java</p>
 *
 * <p>Description: 環繞通知</p>
 *
 * <p>Company: 北京九恆星科技股份有限公司</p>
 *
 * @author luhao
 * 
 * @since:2019年6月5日 上午11:59:46
 * 
 */
public class EntityHistoryAroundAdvice implements MethodInterceptor{
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        ReflectiveMethodInvocation reflectiveMethodInvocation = (ReflectiveMethodInvocation) methodInvocation;
        boolean isRealClass = reflectiveMethodInvocation.getThis().getClass() == RecordMouldServiceImpl.class;
        if(!isRealClass)  {
            return methodInvocation.proceed();
        }
        Object[] args = reflectiveMethodInvocation.getArguments();//方法參數
        Object object = methodInvocation.proceed();//方法結果
        return object;
    }
}
	<bean
		class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
		<property name="beanNames">
			<list>
				<value>AIMS.accountBasicSetService</value>
				<value>AIMS.accountService</value>
				<value>AIMS.associateBankService</value>
				<value>AIMS.associateBankService</value>
				<value>AIMS.accountBalanceService</value>
				<value>AIMS.accountRecordService</value>
				<value>AIMS.bizFlowService</value>
				<value>AIMS.bp3CallBackService</value>
				<value>AIMS.bp3ConnectService</value>
				<value>AIMS.commonService</value>
				<value>AIMS.umFormService</value>
				<value>AIMS.accountSynchroService</value>
				<value>AIMS.cfbRemoteService</value>
				<value>AIMS.attachService</value>
				<value>AIMS.recordMouldService</value>
			</list>
		</property>
		<property name="interceptorNames">
			<list>
 				<value>AIMS.transactionInterceptor</value>
 				<value>AIMS.entityHistoryAdvisor</value>
			</list>
		</property>
	</bean>
	
	
    <bean id="AIMS.entityHistoryAdvice" class="com.nstc.aims.interceptor.EntityHistoryAroundAdvice" />

    <bean id="AIMS.entityHistoryAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <property name="advice">
            <ref bean="AIMS.entityHistoryAdvice" />
        </property>
        <!--指定要代理的方法 -->
        <property name="patterns">
            <value>.*RecordMouldService.*</value>
        </property>
    </bean>

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章