论坛首页 Java企业应用论坛

请问Spring AOP 是否支持嵌套?

浏览 11938 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2006-12-24  
请先看代码
package aop;

public interface SomeService {
	void someMethod();
	void someInnerMethod();
}


package aop;

import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;

public class SomeServiceImpl implements SomeService {
	private static final Logger log = Logger.getLogger(SomeServiceImpl.class);

	protected static ApplicationContext ctx;

	public void someMethod() {
		someInnerMethod();
		log.debug("someMethod");
	}

	public void someInnerMethod() {
		log.debug("someInnerMethod");
	}

}


package aop;

package com.gxlu.srm;

import junit.framework.TestCase;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


public class SomeServiceTest extends TestCase {
	protected void setUp() throws Exception {
		String[] paths = { "classpath:applicationContext-aop.xml" };
		ctx = new ClassPathXmlApplicationContext(paths);
	}
	public void testAop() {
		SomeService someService = (SomeService) ctx.getBean("someService");
		someService.someMethod();
		someService.someInnerMethod();
	}
}





<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
	<bean id="debugInterceptor" class="org.springframework.aop.interceptor.DebugInterceptor"/>
	
	<bean id="someServiceTarget" class="aop.SomeServiceImpl"/>
	
	<bean id="someService" class="org.springframework.aop.framework.ProxyFactoryBean">
	    <property name="proxyInterfaces"><value>aop.SomeService</value></property>
	    <property name="target"><ref local="someServiceTarget"/></property>
	    <property name="interceptorNames">
	    	<list>
	        	<value>someAdvisor</value>
	      	</list>
	    </property>
  </bean>

  <bean id="someAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    	<property name="advice"><ref local="debugInterceptor"/></property>
    	<property name="patterns">
    		<list>
      			<value>aop\.SomeService\.someMethod</value>
      			<value>aop\.SomeService\.someInnerMethod</value>
      		</list>
    	</property>
  </bean>
  
</beans>



log4j.logger.org.springframework.aop=DEBUG
log4j.logger.aop=DEBUG


日志显示
[srm] 2006-12-24 23:06:16.953 < INFO> [main] org.springframework.aop.framework.DefaultAopProxyFactory.<clinit>(61) | CGLIB2 not available: proxyTargetClass feature disabled
[srm] 2006-12-24 23:06:16.984 <DEBUG> [main] org.springframework.aop.framework.ProxyFactoryBean.addInterface(216) | Added new aspect interface: aop.SomeService
[srm] 2006-12-24 23:06:17.015 <DEBUG> [main] org.springframework.aop.framework.ProxyFactoryBean.initializeAdvisorChain(420) | Configuring advisor or advice 'someAdvisor'
[srm] 2006-12-24 23:06:17.015 <DEBUG> [main] org.springframework.aop.framework.ProxyFactoryBean.addAdvisorOnChainCreation(526) | Adding advisor or TargetSource [org.springframework.aop.support.RegexpMethodPointcutAdvisor: advice [org.springframework.aop.interceptor.DebugInterceptor@126804e], pointcut patterns {aop\.SomeService\.someMethod, aop\.SomeService\.someInnerMethod}] with name [someAdvisor]
[srm] 2006-12-24 23:06:17.015 <DEBUG> [main] org.springframework.aop.framework.ProxyFactoryBean.addAdvisorOnChainCreation(535) | Adding advisor with name [someAdvisor]
[srm] 2006-12-24 23:06:17.015 <DEBUG> [main] org.springframework.aop.framework.ProxyFactoryBean.freshTargetSource(549) | Not refreshing target: bean name not specified in interceptorNames
[srm] 2006-12-24 23:06:17.015 <DEBUG> [main] org.springframework.aop.framework.JdkDynamicAopProxy.getProxy(109) | Creating JDK dynamic proxy for [aop.SomeServiceImpl]
[b][color=blue][srm] 2006-12-24 23:06:17.062 <DEBUG> [main] org.springframework.aop.interceptor.DebugInterceptor.invokeUnderTrace(57) | Entering invocation: method 'someMethod', arguments []; target is of class [aop.SomeServiceImpl]; count=1
[srm] 2006-12-24 23:06:17.062 <DEBUG> [main] aop.SomeServiceImpl.someInnerMethod(17) | someInnerMethod
[srm] 2006-12-24 23:06:17.078 <DEBUG> [main] aop.SomeServiceImpl.someMethod(13) | someMethod
[srm] 2006-12-24 23:06:17.078 <DEBUG> [main] org.springframework.aop.interceptor.DebugInterceptor.invokeUnderTrace(60) | Exiting invocation: method 'someMethod', arguments []; target is of class [aop.SomeServiceImpl]; count=1[/color][/b][b][color=red][srm] 2006-12-24 23:06:17.078 <DEBUG> [main] org.springframework.aop.interceptor.DebugInterceptor.invokeUnderTrace(57) | Entering invocation: method 'someInnerMethod', arguments []; target is of class [aop.SomeServiceImpl]; count=2
[srm] 2006-12-24 23:06:17.078 <DEBUG> [main] aop.SomeServiceImpl.someInnerMethod(17) | someInnerMethod
[srm] 2006-12-24 23:06:17.078 <DEBUG> [main] org.springframework.aop.interceptor.DebugInterceptor.invokeUnderTrace(60) | Exiting invocation: method 'someInnerMethod', arguments []; target is of class [aop.SomeServiceImpl]; count=2[/color][/b]


