I have the following configuration:
#Aspect
public class MyAspect {
#Around(#annotation(SomeAnnotation))
public Object myMethod(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("Hello...");
}
}
And have the following beans definitions:
<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-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<bean id="myAspect" class="MyAspect" />
</beans>
I am seeing that the behavior is not getting applied to #SomeAnnotation annotated method at runtime. Any idea why?
Thx.
Make sure the class with #SomeAnnoation is created by the Spring container. Spring applies AOP to classes that are retrieved from the container by creating a proxy class to wrap the object. This proxy class then executes the Aspect before and after methods on that object are called.
If you're not sure try to debug into where you're using the class. You should see that the object isn't an instance of your class but a proxy object.
Have you enabled AspectJ support?
You need to add
<aop:aspectj-autoproxy/>
to your bean context.
Related
Have been trial Spring Web MVC (4.2.5) and have his a number of issues trying to use a DispatcherServlet and
<mvc:annotation-driven />
Have setup a simple #Controller class and wanted to use the POJO to JSON mapping. The docu said that if Jackson was detected on the class path it would be used automatically, however this didn't work for me and I was forced to use the 'deprecated' AnnotationMethodHandlerAdapter
<bean name="mappingJackson2HttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" >
<property name="messageConverters" ref="mappingJackson2HttpMessageConverter"/>
</bean>
which then worked fine.
Equally, tried to create a #ControllerAdvice class for handling all exceptions, but only got an #ExceptionHandler method working on the same controller class, and that was only when I added the (again) deprecated AnnotationMethodHandlerExceptionResolver to the context.
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver" />
Having to instantiate two deprecated classes suggests I am doing something wrong, especially when all the tutorials seem to suggest this should all 'just work', but I cannot see what (and indeed nosing through the Spring source I cannot see how the default and recommended handlers would work anyway)
There are no errors, the annotation simply aren't detected. The fill context xml is
please find the entire context XML below (is very simple)
<?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:p="http://www.springframework.org/schema/p"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven enable-matrix-variables="true"/>
<bean name="mappingJackson2HttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" >
<property name="messageConverters" ref="mappingJackson2HttpMessageConverter"/>
</bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver" />
<context:component-scan base-package="com.domain.datastore.dao"/>
<context:component-scan base-package="com.domain.service"/>
<context:component-scan base-package="com.domain.uiapi"/>
</beans>
An example controller is
#RestController("/place/*")
public class PlaceController {
private PlaceService placeService;
#Autowired
public PlaceController(PlaceService placeService) {
this.placeService = placeService;
}
#RequestMapping(path="/{id}", method = RequestMethod.GET)
public #ResponseBody Place getPlace(#PathVariable("id") long id, Model model) {
return placeService.getPlace(id);
}
}
and the cross-cutting exception handler is
#ControllerAdvice
public class GlobalExceptionController {
public GlobalExceptionController() {
System.out.println("GlobalExceptionController");
}
#ResponseStatus(HttpStatus.NOT_FOUND)
#ExceptionHandler(NotFoundException.class)
public ModelAndView handleCustomException(NotFoundException ex) {
return null;
}
}
The issue was that Spring MVC was matching the path in
#RestController("/place/*")
And as such passing the instance of PlaceController around as the handler. The ExceptionHandlerExceptionResolver expects a HandlerMethod and so was unable to process the exception.
As such dropping the path from the class annotation and putting the full path in the method got it all working and I dropped all the deprecated beans.
#RestController
public class PlaceController {
#RequestMapping(path="/place/{id}", method = RequestMethod.GET)
public #ResponseBody Place getPlace(#PathVariable("id") long id, Model model)
What I am not sure is if this is a bug. Shouldn't it be possible to put the 'base' path in the RestController annotation and the subpath in the RequestMapping?
As far as I can understand you don't want to use a deprecated class. AnnotationMethodHandlerAdapter is indeed Deprecated. As doc suggest you should use RequestMappingHandlerAdapter instead.
See here for the details.
And instead of AnnotationMethodHandlerExceptionResolver you can use ExceptionHandlerExceptionResolver.
I am trying to create a simple aspect .
Here is my simple spring bean
public class SimpleService {
public void sayHello(){
System.out.println("hi");
}
}
Here is my aspect class
#Aspect
public class SimpleAspect {
#Before("execution(void sayHello())")
public void entering(){
System.out.println("entering..");
}
}
Here is my configuration file
<?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/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<aop:aspectj-autoproxy/>
<bean id="service" class="com.schatt.service.SimpleService"></bean>
My understanding was that when I try to invoke SimpleService.sayHello() , the before aspect will be called and after that sayHello() will be called.But the aspect is not getting triggered.Can not understand what I am missing here.
The aspect needs to be created by Spring (in oder to apply the proxying).
<bean id="simpleAspect" class="package-name.SimpleAspect"></bean>
If your class does not implement any interface, you will have to use <aop:aspectj-autoproxy proxy-target-class="true"/>
In addition to what manish and fateddy have said, please also note that SimpleService needs to be a Spring #Component in order to make it work with Spring AOP.
I receive NullPoin Exception while calling any method of a Spring Bean, as it seems it is not injected in the container. And I can' t understand why.
Th particularity is that the Controller is using JSF and the Beans are Spring Bean: may be is this the problem? Or just configuration mistake?
The (simplified) code and config is:
Context.xml (called from root context)
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:plugin="http://www.springframework.org/schema/plugin"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.0.xsd
http://www.springframework.org/schema/plugin http://www.springframework.org/schema/plugin/spring-plugin.xsd">
<!--===========LANGUAGE_TO_LOCALE SERVICE CONFIG BEGIN===========-->
<bean
id="languagesCountryLocaleHelper"
class="com.i18n.MyControllerHelper"
scope="request" />
</beans>
JSF COntroller:
#RequestScoped
#Named
public class MyController {
#Autowired
private MyControllerHelper helper;
public void doSomething() {
helper.doSomething ();
}
}
MyControllerHelper:
#Component
public class MyControllerHelper {
public void doSomething() {
// do something useful
}
}
So, this is the simplified case.. do you have any idea on where my error can be?
Thank you in advance!
#Autowired
private MyControllerHelper helper = new MyControllerHelper();
change to this
#Autowired
private MyControllerHelper languagesCountryLocaleHelper;
I solved the problem injecting MyControllerHelper through:
helper = AppContext.getBean(MyControllerHelper.class);
After that, the bean is instantiated and injected and at cascade all the other beans after it.
I suppose it was due by the fact as JSF Controller the Controller instance Object was in a different container now automatically aware of Spring Beans.
Anything like #PreDestroy in the spring-framework?
If you define a bean that implements the DisposableBean interface then Spring will call the
void destroy() throws Exception;
method before destrying the bean.
That's one way, the other is when your bean doesn't have to implement the given interface.
In one of yours ConfigurationSupport classes your bean has to be defined as as pulic method with the #Bean annotation.
#Bean (destroyMethod="yourDestroyMethod")
public YourBean yourBean() {
YourBean yourBean = new YourBean();
return yourBean;
}
The method "yourDestroyMethod" has to be defined in YourBean.class and then Spring will call it before destroying the bean.
For more info see the Spring documentation: Destruction callbacks
UPDATE
The third way... I would even say the better way would be to specifiy "init-method" and "destroy-method" of your bean... like this: mkyong.com/spring/spring-init-method-and-destroy-method-example
This solves the problem ot third-party dependency beans, and liberates the the code unnecessary Spring interfaces..
There are 3 ways to do that.
#PreDestroy tag
destroy-method in xml
DisposableBean interface as stated above
My favorite is the #PreDestroy method.
To do that u need:
In application-context.xml add the following schema:
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="shutDownBean" class="spring.ShutDownBean" />
<context:annotation-config/>
</beans>
The context:annotation-config/ makes the #PreDestroy and the #PostDestroy tags available.
Now lets say that you have the ShutDownBean that you want to run some code when the shutdown callback is called.
The <bean id="shutDownBean" class="spring.ShutDownBean" /> part registers the bean.
import javax.annotation.PreDestroy;
public final class ShutDownBean {
#PreDestroy
public static void shutDownMethod() {
System.out.println("Shutting down!");
}
}
Now you are done.
If you have a desktop application then to use the #PreDestroy annotation you need to close it like this:
AbstractApplicationContext applicationContext =
new ClassPathXmlApplicationContext("application-context.xml");
applicationContext.registerShutdownHook();
note:
AbstractApplicationContext has the implementation of registerShutdownHook() so this is the minimum class you can use.
Also you can use the destroy-method tag for classes you do not control their implementation. For example you can add this in your applcation-context.xml:
<bean id = "dataSource"
class = "org.apache.commons.dbcp.BasicDataSrouce"
destroy-method = "close">
The destroy-method value can have any visibility but needs to have no arguments.
Hope this helps!
You mean like annotating a method with the standard JDK #PreDestroy? That's common enough in Spring, and usually better than using a destroy-method attribute on the bean declaration in XML. All you have to do is include
<context:annotation-config/>
In your configuration file and Spring handles the rest.
there's standard .NET IDisposable.Dispose() method. I don't know Spring but from quick googling it seems that #predestroy is pretty much the same concept.
How do I implement AOP with an annotated Controller?
I've search and found two previous posts regarding the problem, but can't seem to get the solutions to work.
posted solution 1
posted solution 2
Here's what I have:
Dispatch Servlet:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<context:annotation-config/>
<context:component-scan base-package="com.foo.controller"/>
<bean id="fooAspect" class="com.foo.aop.FooAspect" />
<aop:aspectj-autoproxy>
<aop:include name="fooAspect" />
</aop:aspectj-autoproxy>
</beans>
Controller:
#Controller
public class FooController {
#RequestMapping(value="/index.htm", method=RequestMethod.GET)
public String showIndex(Model model){
return "index";
}
}
Aspect:
#Aspect
public class FooAspect {
#Pointcut("#target(org.springframework.stereotype.Controller)")
public void controllerPointcutter() {}
#Pointcut("execution(* *(..))")
public void methodPointcutter() {}
#Before("controllerPointcutter()")
public void beforeMethodInController(JoinPoint jp){
System.out.println("### before controller call...");
}
#AfterReturning("controllerPointcutter() && methodPointcutter() ")
public void afterMethodInController(JoinPoin jp) {
System.out.println("### after returning...");
}
#Before("methodPointcutter()")
public void beforeAnyMethod(JoinPoint jp){
System.out.println("### before any call...");
}
}
The beforeAnyMethod() works for methods NOT in a controller; I cannot get anything to execute on calls to controllers. Am I missing something?
In order to put an aspect on a HandlerMethod in a class annotated with #Controller in Spring 3.1 you need to have the proxy-target-class="true" attribute on the aspectj-autoproxy element. You also need to have the CGLIB and the ASM libraries as a dependency in your WAR/EAR file. You can either specify your annotated aspect class as a bean and use the aop:include as stated above or you can leave the aop:include out and add a filter similar to this in your component scan element:
<context:component-scan>
<context:include-filter type="aspectj"
expression="com.your.aspect.class.Here"/>
</context:component-scan>
I do not know if this is a requirement as a result of Spring 3.1 only but I know that without this, you will not be able to put an aspect on your controller HandlerMethod. You would get an error similar to:
Caused by: java.lang.IllegalArgumentException: object is not an instance of declaring class
HandlerMethod details:
Controller [$Proxy82]
Method [public void com.test.TestController.testMethod(java.security.Principal,javax.servlet.http.HttpServletResponse) throws javax.servlet.ServletException]
Resolved arguments:
[0] [null]
[1] [type=com.ibm.ws.webcontainer.srt.SRTServletResponse] [value=com.ibm.ws.webcontainer.srt.SRTServletResponse#dcd0dcd]
This is not required if your aspect is on a method in a class that is not a controller
I am going to state an alternative solution (sorry not a direct answer) but what you wanting to do is probably best done via interceptors and filters.