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>
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>
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.
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
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.)
Related
I am in the process of understanding the Spring and I stumbled with these peculiar things.
I Have the Component annotated class below named MyComponent (please disregard the interface), and that Class uses the HelperClass. This helper class was instantiated manually twice for two different variables inside the method named doSomething
I also have my bean project-properties.xml that was also imported in app-config.xml
Yes, there is a Bean for HelperClass for some reason and it also has an Initial value every time it's been #autowired, and even if it is instantiated it manually and that value is from the bean xml.
#Component
public MyCompontent implement MyInterface {
public doSomething() {
HelperClass helper1 = new HelperClass();
HelperClass helper2 = new HelperClass();
// print the value set by helper1 and its not null, the value is from bean xml
System.out.println(helper1.getVariable1);
helper1.setVariable1("Set Value for Helper1");
helper2.setVariable1("Set Value for Helper2");
// print the value set by helper1 but it display the value of the helper 2
System.out.println(helper1.getVariable1);
}
}
public HelperClass {
private String variable1;
private String variable2;
public void variable1(String variable1){
this.variable1 = variable1
}
public String getvariable1() {
return this.variable1;
}
public void variable2(String variable2){
this.variable2 = variable2
}
public String getvariable2() {
return this.variable2;
}
}
project-properties.xml
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myHelper" class="com.example.HelperClass">
<property name="variable1" value="bean-value1"/>
<property name="variable1" value="bean-value2"/>
</bean>
</beans>
app-config.xml
<?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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
...........
<!-- Configures Spring MVC -->
<import resource="project-properties.xml"/>
.....
.....
</beans>
My Questions are:
I understand that if I use #autowired on HelperClass it will have properties values from bean's XML, but why is it still happening even if I manually Instantiate this class(HelperClass helper = new HelperClass())?
What is the mechanism of spring behind this?
Can I disable this thing or prevent it to happen in a specific class?
Even if I instantiated it multiple times, why are they still pointing or referencing into a Single instance of HelperClass? It sounds like its scope is Singleton.
If I ever get the answer to previous questions, my next question is how can I perfectly instantiate HelperClass without reference to the bean, what I mean is how can I disable those things to happen on a specific line in a class?
If you feel that my question is redundant please help me to redirect
Thanks and Regards
There is a very high probability that you have been misled by your printings.
Spring can autowire dependencies if class has such annotation on constructor, field, or setter. Spring does not control the instances that have been created manually.
Spring can't even get inside your method, because the framework (in standard case) operates with the interface of your class using reflections. On startup, the framework goes through all the classes, finds all the annotations that have to be processed, and covers such classes with proxies (almost always). But Spring never goes inside your code directly, it can't put a new line of its code in between of 2 your lines in the same method.
Why post construct does not get called without putting bean in applicationContext.xml
Here is my class which contains #PostConstruct annotation.
package org.stalwartz.config;
import javax.annotation.PostConstruct;
import javax.inject.Singleton;
#Singleton
public class PropertyLoader {
#PostConstruct
public void init() {
System.out.println("PropertyLoader.init()");
}
}
Below is my applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:dwr="http://www.directwebremoting.org/schema/spring-dwr" xmlns:tx="http://www.springframework.org/schema/tx"
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
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.directwebremoting.org/schema/spring-dwr
http://www.directwebremoting.org/schema/spring-dwr/spring-dwr-3.0.xsd">
<dwr:annotation-config />
<dwr:annotation-scan base-package="org.stalwartz" scanDataTransferObject="true" scanRemoteProxy="true" />
<dwr:url-mapping />
<!-- <bean id="proeprtyLoader" class="org.stalwartz.config.PropertyLoader"></bean> -->
<dwr:controller id="dwrController" debug="false">
<dwr:config-param name="activeReverseAjaxEnabled" value="true" />
</dwr:controller>
<context:annotation-config>
<context:component-scan base-package="org.stalwartz" annotation-config="true"></context:component-scan>
</context:annotation-config>
<mvc:annotation-driven />
...
...
...
</beans>
Looks simple, but it does not work without uncommenting bean declaration.
In Spring environment initialization callback method (the one annotated by #PostConstruct) make sense only on spring-managed-beans. To make instance(s) of your PropertyLoader class managed, you must do one of the following:
Explicitly register your class in context configuration (as you did)
<bean id="proeprtyLoader" class="org.stalwartz.config.PropertyLoader"></bean>
Let component scanning do the work (as you nearly did), but classes must be annotated by one of #Component, #Repository, #Service, #Controller.
Note from Spring documentation: The use of <context:component-scan> implicitly enables the functionality of <context:annotation-config>. There is usually no need to include the <context:annotation-config> element when using <context:component-scan>.
Because putting bean in applicationContext.xml you are adding bean to Spring container, which has interceptor for this annotation. When Spring inject beans it checks #PostConstruct annotation, between others.
When you call simple new PropertyLoader() JVM will not search for the #PostConstruct annotation.
From doc of #PostConstruct annotation:
The PostConstruct annotation is used on a method that needs to be executed
after dependency injection is done to perform any initialization. This
method MUST be invoked before the class is put into service. This
annotation MUST be supported on all classes that support dependency
injection. The method annotated with PostConstruct MUST be invoked even
if the class does not request any resources to be injected.
Singleton is a scope annotation. It can be used to declare 'singletone' scope for a particular bean, but not instantiate it. See this article.
If you want to instantiate your class as singleton you can try Spring Service annotation.
#Service
public class PropertyLoader {
#PostConstruct
public void init() {
System.out.println("PropertyLoader.init()");
}
}
Also, you can replace annotation-config tag with component-scan. Here is a good article about differences of annotation-config and component-scan tags.
you are using #Singleton from javax.inject package which is not picked up as bean by spring container. Change it to :
package org.stalwartz.config;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
#Component
public class PropertyLoader {
#PostConstruct
public void init() {
System.out.println("PropertyLoader.init()");
}
}
and the spring will auto detect PropertyLoader and will include it in Spring container as bean via the #Component annotation and this bean will be with singleton scope
by default a bean is singleton scoped in Spring, and #PostConstruct is usually used for service beans and service beans must scoped prototype and here because you need multiple objects for that particular class, Spring will provide you singleton instance.
also by doing this spring will attempt multiple times to find this service bean and finally throws below exception:
java.lang.NoClassDefFoundError: Could not initialize class org.springframework.beans.factory.BeanCreationException
so try like this in annotation way:
package org.stalwartz.config;
import javax.annotation.PostConstruct;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
#Component
#Scope("prototype") //you have to make it prototype explicitly
public class PropertyLoader {
#PostConstruct
public void init() {
System.out.println("PropertyLoader.init()");
}
}
Now every thing is good, and work fine for you.
add this dependency to pom.xml
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
I am new to Spring framework and what I want to do is that I have a bean definition in my spring config which is not referenced in any of other beans and also I don't want it to be loaded using context. I want that while doing bean initialization, spring it self loads it calls it init-method.
<bean id="test" class="com.spring.test.Test" init-method="init"/>
package com.spring.test;
public class Test {
public void init() {
System.out.println("Recvd the call Test.print() ");
}
}
I don't get a call in this init(), I think this Test bean should be implementing an interface to tell spring to load this as well.
you have to use default-init-method attribute in father "beans" tag, see my example:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
default-init-method="init" default-destroy-method="destroy">
<!--then you can disable init-method using these tag in child bean:-->
<bean id="test" class="com.spring.test.Test" init-method=""/>
</beans>
Adding "init-method" attribute in bean tag is override the father method, like an inherit method. Same with destroy method.
Good luck!
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.
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.