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

查看:33
本文介绍了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 :

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

<小时>

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

-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,则必须只调用一个通过由Spring,notthis,我认为您也不能将切入点应用于私有方法(最后一部分可能是错误的).这是因为 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天全站免登陆