Spring AOP:日志记录和嵌套方法
我编写了一个简单的 Spring2.5 应用程序来演示/测试 AOP;具体来说,我想记录特定包中每个类的每个方法的进入和退出。这就是我所拥有的...
(注意:我正在使用注释控制器;我省略了与 aop 不直接相关的细节,因为我的基本设置工作正常——我只包括与 aop 相关的细节——如果你需要查看更多)
applicationContext.xml :
(...)
<bean id="loggerInterceptor" class="aspect.LoggerInterceptor" />
(...)
dispatcher-servlet.xml :
(...)
<aop:aspectj-autoproxy proxy-target-class="true" />
(...)
HomeController.java :
public class HomeController() {
public HomeController() { }
public ModelAndView get() {
System.out.println("In HomeController#get()...");
this.somePrivateMethod();
this.somePublicMethod();
return new ModelAndView( "home" );
}
private void somePrivateMethod() {
System.out.println("In HomeController#somePrivateMethod()...");
}
public void somePublicMethod() {
System.out.println("In HomeController#somePublicMethod()...");
}
}
LoggerInterceptor.java :
public class LoggerInterceptor {
@Pointcut("execution(* controller.*.*(..))")
private void anyOperationInControllerPackage() {
/* nothing to do here;
* this just defines that we want to catch all methods
* in the controller-package
*/
}
@Around("anyOperationInControllerPackage()")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("Entering " + joinPoint.getSignature().getDeclaringTypeName() + "#" + joinPoint.getSignature().getName() + "() using arguments: " + Arrays.toString( joinPoint.getArgs() ) );
try {
Object result = joinPoint.proceed();
System.out.println("Leaving " + joinPoint.getSignature().getDeclaringTypeName() + "#" + joinPoint.getSignature().getName() + "()." );
return result;
} catch (Throwable ex) {
ex.printStackTrace();
throw ex;
}
}
}
这是调用 HomeController#get() 时得到的结果:
Entering controller.HomeController#get() using arguments: []
In HomeController#get()...
In HomeController#somePrivateMethod()...
In HomeController#somePublicMethod()...
Leaving controller.HomeController#get().
如您所见,唯一被拦截的方法是 HomeController#get()。当 #get() 调用 #somePrivateMethod() 或 #somePublicMethod() 时,拦截器不会捕获这些内容。我预计,至少 #somePublicMethod() 也会被捕获(并且由于我使用的是 cglib,我也预计 #somePrivateMethod() 也会被捕获)。
所以我想我的问题是我需要更改/添加什么才能允许(至少)控制器包中的所有公共方法被捕获,即使该包中的另一个方法调用它们并且本身首先被捕获? ??
我希望这是有道理的。 :D
编辑(25APR2011 @ 1:13PM)
applicationContext.xml :
(...)
<context:load-time-weaver /> <!-- added -->
<bean id="loggerInterceptor"... />
(...)
aop.xml :
<!DOCTYPE aspectj PUBLIC
"-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<weaver>
<!-- only weave classes in this package -->
<include within="controller.*" />
</weaver>
<aspects>
<!-- use only this aspect for weaving -->
<aspect name="aspect.LoggerInterceptor" />
</aspects>
</aspectj>
< strong>在 Netbean 的“项目属性”中的“运行”选项卡下,我将此行添加到“VM 选项”:
-javaagent:C:\Users\bgresham\Documents\libraries\spring-framework-2.5\dist\weaving\spring-agent.jar
和以前一样,我没有收到任何错误 - 我只是没有获取我正在寻找的“嵌套”日志记录。
???
I have written a simple Spring2.5 app to demo/test AOP; specifically, I want to log the entry and exit of every method of every class in a specific package. This is what I have...
(note: I am using annotation-controllers; I am omitting details not directly-related to aop because my basic setup works fine -- I am only including aop-related details -- let me know if you need to see more)
applicationContext.xml :
(...)
<bean id="loggerInterceptor" class="aspect.LoggerInterceptor" />
(...)
dispatcher-servlet.xml :
(...)
<aop:aspectj-autoproxy proxy-target-class="true" />
(...)
HomeController.java :
public class HomeController() {
public HomeController() { }
public ModelAndView get() {
System.out.println("In HomeController#get()...");
this.somePrivateMethod();
this.somePublicMethod();
return new ModelAndView( "home" );
}
private void somePrivateMethod() {
System.out.println("In HomeController#somePrivateMethod()...");
}
public void somePublicMethod() {
System.out.println("In HomeController#somePublicMethod()...");
}
}
LoggerInterceptor.java :
public class LoggerInterceptor {
@Pointcut("execution(* controller.*.*(..))")
private void anyOperationInControllerPackage() {
/* nothing to do here;
* this just defines that we want to catch all methods
* in the controller-package
*/
}
@Around("anyOperationInControllerPackage()")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("Entering " + joinPoint.getSignature().getDeclaringTypeName() + "#" + joinPoint.getSignature().getName() + "() using arguments: " + Arrays.toString( joinPoint.getArgs() ) );
try {
Object result = joinPoint.proceed();
System.out.println("Leaving " + joinPoint.getSignature().getDeclaringTypeName() + "#" + joinPoint.getSignature().getName() + "()." );
return result;
} catch (Throwable ex) {
ex.printStackTrace();
throw ex;
}
}
}
Here is what I'm getting when HomeController#get() is invoked:
Entering controller.HomeController#get() using arguments: []
In HomeController#get()...
In HomeController#somePrivateMethod()...
In HomeController#somePublicMethod()...
Leaving controller.HomeController#get().
As you can see, the only method that's getting intercepted is HomeController#get(). When #get() calls #somePrivateMethod() or #somePublicMethod(), the interceptor doesn't catch those. I would expect, at the very least, that #somePublicMethod() would also get caught (and since I'm using cglib, I would also expect that #somePrivateMethod() would get caught).
So I guess my question is what do I need to change/add in order to allow (at the very least) all public methods in the controller-package to get caught even when another method in that package called them and was itself caught first???
I hope that makes sense.
:D
EDIT(25APR2011 @ 1:13PM)
applicationContext.xml :
(...)
<context:load-time-weaver /> <!-- added -->
<bean id="loggerInterceptor"... />
(...)
aop.xml :
<!DOCTYPE aspectj PUBLIC
"-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<weaver>
<!-- only weave classes in this package -->
<include within="controller.*" />
</weaver>
<aspects>
<!-- use only this aspect for weaving -->
<aspect name="aspect.LoggerInterceptor" />
</aspects>
</aspectj>
In Netbean's "Project Properties" under the "Run" tab I added this line to the "VM Options" :
-javaagent:C:\Users\bgresham\Documents\libraries\spring-framework-2.5\dist\weaving\spring-agent.jar
As before, I'm not getting any errors -- I just don't get the "nested"-logging I'm looking for.
???
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果您使用 Spring AOP,则必须仅调用通过 Spring 返回的引用应用了切面的方法,不能通过
this,而且我认为您也不能将切入点应用于私有方法(最后一部分可能是错误的)。这是因为 Spring AOP 通过代理对象应用切入点,而不是通过类重写(AspectJ 就是这么做的)。这种严格限制的好处是,让它在容器中工作要容易得多(我从经验中知道 Spring AOP 在 Tomcat 中工作得很好),因为没有关于哪些位插入到哪里的争论。
最好的方法是拆分类定义,这样您就永远不会通过
this
调用方法,但如果不可能,那么您始终可以尝试为 bean 提供对自身的 Spring 派生引用:(这非常简洁;
self
是多种语言中的关键字,但 Java 中不是这样,因此相对容易记住它的用途。)If you're using Spring AOP, you must only call a method that's had an aspect applied to it via a reference returned by Spring, not through
this
, and I don't think you can apply pointcuts to private methods either (might be wrong on that last part). That's because Spring AOP applies the pointcuts through the proxy object, not by class rewriting (which is what AspectJ does). The benefit of that heavy restriction is that it is much easier to make it work in containers (I know from experience that Spring AOP works just fine inside Tomcat) because there's no warring over what bits are plugged in where.The best way of doing this is by splitting the class definition so that you never call a method via
this
, but if that's not possible then you can always try giving a bean a Spring-derived reference to itself:(This is pretty neat;
self
is a keyword in a number of languages but not Java so it's relatively easy to remember what you're using it for.)您正在使用 spring aop 来支持方面。 Spring aop 仅适用于 spring beans。因此,切入点不适用于实际的类实例,即当控制器调用其任何公共或私有方法时。为了记录控制器中的所有方法,您需要通过启用您想要拦截的所有类的加载时或编译时编织来使用 AspectJ 来支持 aop。
编辑:
您需要以下内容来进行加载时编织:
aop.xml
这意味着使用指定的方面编织所有文件('within=*',根据需要修改)。在加载时,您应该看到有关类编织的详细信息。
Spring 配置中的配置:
请注意,编织类必须位于服务器库路径中,而不是您的应用程序路径中。
上述配置应该可以满足您的要求。
You are using spring aop for aspect support. Spring aop will work only on spring beans. So, the pointcut does not work on the actual class instance i.e. when the controller calls any of its public or private method. In order to log all the methods in the controller, you need to use AspectJ for your aop support by enabling either load time or compile time weaving of all the classes that you want to intercept.
Edit:
You would need the following for load time weaving :
aop.xml
This implies weaving in all your files ('within=*', modify as you wish) with the aspect/s specified. On load time you should see verbose information on weaving of classes.
Configurations in the spring configurations :
Notice the weaving class has to be in the server library path and NOT your application path.
The above configurations should do what you are looking out to do.