Prashant Chindhade
Prashant Chindhade

Reputation: 334

Aspectj Pointcut expression not working for one method and working for another method in single class

I have written below code in controller.

For this controllerMethod method the aspectj Pointcut expression is working fine but for executeService method Aspect is not working.

@RequestMapping(value = "URL", method = RequestMethod.POST)
public ModelAndView controllerMethod(@ModelAttribute ModelAttribute reqModel, HttpServletRequest req, HttpServletResponse res) {

    try {
        response = executeService(param1, param2);

    } catch (Exception e) {

    }

    }       
private ResponseObject executeService(String param1, String param2){
    //Code....
}

I have written the aspect as below.

@Before("execution(* com.*.*.Controller.executeService(..))")
public void logBefore(JoinPoint joinPoint) {
    logger.info("Before aspect: " + joinPoint.getSignature().getName());
}

Can you please let me know where is the issues. I need to execute aspect before calling executeService method.

Upvotes: 1

Views: 2319

Answers (3)

Mark Bramnik
Mark Bramnik

Reputation: 42491

Although our colleagues have provided correct answers, I'll summarize.

When it comes to aspects implementation, spring generates a proxy that wraps your controller. The proxy is implemented in a way that it has special hooks to invoke aspects before and after the class (or around, altering the flow altogether).

Spring uses two different strategies for proxy generation:

  • java.lang.Proxy based
  • CGLIB based

The first one is in general better, faster but works only with interfaces. The generated proxy is "something" that implements all the methods of the interface. The implementation methods contain those hooks I've talked before, but since the methods are only methods in the interface they have to be public

CGLIB - is slower, but it can work with classes as well (with some restrictions though). The way it works is sub-classing the parent class and overriding the methods provided by the super class. This new method (let's call it foo) will call all the hooks and somewhere in code if needed will call super.foo().

Now, obviously this can't really work with private methods because its impossible to override private methods. That's why my colleagues have pointed that private won't work here.

Now regarding the self injection stuff:

When you're inside the method of original controller and you're trying to call just another method (even if its public), you're not working with proxy any more, you're kind of behind the proxy and work with original class. So this means that you won't be able to take advantage of "enhanced" method.

That's why there is a self injection - you can see (with debugger for example) that the self-injected dependency is actually a dependency with all the proxies, that's why it starts to work.

Another workaround is to refactor the method to another Spring bean, inject this bean to your controller, and provide a definition for that bean.

Upvotes: 0

dabaicai
dabaicai

Reputation: 999

Because the AOP not intercept internal call ,so you can add a self-controller field,and call the internal method by self.method(...). Following code:

@Controller
public class ExampleController{

    @Autowired
    private ExampleController self;

    @RequestMapping(value = "URL", method = RequestMethod.POST)
    public ModelAndView controllerMethod(@ModelAttribute ModelAttribute reqModel, HttpServletRequest req, HttpServletResponse res) {

        try {
            response = self.executeService(param1, param2);

        } catch (Exception e) {

        }

    }
    public ResponseObject executeService(String param1, String param2){
        //Code....
    }
}

Upvotes: 1

T L Patel
T L Patel

Reputation: 86

You need to @RequestMapping(value = "URL", method = RequestMethod.POST) direct to executeService then its work.

Upvotes: 0

Related Questions