How control advice catches exception - spring

I am trying to understand how ControllerAdvice is working in SpringBoot. It is suggested that for per application there should be one ControllerAdvice. But my question is how this ControllerAdvice is tied to Controllers and catching the exceptions. So basically what is the underhood?

Spring AOP works with proxies.
That is when you annotate a class with any of AOP annotation spring will create a proxy class by extending your annotated class and all the methods will be overridden there in the proxy class.
Thus here after when you call a method in your class spring will call the proxy object method first then your actual method. This is Spring AOP knows whether the method has been called or thrown some exception or returned successfully etc etc.
This is the reason why when you call a private method with in the class AOP cannot intercept that method call.

Related

Spring service method validation

I have a service class which is annotated with #Validated.
In this class I have a method with an argument which is annotated with #Valid.
If the method is called from another class instance with an argument that is not valid an exception is thrown.
As expected an error of type ConstraintViolationException is thrown.
If I call this method from another service method (internal call) no validation is performed and an error arises in the body of the method.
This is not what I want. Apparently calls made from within are not validated.
Investigating the problem I found out that the method was not invoked using a Spring proxy bean.
I fixed the problem by retrieving the proxy from the (#Autowired) application context and invoke the method using the proxy:
((T) context.getBean(this.getClass()).myMethod(validatedArgument)
This is an ugly solution.
How can I configure Spring so that method calls made from within are validated?
There is a tricky way to autowire the service to itself.
#Service
public class MyService {
#Autowired
private MyService copy;
private void call() {
//myMethod(validatedArgument);
copy.myMethod(validatedArgument);
}
}
The way Spring handles aspects is such that they are only invoked when one instance sends a message to a different instance. There are some ways to overcome this, but in your case, the fact that you want to do it is probably revealing a design flaw.

HystrixCommand only works with Spring Service or Component?

Does Spring Hystrix only work with #Service and #Component?
I had a class that was defined as a #RestController and my HystrixCommand would not fire, the method would execute but not behave as a HystrixCommand. When I made a #Service class and put the HystrixCommand method and fallback into it the HystrixCommand would work properly.
What are the appropriate Spring annotations that can be used with #EnableHystrix?
For now, you described the appropriate places. We have an open issue that mentions support for controllers.

Spring AOP Method Interceptor vs Method Advice

I am new to AOP and I am trying to understand the difference between Method Interceptor and MethodAdvice(i.e. MethodBeforeAdvice or MethodAfterAdvice). To me looks like both are doing the same thing i.e. are called on method invocation. When should we use MethodInterceptor vs MethodAdvice.
Take a look at the definition of the org.aopalliance.interceptInterceptor interface (implemented by MethodInterceptor):
public interface Interceptor extends Advice {
}
It's easy to see that a MethodInterceptor actually IS an Advice.
The only difference between an Advice being defined in an #Aspect class and such an Interceptor is that Interceptor implementations can be added to and removed from Spring AOP Proxies at runtime (casting them to 'Advised'), whereas the Advice you're talking about is a more static construct. But their still essential to Spring AOP since their presence tells Spring which beans to wrap in a proxy object during application context startup.

Invoking custom annotation using Spring AOP

I searched the web for a clear example on how to invoke my custom method annotation using Spring AOP but couldn't find a clear example.
I am building a framework to inject a user profile in the context when certain methods on any POJO is called.
The framework API should be invoked via a custom method annotation, say #RunAsAdmin. I can build the annotation part and parser, my question is what is the best way to invoke my parser when the annotated method is called.
We are using Spring 3.0 and would like to know what is the best practice to configure Spring framework to understand those methods annotated with specific annotation and invoke my annotation handler (parser).
Any example or guidance will be highly appreciated.
Intercepting a call on any annotated Spring bean method is straightforward, see the example below.
Intercepting a call on a POJO is not possible by definition - you have to return a proxy instead.
That is, you should implement a factory for these POJOs that will return proxies instead of real POJOs. You might use ProxyFactoryBean http://docs.spring.io/autorepo/docs/spring-framework/3.2.0.BUILD-SNAPSHOT/api/org/springframework/aop/framework/ProxyFactoryBean.html for this.
//intercepting a call to any method annotated with #com.yours.RunAsAdmin of any Spring-managed bean
#Component #Aspect class RunAsAdminAspect {
#Autowired
private YourRunAsAdminHandler handler;
#Before("#annotation(com.yours.RunAsAdmin)")
public void doRunAsAdmin() {
handler.grantAdminRightsToCurrentUser(); //your real stuff
}
}

Spring DefaultAdvisorAutoProxyCreator with #Transactional causing problems

I'm working on a Spring MVC project and trying to integrate Apache Shiro for the security. Everything was going just swimmingly until I realized Hibernate was prematurely closing the session/connection after a single query and causing a lazyinit exception. Not surprising, what I was doing should be done within a transaction so the session isn't closed.
Dilemmas…
I tried putting #Transactional on my controller method, but I get 404's then. Looking at my logs, I can see that when Spring is bootstrapping it ignores any mappings in my HomeController if that #Transactional annotation is on any method within the controller.
Without the #Transactional and it loads up just fine, and Ih can see the RequestMappingHandlerMapping bean sees all the #RequestMapping annotations in my controller.
With #Transactional but without DefaultAdvisorAutoProxyCreator, and it works except Shiro annotations are simply ignored.
tldr: Shiro requires DefaultAdvisorAutoProxyCreator, but if I create that bean, Spring blows up when using the #Transactional annotation.
I'm asking for help because I'm completely at a loss for how to proceed at this point.
This is typically because when you put #Transactional on a method, Spring creates a dynamic proxy for that bean - if the bean implements an interface then dynamic proxy is created based on that interface, otherwise CGLIB will be used for creating the proxy.
The problem in your case, I am guessing is because you probably have based your controller on some interface, or you are extending it based on a base class. This is ending up creating a proxy based on that interface, because of this when it comes time for mappings to be created for your request, Spring MVC is probably not finding your mappings from your bean.
The fix could be a few:
a. You can try and force proxies to be based on CGLIB for your transactions:
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
b. You can use pure Aspectj,either load time weaving or compile time weaving
c. You can move the #Transactional into a Service (which has an interface) and delegate the call from the controller to the service, this way avoiding #Transaction on the controller

Resources