单独进入'someInnerMethod'时 AOP起作用
但通过'someMethod'调用someInnerMethod时为什么没有出现Entering invocation: method 'someInnerMethod'的日志?

是否SpringAOP不支持嵌套?!
   发表时间:2006-12-25  
spring aop 原理上是创建一个 proxy
通过'someMethod'调用someInnerMethod 时是普通的java 函数调用,并不会调用到proxy上,所以aop不起作用

使用aspectJ 的静态织入组件可能会起作用
1 请登录后投票
   发表时间:2006-12-25  
pikachu 写道
spring aop 原理上是创建一个 proxy
通过'someMethod'调用someInnerMethod 时是普通的java 函数调用,并不会调用到proxy上,所以aop不起作用

使用aspectJ 的静态织入组件可能会起作用




同意,cglib是继承原来的类,jdk proxy是继承Proxy类,返回的是一个新的"包装"过的类,但原来Object方法中(super中)的调用还是属于super中的.
0 请登录后投票
   发表时间:2007-04-28  
如果去反编辑一下那些代理类,就什么都明白了,public final class ItestImpProxy extends Proxy
    implements ITest
{

    public ItestImpProxy(InvocationHandler invocationhandler)
    {
        super(invocationhandler);
    }

    public final void test1()
    {
        try
        {
            super.h.invoke(this, m3, null);
            return;
        }
        catch(Error _ex) { }
        catch(Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final String toString()
    {
        try
        {
            return (String)super.h.invoke(this, m2, null);
        }
        catch(Error _ex) { }
        catch(Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final int hashCode()
    {
        try
        {
            return ((Integer)super.h.invoke(this, m0, null)).intValue();
        }
        catch(Error _ex) { }
        catch(Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final void test2()
    {
        try
        {
            super.h.invoke(this, m4, null);
            return;
        }
        catch(Error _ex) { }
        catch(Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final void test3()
    {
        try
        {
            super.h.invoke(this, m5, null);
            return;
        }
        catch(Error _ex) { }
        catch(Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final boolean equals(Object obj)
    {
        try
        {
            return ((Boolean)super.h.invoke(this, m1, new Object[] {
                obj
            })).booleanValue();
        }
        catch(Error _ex) { }
        catch(Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    private static Method m3;
    private static Method m2;
    private static Method m0;
    private static Method m4;
    private static Method m5;
    private static Method m1;

    static
    {
        try
        {
            m3 = Class.forName("reflect.aop.ITest").getMethod("test1", new Class[0]);
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
            m4 = Class.forName("reflect.aop.ITest").getMethod("test2", new Class[0]);
            m5 = Class.forName("reflect.aop.ITest").getMethod("test3", new Class[0]);
            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {
                Class.forName("java.lang.Object")
            });
        }
        catch(NoSuchMethodException nosuchmethodexception)
        {
            throw new NoSuchMethodError(nosuchmethodexception.getMessage());
        }
        catch(ClassNotFoundException classnotfoundexception)
        {
            throw new NoClassDefFoundError(classnotfoundexception.getMessage());
        }
    }
}
0 请登录后投票
   发表时间:2007-04-28  
可以看出的,基于jdk proxy 是不可能实现嵌套的,cglib是基于子类,具体源码还没时间去看呢,不太清楚,期待有人回答
0 请登录后投票
   发表时间:2007-04-29  
只要在被spring拦截的方法中再调用其他被代理的对象的方法就可以实现嵌套拦截,如果调用自己对象的方法(包括继承的),只是普通对象的方法调用(这时自己是被剥去了代理的壳的原始对象),是不能被拦截的。
0 请登录后投票
   发表时间:2007-04-29  
someMethod()调用someInnerMethod()根本就不是走的proxy.
起作用才怪了.
0 请登录后投票
   发表时间:2007-08-03  
这个问题也捆饶了我很久
0 请登录后投票
   发表时间:2007-08-04  
yeshucheng 写道
这个问题也捆饶了我很久

我觉得自己的嵌套调用不被aop拦截挺好啊,保证了在一个事务里面,

如果你要实现嵌套调用的拦截,那么里面的方法不能用this来调用,直接写someInnerMethod();实际就是执行了this.someInnerMethod();这个this是剥离了aop代理的真正的SomeServiceImpl对象,而外面执行的someService.someMethod()这个someService对象是aop代理对象,只有调用代理对象的方法才有机会执行代理动作,
那么怎么在方法里面来调用代理对象,自己想办法吧,可以从spring容器中取得该对象,或者把该对象作为参数传到方法里面,或者可以在SomeServiceImpl类里加一个属性来引用自己的代理对象,如名为self,在使用前先设置一下,someService.setSelf(someService);把代理对象的引用保存到对象里面,在嵌套调用时调用self的方法而不是this。
0 请登录后投票
   发表时间:2007-08-04  
janh 写道
yeshucheng 写道
这个问题也捆饶了我很久

那么怎么在方法里面来调用代理对象,自己想办法吧,可以从spring容器中取得该对象,或者把该对象作为参数传到方法里面,或者可以在SomeServiceImpl类里加一个属性来引用自己的代理对象,如名为self,在使用前先设置一下,someService.setSelf(someService);把代理对象的引用保存到对象里面,在嵌套调用时调用self的方法而不是this。


不知道janh是否试过?
我用过这个法子,但是这样好像不工作。异常。什么异常,什么原因没查。

这个问题,应该是设计问题。抽取方法,另行安排。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics