Spring AOP:日志记录和嵌套方法 [英] Spring AOP: logging and nested-methods

查看:283
本文介绍了Spring AOP:日志记录和嵌套方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经编写了一个简单的Spring2.5应用程序来演示/测试AOP;具体来说,我想记录特定程序包中每个类的每个方法的进入和退出.这就是我所拥有的...

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...

(注意:我使用的是注解控制器;我省略了与aop不直接相关的细节,因为我的基本设置可以正常工作-我只包含了与aop相关的细节-如果您需要了解更多信息,请告诉我)

(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;

        }

    }

}


这是调用HomeController#get()时得到的内容:


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().

如您所见,唯一被拦截的方法是HomeController#get().当#get()调用#somePrivateMethod()或#somePublicMethod()时,拦截器不会捕获这些内容.我至少希望#somePublicMethod()也会被捕获(并且由于我正在使用cglib,所以我也希望#somePrivateMethod()会被捕获).

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???

我希望这是有道理的. :D

I hope that makes sense. :D

applicationContext.xml:

applicationContext.xml :

(...)
<context:load-time-weaver />  <!-- added -->
<bean id="loggerInterceptor"... />
(...)


aop.xml:


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>


在Netbean的运行"选项卡下的项目属性"中,我将此行添加到了虚拟机选项" :


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.

???

推荐答案

如果您使用的是Spring AOP,则您必须仅调用通过其返回的引用对其应用了方面的方法春天,不是不是this,我也不认为您也可以将切入点应用于私有方法(最后一部分可能是错误的).这是因为Spring AOP通过代理对象而不是通过类重写(这是AspectJ所做的)应用切入点.严格的限制的好处在于,使其更容易在容器中运行(我从经验中知道,Spring AOP在Tomcat中运行良好),因为不必担心在何处插入了什么位.

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.

做到这一点的最佳方法是拆分类定义,这样您就永远不会通过this调用方法,但是如果不可能,那么您总是可以尝试为bean提供一个Spring派生的对自身的引用:

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:

private HomeController self;
@Required
public void setSelf(HomeController self) { this.self = self; }

public ModelAndView get() {
    System.out.println("In HomeController#get()...");

    self.somePrivateMethod();
    self.somePublicMethod();

    return new ModelAndView( "home" );
}

(这很简洁; self是许多语言的关键字,但不是Java ,因此记住它的用途相对容易.)

(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:日志记录和嵌套方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