Configuring AOP with ZK to intercept methods - java

Before certain methods (or as of now all the methods) I have to call the method of an Aspect to log some messages. My application is functioning correctly otherwise but none of the methods of the Aspect class are called.
I have tried the same cutpoint in same folder structure in my local application but when I try to include it with ZK i am having issues. I have also modified my application-context.xml to support AOP.
This is my aspect class :
package com.mypckg.services.impl;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
#Aspect
public class MyIntercpeter {
#Pointcut("execution(* com.mypckg.services.impl.MyService.getStudents(..))")
public void performance() {
}
#Before("performance()")
public void doSomethingBeforeExecution() {
System.out.println("Before execution method called...");
}
#AfterReturning("performance()")
public void doSomethingAfterExecution() {
System.out.println("After execution method called...");
}
}
The modifications I made in the application-context.xml are
<beans .........
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
..........
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
.....
<aop:aspectj-autoproxy />
<context:annotation-config />
Am I missing something? Thanks in advance.

Looks like you missed an obvious thing : you forgot to declare beans in spring config?
From Spring docs:
Spring AOP only supports method execution join points for Spring beans, so you can think of a pointcut as matching the execution of methods on Spring beans.
http://static.springsource.org/spring/docs/2.0.x/reference/aop.html
You can declare your beans with annotations or by config.
Also would be better to put a version of spring you use (I supposed it was 2.0.x).

Related

Spring Autowiring is not happening ? Object is not initializing at all

