Announcement Announcement Module
Collapse
No announcement yet.
AOP Autoproxying not Working for @Service Components Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • AOP Autoproxying not Working for @Service Components

    Hi,

    I have a business service component defined with @Service annotation.
    This component is injected into a web MVC controller using auto-wiring.
    Additionally, I have an @Aspect aspect defined that applies to the execution of any method in the above service component.
    Here's the gist of class definitions:

    @Controller
    public class SomeController {
    @Autowired
    public SomeService service;
    }

    @Service
    public class SomeService {
    public void foo(){}
    }

    @Aspect
    public class SomeAspect {
    @Pointcut ("execution(* SomeService.*(..))")
    public void serviceOperation (){}

    @Around ("serviceOperation()")
    public Object profile (ProceedingJoinPoint jp) throws Throwable {
    Object returnValue;
    . . .
    return returnValue;
    }

    With the above definitions and with auto-proxying for Spring AOP enabled using <aop:aspectj-autoproxy/> and with component scanning enabled with <context:component-scan base-package="" />, the problem that I encounter is that the controller is always getting injected with an instance of SomeService instead of a proxy and hence the around advice within SomeAspect is never getting executed. If I remove the @Service annotation from the SomeService component and instead provide an explicit bean definition in the XML file, then the controller is getting injected with the AOP proxy.

    Can someone please tell what I am doing wrong here?

    Thanks,
    Viji

  • #2
    Just wanted to make a correction to the class definitions in my original email.
    The service definition and the injection are using interface-based semantics as follows:

    @Controller
    public class SomeController {
    @Autowired
    public ISomeService service;
    }

    public interface ISomeSerice{
    public void foo();
    }

    @Service
    public class SomeService implements ISomeService{
    public void foo(){}
    }

    Comment


    • #3
      Your pointcut definition is wrong because the class must be fully qualified (i.e. preceded by the package definition). So either

      execution(* com.mycompany.myapp.mysubpackage.SomeService.*(..)) -> To advise only SomeService class in that particular package, or

      execution(* *.SomeService.*(..)) -> To advise all classes called SomeService in any package.

      Comment


      • #4
        Hi Enrico,

        I know for a fact that Pointcut definition is NOT the issue here.
        Sorry that I did not present the complete code in the original email.
        It does include the fully qualified name preceded by the package definition like you have shown. I apologize for misleading you.

        Besides, I know for a fact that the aspect fires when I use XML to specify the bean definition for the service component instead of relying on annotation.
        I have checked that the controller component does get injected with a AOP proxy to the service component in the latter case.

        My question is this:
        With everything else remaining exactly the same, if the I remove the bean definition from the XML file and add the @Service annotation to the class definition of the service component,
        the controller does not get injected with an AOP proxy but instead gets a reference to an un-proxied instance of the class.
        When Spring detects the service component as a candidate bean (based on @Service annotation) and registers it with the container, should it not also detect that there is an aspect with a matching pointcut and hence wrap the bean with an AOP proxy?

        Thanks,
        Viji
        Last edited by vijisarathy; Sep 6th, 2011, 06:35 AM.

        Comment


        • #5
          It should, provided the bean is in the same context in which aop is defined. Aop only works for the context in which it is explicitly defined, yours is a web application so if you have configured it correctly you should have (at least) 2 different contexts:
          - the father context, loaded by the listener, that has all service and dao layer beans defined / scanned from classpath;
          - the child context, loaded by DispatcherServlet, that has all frontend layer configured.

          If that is the case, remember that aop defined for father context only works for dao and service beans, and aop defined in child context only works for controllers, filters etc. So, if you detect your aspect beans by component scanning, you should be sure to include their package in both contexts (and of course be sure to have the aop : aspectj-autoproxy annotation in both contexts also).

          Comment


          • #6
            My service component and the aspect are both defined in the parent context loaded by ContextListener.
            The controller is in the child context loaded by the DispatcherServlet.

            Component scanning is enabled in both contexts. I have @AspectJ aspects defined only in the parent content and so <aop:aspectj-autoproxy/> configuration is included only in the parent context.

            I think that the problem might be the following:
            I have component scanning turned on in both contexts and the package that the service component belongs to is included in both the scans.
            So, when I use explicit bean definition in the parent context, the service component gets registered as a bean only in the parent context as well as gets wrapped by a AOP proxy. However, when I don't use XML bean definition but instead rely on @Service annotation, then the service component gets registered as a bean in both contexts but only the one in the parent context gets wrapped by the AOP proxy while the one on the child context is un-proxied. So, when the controller gets dependency injected, it gets the bean from the context that is closest to it, namely the child context and hence it gets the unproxied instance.

            I will check this in a bit and confirm.

            Thanks,
            Viji

            Comment


            • #7
              the package that the service component belongs to is included in both the scans
              this is always wrong, as it means your beans are registered twice. I can confirm the behaviour you described is the source of your problems.

              Comment

              Working...
              X