1

I have an aspect advice that tracks the execution of classes annotated with @Service. The code is currently working but I would like to change it to track REST endpoints on controllers instead of autowired services. Here is the code:

@Aspect
public class AuditingAspect
{
    @Pointcut(
            //TODO Change pointcut from public methods in Services to REST endpoints in Controllers
            "execution(public * my.base.package..*.*(..))" //Must be in package
                    //+ " && @within(org.springframework.stereotype.Service)" //Has to be a service
                    + " && @within(org.springframework.stereotype.Controller)" //Has to be a controller
    )
    public void auditLoggingPointCut() {
        //no op
    }

    @Around(value ="auditLoggingPointCut()")
    public Object logAround(final ProceedingJoinPoint joinPoint) throws Throwable
    {
        System.out.println("Exection");

        returnVal = joinPoint.proceed();

        // Now Do The After Logging Part
        afterReturningLog(joinPoint, returnVal) ;

        return returnVal;
    }

    private void afterReturningLog(final JoinPoint joinPoint, final Object returnValue)
    {
        System.out.println("Exiting");
    }
}

When I change the "within" from @Service to @Controller, I don't see any output from the advice but the method executes when accessed from the URL. What is different about a Controller that would ignore execution?

The Controller class looks like this:

@Controller
public class CaseReferralEndpoints {

    @Autowired
    CaseReferralFacade caseReferralFacade;

    @RequestMapping(value="/backgroundcheck/getcasereferrals", method = RequestMethod.GET)
    @ResponseBody
    public List<CaseReferralSection> getCaseReferrals(@RequestParam("caseID") Long caseID) {
        return caseReferralFacade.getCaseReferrals(caseID); 
    }
}

Here is my applicationContext-aop.xml The full config is much larger but I believe this is the most relevant.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:aop="http://www.springframework.org/schema/aop"
   xsi:schemaLocation="
    http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/aop 
    http://www.springframework.org/schema/aop/spring-aop.xsd">



    <bean class="gov.dhs.uscis.elis2.backend.services.logging.AuditingAspect"/>

    <aop:aspectj-autoproxy proxy-target-class="false" />


</beans>
geoand
  • 60,071
  • 24
  • 172
  • 190
Dan Little
  • 91
  • 1
  • 10
  • There are various things that could cause the advice to not be triggered. Could you please post your whole spring configuration? – geoand Apr 25 '14 at 15:58

4 Answers4

1

Supposing that your @within configuration is correct, a potential remedy to your troubles would be the following:

<aop:aspectj-autoproxy proxy-target-class="true" />

Also you will have to add CGLIB to your classpath

The above steps are needed since your controller does not implement an interface

Finally if you have a root context and a web context, the aop related stuff needs to be applied to the web context (having it in the root context will not work for the controllers that are configured in the web context)

UPDATE

In Gradle to add CGLIB to the classpath add:

'cglib:cglib:2.2.2'

In Maven it would be:

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.2.2</version>
</dependency>
geoand
  • 60,071
  • 24
  • 172
  • 190
  • What is CGLIB exactly and how do I add it to my classpath? – Dan Little Apr 25 '14 at 16:14
  • Using gradle which patches through to maven – Dan Little Apr 25 '14 at 16:17
  • CGLIB is a library that enables Spring (or any other code) to create proxies for classes that do not implement an interface – geoand Apr 25 '14 at 16:17
  • I'm not sure how to change from root to web context – Dan Little Apr 25 '14 at 16:21
  • Move `` to your spring configuration that configures the controllers. Take not though that aspects not meant for controllers will probably not work – geoand Apr 25 '14 at 16:22
  • What do you mean by not meant for controllers? – Dan Little Apr 25 '14 at 16:26
  • This is what I meant to say: Move `` to your spring configuration that configures the controllers. Take note though, that advices for spring beans that are not controllers (services,daos, etc.) will probably not work – geoand Apr 25 '14 at 16:29
  • I've had the advice working on @Services which were autowired in. I would have hoped that it would be a simple change but I'm fairly new to AOP – Dan Little Apr 25 '14 at 16:30
  • I know that it currently works for you , but to get it to work on @Controller classes you need to take the steps I mentioned and that will probably brake the aspects that currently work – geoand Apr 25 '14 at 16:32
  • Luckily this is just an experiment at the moment. If it gives me problems, I've heard that an "Interceptor" can be used to capture REST calls. – Dan Little Apr 25 '14 at 16:33
  • 1
    Yes, Spring Interceptors can give you AOP like functionality for Spring Controllers with minimal fuss – geoand Apr 25 '14 at 16:34
  • I think I found the issue. There is a filter set to exclude scanning of Controllers specifically – Dan Little Apr 25 '14 at 16:40
  • That is probably in a file called `applicationContext.xml`. There should be another file called `something-servlet.xml` or something like that. That is where you need to move `` – geoand Apr 25 '14 at 16:41
  • This sounds like it's a little more dangerous than I'm willing to put this application into. Even if it works I'd be nervous. I'm going to look into the Interceptors instead. Thanks for all your help! – Dan Little Apr 25 '14 at 16:54
1

Error was found inside of the applicationContext.xml

My controllers were being filtered out of context scanning! I'm one of many developers on the project so I did not think to look here initially.

<context:component-scan>
    <!-- a bunch of packages -->

    <context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>

However, I ended up adding an Interceptor which has proven to be closer to what I wanted. Because all of our user actions are REST driven it was easier and cleaner to audit the invocation of REST calls than try and track autowired service methods.

Dan Little
  • 91
  • 1
  • 10
0

As your pointcut expression is having

 @within(org.springframework.stereotype.Service)

with && symbol , advice is going to apply only within your package upto service.

and i hope your controller class is not inside ..Service package, it might be inside .*.*Controller package so its not executing for controller

solution Remove within inside point cut expression

or add controller also inside point cut expression

Karibasappa G C
  • 2,686
  • 1
  • 18
  • 27
  • I'm showing what works in Services and I included a commented out portion that I'm trying to switch to. I'll switch the code to show what is NOT working. I've tried this and it doesn't work. – Dan Little Apr 25 '14 at 16:11
0

Assuming your pointcut is correct, and you are using two spring contexts, one for the services/daos (appcontext) and one for the controllers (servletcontext), my tip goes in the direction of misconfiguration.

AOP configuration is one of the spring beans which are applied ONLY inside the context it is declared/scanned.

So assuming you have a servletcontext.xml for your controllers your pointcuts wont be applied unless you declare the aop context configuration within this context.

(The application context declaration will be needed if you want to apply the pointcuts to your services.)

Martin Frey
  • 10,025
  • 4
  • 25
  • 30