We are using Spring MCV and i am trying to use spring auto wiring to decouple my code. however, autowiring is not happening at all. Can you please suggest any issue in following code/ dispatcher
dispatcher-servlet.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.1.xsd"
xmlns:context="http://www.springframework.org/schema/context">
<context:component-scan base-package="com.eos.accounts" />
</beans>
User.java
package com.eos.accounts.data;
#Service
public class User {
.......
#Autowired
public UserMilesHelper userMilesHelper ;
.....
public static setUserPoints(User user){
user.setPoints(user.userMilesHelper.getUserPoints(user.getUserId()));
}
IUserMilesHelper.java
package com.eos.accounts.data;
public interface IUserMilesHelper {
public int getUserPoints(int userId);
}
UserMilesHelper.java
package com.eos.accounts.data;
import org.springframework.stereotype.Component;
//I have used #Repository or Qualifier etc, no avail
#Component
public class UserMilesHelper implements IUserMilesHelper {
#Override
public int getUserPoints(int userId) {
return 10;
}
}
Web.xml
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>throwExceptionIfNoHandlerFound</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>50</load-on-startup>
</servlet>
your User.java class have to be annotated with #Component too or any of its children for ex.
#Controller
#Service
#RestController
Spring initiliaze component in his context by scanning packages and looking for class annoted with stereotypes (#Controller, #Service, #Repository....) or by explicit instantiation with manually adding a bean. If you use a the new it won't call Spring initilization mecanism and won't inject the dependancy.
I suppose your User class is not a singleton class so you should add #Scope("prototype") and use applicationContext.getBean(User.class) to instantiate with dependancy.
But to be honest i would instead refactor the code to avoid public members and static method to set variable and have class like that:
#Service
public class UserService{
private IUserMilesHelper userHelper;
#Autowired
public UserService(IUserMilesHelper userHelper){
this.userHelper = userHelper:
}
public setUserPoints(User user){
user.setPoints(userHelper.getUserPoints(user.getUserId()));
}
}
By default, the name of the dispatcher servlet is xxx-servlet.xml where xxx is the servlet name. Which means that the spring is looking for dispatcher-servlet.xml, which is not the name of your XML config.
Thus the context itself is not loaded for you. Change it and test.
Apart from that, make sure that you follow best practises. Autowire on interfaces rather than on concrete class. Quick link for you - Spring: Why do we autowire the interface and not the implemented class?
pleae change <context:component-scan base-package="com.eos.accounts" /> to
<context:component-scan base-package="com.eos.accounts.*" />
give it a try and let me know the result.
hope it helps.

How does spring construct and auto wire maps

I am using spring for quite some time but this morning I came across with some unexpected behavior.
As I could not decide by myself whether that was a desired functionality or a bug I am presenting it here with the hope I will get some good explanations about why would this be happening.
In short I have multiple beans defined in an application context and I create two map beans using utils:map name space with only part of my beans added to those maps. The two maps have exactly the same entries.
Then I auto wire those maps. One auto wire is done using #Autowired annotation and the other one is done using #Resource
To my surprise the bean annotated with #Autowired had got all beans in the context not only the ones I specifically put in the map. The other one auto wired using #Resource annotation had only the expected two entries in it.
I am mainly interested in:
1. Why all the beans declared in my context of that time appear in the #Autowired map and not the ones I added
2. Why #Resource and #Autowired would behave differently
Here is the working code that reproduces the scenario described above.
Some interface here:
package my.testing.pkg;
public interface Foo {
void doStuff();
}
And its implementation:
package my.testing.pkg;
public class FooImpl implements Foo {
#Override
public void doStuff() {}
}
The spring config 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:utils="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<bean id="foo_1" class="my.testing.pkg.FooImpl"/>
<bean id="foo_2" class="my.testing.pkg.FooImpl"/>
<bean id="foo_3" class="my.testing.pkg.FooImpl"/>
<bean id="foo_4" class="my.testing.pkg.FooImpl"/>
<utils:map id="fooMap1" map-class="java.util.HashMap">
<entry key="foo_1" value-ref="foo_1"/>
<entry key="foo_2" value-ref="foo_2"/>
</utils:map>
<utils:map id="fooMap2" map-class="java.util.HashMap">
<entry key="foo_1" value-ref="foo_1"/>
<entry key="foo_2" value-ref="foo_2"/>
</utils:map>
</beans>
And the test case to reproduce the behavior:
package my.testing.pkg;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
import java.util.Map;
import static org.junit.Assert.assertEquals;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = "/test-context.xml")
public class SpringMapCreatingTest {
#Autowired
private Map<String, Foo> fooMap1;
#Resource
private Map<String, Foo> fooMap2;
#Test
public void shouldInjectATwoEntriesMap() throws Exception {
assertEquals("fooMap1 should have to entries", 2, fooMap1.size());
assertEquals("fooMap2 map should have to entries", 2, fooMap1.size());
}
}
Thank you in advance for your clarifications.
What is happening there is the following:
The #Autowired dependency will look for beans that match its type, and in this case it will create a map of your beans Foo mapped by their name. The same behavior will happen when you autowire on a list of beans, Spring will inject all the beans that implement the interface.
The #Resource dependency will look first for a bean that matches the dependency name, e.g fooMap2 and will inject it.
Take a look at the documentation http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-autowired-annotation-qualifiers
Maps / List are not handled as "standard" beans injection.
Take a look to those questions on so: Can spring #Autowired Map?
https://stackoverflow.com/a/13914052/1517816
HIH
Check the spring docs, the tips section:
beans that are themselves defined as a collection or map type cannot
be injected through #Autowired, because type matching is not properly
applicable to them. Use #Resource for such beans
So it is better to use #Resource and not #Autowired for maps

How Can I create Spring Bean outside of Spring Application Context

I'm developing some kind of plugin which should be called by external java app.
my Plugin is using Spring and of cause I tried to simplify my as I can:
Let's consider that this is 3d party app and it's calling my plugin in its main function.
public class ThirdPartyClass {
public static void main(String[] args) {
GeneralPlugin plugin = new MyPlugin();
plugin.init();
//calling ext. plugin functionality.
plugin.method1();
}
}
Now this is my plugin
package com.vanilla.spring;
#Component
public class MyPlugin implements GeneralPlugin{
#Autowired
Dao mydao;
public void init(){
//some initiation logic goes here...
}
public void method1(){
dao.delete();
}
}
Now my Dao
package com.vanilla.spring;
Component(value="dao")
public class MyDao {
public void delete(){
//SOME DATABASE LOGIC GOES HERE!!!
}
}
now my 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:p="http://www.springframework.org/schema/p"
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
<context:annotation-config />
<context:component-scan base-package="com.vanilla.spring"></context:component-scan>
</beans>
My problem is that my dao is null and I'm getting NullPointerException when accessing dao object.
I
m believe it happens because I'm initiation bean out of Application context and as the result my Autowiring is not working.
Is there any other way to make autowiring work?
"Spring beans" are just that: Java beans. They have no intrinsic abilities other than those given to them by inheritance or object instantiation.
The Spring Application Context is responsible for creating the bean and "wiring" it, which is the process of creating other beans in the context and calling the bean's setters (and constructors) with the results to configure them. To do this is uses the XML configuration file and annotations to decide what to create and where to put it.
If you aren't going to use an actual Application Context, then you have to do all of that work yourself, manually. That is, create the DAO with the proper data source, create the plugin bean, and set the DAO on the plugin bean.
In this specific example, since the 3rd party application controls the instantiation of your plugin bean, you will likely have to either a) create the DAO in the plugin constructor (which is what you're using Spring to avoid in the first place), or b) create an Application Context in the plugin constructor and reference the beans the plugin needs by querying the context. This isn't quite as useful as letting the context do everything, but at least you don't have to configure the rest of the beans your application uses manually (with user names, connection URLs, etc).
If you go the second route you would then need the Spring configuration file somewhere in the classpath or somehow otherwise able to be referenced by the plugin bean.

Spring #Async Not Working

An #Async method in a #Service-annotated class is not being called asynchronously - it's blocking the thread.
I've got <task: annotation-driven /> in my config, and the call to the method is coming from outside of the class so the proxy should be being hit. When I step through the code, the proxy is indeed hit, but it doesn't seem to go anywhere near any classes related to running in a task executor.
I've put breakpoints in AsyncExecutionInterceptor and they never get hit. I've debugged into AsyncAnnotationBeanPostProcessor and can see advice getting applied.
The service is defined as an interface (with the method annotated #Async there for good measure) with the implementation's method annotated #Async too. Neither are marked #Transactional.
Any ideas what may have gone wrong?
-=UPDATE=-
Curiously, it works only when I have my task XML elements in my app-servlet.xml file, and not in my app-services.xml file, and if I do my component scanning over services from there too. Normally I have one XML file with only controllers in it (and restrict the component-scan accordingly), and another with services in it (again with a component-scan restricted such that it doesn't re-scan the controllers loaded in the other file).
app-servlet.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:jee="http://www.springframework.org/schema/jee"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:webflow="http://www.springframework.org/schema/webflow-config"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:tx="http://www.springframework.org/schema/tx"
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/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-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/jee
http://www.springframework.org/schema/jee/spring-jee-3.0.xsd"
>
<task:annotation-driven executor="executor" />
<task:executor id="executor" pool-size="7"/>
<!-- Enable controller annotations -->
<context:component-scan base-package="com.package.store">
<!-- <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" /> -->
</context:component-scan>
<tx:annotation-driven/>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<mvc:annotation-driven conversion-service="conversionService" />
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
app-services.xml (doesn't work when specified here)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:task="http://www.springframework.org/schema/task"
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-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/task
http://www.springframework.org/schema/task/spring-task-3.0.xsd">
<!-- Set up Spring to scan through various packages to find annotated classes -->
<context:component-scan base-package="com.package.store">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>
<task:annotation-driven executor="han" />
<task:executor id="han" pool-size="6"/>
...
Am I missing something glaringly obvious in my configuration, or is there some subtle interplay between config elements going on?
For me the solution was to add #EnableAsync on my #Configuration annotated class:
#Configuration
#ComponentScan("bla.package")
#EnableAsync
public class BlaConfiguration {
}
Now the class in package bla.package which has #Async annotated methods can really have them called asynchronously.
With the help of this excellent answer by Ryan Stewart, I was able to figure this out (at least for my specific problem).
In short, the context loaded by the ContextLoaderListener (generally from applicationContext.xml) is the parent of the context loaded by the DispatcherServlet (generally from *-servlet.xml). If you have the bean with the #Async method declared/component-scanned in both contexts, the version from the child context (DispatcherServlet) will override the one in the parent context (ContextLoaderListener). I verified this by excluding that component from component scanning in the *-servlet.xml -- it now works as expected.
Jiří Vypědřík's answer solved my problem. Specifically,
Check if your method annotated with #Async is public.
Another useful information from Spring tutorials https://spring.io/guides/gs/async-method/:
Creating a local instance of the FacebookLookupService class does NOT
allow the findPage method to run asynchronously. It must be created inside
a #Configuration class or picked up by #ComponentScan.
What this means is that if you had a static method Foo.bar(), calling it in that manner wouldn't execute it in async, even if it was annotated with #Async. You'll have to annotate Foo with #Component, and in the calling class get an #Autowired instance of Foo.
Ie, if you have a annotated method bar in class Foo:
#Component
class Foo {
#Async
public static void bar(){ /* ... */ }
#Async
public void bar2(){ /* ... */ }
}
An in your caller class:
class Test {
#Autowired Foo foo;
public test(){
Foo.bar(); // Not async
foo.bar(); // Not async
foo.bar2(); // Async
}
}
Edit: Seems like calling it statically also doesn't execute it in async.
Hope this helps.
Try adding proxy-target-class="true" to all <*:annotation-driven/> elements that support this attribute.
Check if your method annotated with #Async is public.
In my case the #Async method was defined in same class as the sync method that used it, and that apparently caused all jobs to hang on current thread.
Bad
#Component
#EnableAsync
public class TranslationGapiReader {
#Async
public CompletableFuture<GapiFile> readFile(String fileId) {
try { Thread.sleep(2000); } catch (Exception exc) { throw new RuntimeException("ololo", exc); }
return CompletableFuture.completedFuture(null);
}
public Stream<GapiFile> readFiles(Iterable<String> fileIds) {
List<CompletableFuture<GapiFile>> futures = new ArrayList<>();
for (String fileId: fileIds) {
futures.add(readFile(fileId));
}
return Stream.empty();
}
}
Good
#Component
#EnableAsync
public class AsyncGapiFileReader {
#Async
public CompletableFuture<TranslationGapiReader.GapiFile> readFile(String fileId) {
try { Thread.sleep(2000); } catch (Exception exc) { throw new RuntimeException("ololo", exc); }
return CompletableFuture.completedFuture(null);
}
}
#Component
#EnableAsync
public class TranslationGapiReader {
#Autowired
AsyncGapiFileReader asyncGapiFileReader;
public Stream<GapiFile> readFiles(Iterable<String> fileIds) {
List<CompletableFuture<GapiFile>> futures = new ArrayList<>();
for (String fileId: fileIds) {
futures.add(asyncGapiFileReader.readFile(fileId));
}
return Stream.empty();
}
}
I'm not Spring guru enough to understand why does it only work when the #Async method is in a different class, but that's what fixes the issue from my observations.
Firstly make your .xml config looks like:
<task:scheduler id="myScheduler" pool-size="10" />
<task:executor id="myExecutor" pool-size="10" />
<task:annotation-driven executor="myExecutor" scheduler="myScheduler" proxy-target-class="true" />
(Yes, scheduler count and executor thread pool size is configurable)
Or just use default:
<!-- enable task annotation to support #Async, #Scheduled, ... -->
<task:annotation-driven />
Secondly make sure #Async methods are public.
#Async can not be used in conjunction with lifecycle callbacks such as #PostConstruct. To asynchonously initialize Spring beans you currently have to use a separate initializing Spring bean that invokes the #Async annotated method on the target then.
public class SampleBeanImpl implements SampleBean {
#Async
void doSomething() { … }
}
public class SampleBeanInititalizer {
private final SampleBean bean;
public SampleBeanInitializer(SampleBean bean) {
this.bean = bean;
}
#PostConstruct
public void initialize() {
bean.doSomething();
}
}
source
I realized following the tutorial async-method tutorial code that my issue source was: the bean with the annotated #Async method was not being created wrapped in a proxy.
I started digging and realized that there was a message saying
Bean 'NameOfTheBean' is not eligible for getting processed by all
BeanPostProcessors (for example: not eligible for auto-proxying)
You can see here responses about this issue and its basically that BeanPostProcessors are required by every Bean, so every bean injected here and its dependencies will be excluded to be processed later by other BeanPostProcessors, because it corrupted the life cycle of beans. So identify which is the BeanPostProcessor that is causing this and dont use or create beans inside of it.
In my case i had this configuration
#EnableWs
#Configuration
public class WebServiceConfig extends WsConfigurerAdapter {
#Autowired
private Wss4jSecurityInterceptor securityInterceptor;
#Autowired
private DefaultPayloadLoggingInterceptor payloadLoggingInterceptor;
#Override
public void addInterceptors(List<EndpointInterceptor> interceptors) {
interceptors.add(securityInterceptor);
interceptors.add(payloadLoggingInterceptor);
}
}
WsConfigurerAdapter is actually a BeanPostProcessor and you realize it because there is always a pattern: #Configuration that extends classes and override some of it functions to install or tweak beans involved in some non functional features, like web service or security.
In the aforementioned example you have to override the addInterceptors and added interceptors beans, so if you are using some annotation like #Async inside DefaultPayloadLoggingInterceptor it wont work. What is the solution? Get ride of WsConfigurerAdapter to start.
After digging a bit i realized a class named PayloadRootAnnotationMethodEndpointMapping at the end was which had all valid interceptors, so i did it manually insted of overriding a function.
#EnableWs
#Configuration
public class WebServiceConfig {
#Autowired
private Wss4jSecurityInterceptor securityInterceptor;
#Autowired
private DefaultPayloadLoggingInterceptor payloadLoggingInterceptor;
#Autowired
public void setupInterceptors(PayloadRootAnnotationMethodEndpointMapping endpointMapping) {
EndpointInterceptor[] interceptors = {
securityInterceptor,
payloadLoggingInterceptor
};
endpointMapping.setInterceptors(interceptors);
}
}
So this will be run after all BeanPostProcessor have done their job. The setupInterceptors function will run when that party is over and install the interceptors beans. This use case may be extrapolated to cases like Security.
Conclusions:
If you are using a #Configuration extending from some class that runs some given functions automatically and you override them, you are probably inside of a BeanPostProcessor, so dont inject beans there and try to use AOP behaviour, because it wont work, and you will see Spring tells it to you with the beforementioned message in the console. In those cases dont use beans but objects (using the new clause).
If you need to use beans digg about which class is carrying the beans you want to setup at the end, #Autowired it and add those beans like i did before.
I hope this may save some time for you.
You need 3 lines of code for Async to work
in applicationContext.xml
At class level #EnableAsync
#Async at method level
#Service
#EnableAsync
public myClass {
#Async
public void myMethod(){
}
write a independent Spring configuration for asynchronous bean.
for example:
#Configuration
#ComponentScan(basePackages="xxxxxxxxxxxxxxxxxxxxx")
#EnableAsync
public class AsyncConfig {
/**
* used by asynchronous event listener.
* #return
*/
#Bean(name = "asynchronousListenerExecutor")
public Executor createAsynchronousListenerExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setMaxPoolSize(100);
executor.initialize();
return executor;
}
}
I overcome this problem with this situation.
Try below:
1. In config create bean for ThreadPoolTaskExecutor
#Bean(name = "threadPoolTaskExecutor")
public Executor threadPoolTaskExecutor() {
return new ThreadPoolTaskExecutor();
}
2. In service method where #Async is used add
#Async("threadPoolTaskExecutor")
public void asyncMethod(){
//do something
}
This should get #Async working.

Spring autowiring using #Configurable

I'm playing with the idea of using Spring #Configurable and #Autowire to inject DAOs into domain objects so that they do not need direct knowledge of the persistence layer.
I'm trying to follow http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop.html#aop-atconfigurable, but my code seems to have no effect.
Basically, I have:
#Configurable
public class Artist {
#Autowired
private ArtistDAO artistDao;
public void setArtistDao(ArtistDAO artistDao) {
this.artistDao = artistDao;
}
public void save() {
artistDao.save(this);
}
}
And:
public interface ArtistDAO {
public void save(Artist artist);
}
and
#Component
public class ArtistDAOImpl implements ArtistDAO {
#Override
public void save(Artist artist) {
System.out.println("saving");
}
}
In application-context.xml, I have:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springsource.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" />
<bean class="org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect" factory-method="aspectOf"/>
</beans>
Class path scanning and initialisation is performed by the spring module for Play! framework, although other autowired beans work, so I'm pretty sure this is not the root cause. I'm using Spring 3.0.5.
In other code (inside a method in bean that's injected into my controller using Spring, in fact), I'm doing this:
Artist artist = new Artist();
artist.save();
This gives me a NullPointerException trying to access the artistDao in Artist.save().
Any idea what I'm doing wrong?
Martin
You need to enable load-time weaving (or other kinds of weaving) in order to use #Configurable. Make sure you enabled it correctly, as described in 7.8.4 Load-time weaving with AspectJ in the Spring Framework.
I was having this problem with Tomcat 7 using LTW trying to autowire beans into my domain classes.
There was some updates to the doc for 3.2.x at http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/aop.html#aop-configurable-container that revealed that one can use #EnableSpringConfigured instead of the xml configuration .
So I have the following annotation on my Domain object:
#Configurable(preConstruction=true,dependencyCheck=true,autowire=Autowire.BY_TYPE)
#EnableSpringConfigured
#EnableSpringConfigured is a substitue for
<context:spring-configured />
and don't forget to add this to your context xml file:
<context:load-time-weaver weaver-class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver" aspectj-weaving="on"/>
Of course I needed to setup Tomcat for load time weaving first.
Also, I ran into a bug in 3.2.0 (null pointer) so I needed to upgrade to Spring 3.2.1 (https://jira.springsource.org/browse/SPR-10108)
All is well now!
You should just look how Spring Roo does it since it does exactly what you want to do.
There are lots of things that can cause the NPE your having but most of the time it has to do with not compiling properly with AspectJ compiler and not having the Spring Aspects jar in your AspectJ lib path (this is different than your classpath).
First just try to get it to work with Maven and the AspectJ compiler plugin. Thats why I recommend Spring Roo as it will generate a POM file with the correct setup.
I have found #Configurable does not really work with LTW (despite one of the answers saying so). You need compile time weaving for #Configurable to work because the advice is happening at object construction time (constructor advice cannot be done with Springs LTW).
First, enable Spring debug logging. I use Log4j to do it. I've created a logger like so (with Log4j xml configuration so I can use RollingFileAppender):
<log4j:configuration>
<appender name="roll" class="org.apache.log4j.rolling.RollingFileAppender">
blah blah configuration blah blah
</appender>
<logger name="org.springframework">
<level value="debug" />
<appender-ref ref="roll" />
</logger>
</log4j:configuration>
This will allow you to see what Spring is doing and when.
Second, you have ArtistDAO autowired but I don't see where you have a bean named ArtistDAO. Your DAO component bean will be named "artistDaoImpl" by default. Try changing #Component to #Component("artistDao") and applying #Autowired to the setter instead:
private ArtistDAO artistDao;
#Autowired
public void setArtistDao(ArtistDAO artistDao)
{
this.artistDao = artistDao;
}
I had the same problem and never managed to get the code working with #Configurable and #Autowired. I finally decided to write an aspect myself which would handle the #Configurable and #Autowired annotations. Here is the code:
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
#SuppressWarnings( "rawtypes" )
#Aspect
public class AutoInjectDependecyAspect implements ApplicationContextAware {
private static final Logger LOGGER = Logger.getLogger( AutoInjectDependecyAspect.class );
private ApplicationContext applicationContext = null;
#Pointcut( "execution( (#org.springframework.beans.factory.annotation.Configurable *).new())" )
public void constructor() {
}
#Before( "constructor()" )
public void injectAutoWiredFields( JoinPoint aPoint ) {
Class theClass = aPoint.getTarget().getClass();
try{
Field[] theFields = theClass.getDeclaredFields();
for ( Field thefield : theFields ) {
for ( Annotation theAnnotation : thefield.getAnnotations() ) {
if ( theAnnotation instanceof Autowired ) {
// found a field annotated with 'AutoWired'
if ( !thefield.isAccessible() ) {
thefield.setAccessible( true );
}
Object theBean = applicationContext.getBean( thefield.getType() );
if ( theBean != null ) {
thefield.set( aPoint.getTarget(), theBean );
}
}
}
}
} catch ( Exception e ) {
LOGGER.error( "An error occured while trying to inject bean on mapper '" + aPoint.getTarget().getClass() + "'", e );
}
}
#Override
public void setApplicationContext( ApplicationContext aApplicationContext ) throws BeansException {
applicationContext = aApplicationContext;
}
}
Next in your spring context define the aspect so that the springcontext will be injected into the aspect
<bean class="[package_name].AutoInjectDependecyAspect" factory-method="aspectOf"/>
Perhaps using the #Repository annotation for the DAO will do it.
try : #Configurable(autowire=Autowire.BY_TYPE). Autowired defaults to off :<
I had a similar issue that I resolved today. The important thing is that you need to enable load-time weaving and make sure the appropriate aspectj classes are loaded. In your pom.xml you need to add the aspectjweaver artifact:
...
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.12</version>
</dependency>
....
You can change the version if you need to. Then, I would go the xsd route in you application-context.xml instead of the DTD route:
<?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-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!--Scans the classpath for annotated components #Component, #Repository, #Service, and #Controller -->
<context:component-scan base-package="your.base.package"/>
<!--Activates #Required, #Autowired, #PostConstruct, #PreDestroy and #Resource -->
<context:annotation-config/>
<!--This switches on the load-time weaving for #Configurable annotated classes -->
<context:load-time-weaver/>
</beans>
Also, please verify that your version of AspectJ is current. I wasted a few hours trying to make this work, and the cause was an old version of Aspectjweaver.jar. I updated to 1.7.2 and everything worked like a charm.
There is a bug with #Configurable and LTW. If you use your class as a parameter in any method the auto wiring stops working.
https://jira.spring.io/plugins/servlet/mobile#issue/SPR-8502

Categories