I'm trying to use automatic dependency injection via Spring's @Configurable annotation w/ @Resource on the fields needing injection. This involved some setup, like passing spring-agent.jar to my JVM. For the full details see here.
It works… mostly. When my Tomcat is booting up, I see the AspectJ init messages, my User objects automatically get FileService references, etc.
The problem is that sometimes it just doesn't happen. It appears to be completely random; sometimes I boot up and the dependencies are not injected, sometimes they are. I previously had trouble with @Transactional being on my User because it created a conflict, I believe with proxies. I am using JPA, so my User is marked with @Entity, so my best guess right now is that this is creating a conflict. I've read you can't auto proxy a proxy. To offset the conflict, I followed some notes I found online about excluding CGLIB and javassist which Hibernate (my JPA impl) uses.
Clues:
- It's all or nothing. All of my @Configurable instances have been injected or none of them.
- Reloading (reinstantiating) the Entity from the DB doesn't appear to help; it's either working or not.
- Rebooting Tomcat any number of time also won't even fix it. The only thing that appears to roll the dice again is a redeploy. In other words, if I redeploy it may work.
How can I figure out what is going wrong? Is anyone using @Configurable with JPA? Why isn't my dependencyCheck = true throwing an error when dependencies are not actually injected?
Entity
@Entity
@Configurable(dependencyCheck = true)
@NamedQueries( { @NamedQuery(name = "User.findAll", query = "SELECT user FROM User user"),
@NamedQuery(name = "User.findByEmail", query = "SELECT user FROM User user WHERE user.email = :email") })
public abstract class User extends BaseModel {
private static final long serialVersionUID = 7881431079061750040L;
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
private Long id;
@Column(unique = true, nullable = false)
private String email;
@Basic(optional = false)
private String password;
@Resource
private transient UserEmailer userEmailer;
@Resource
private transient FileService fileService;
...
aop.xml
<!DOCTYPE aspectj PUBLIC
"-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<weaver options="-verbose">
<include within="com.myapp.domain..*" />
<exclude within="*..*CGLIB*" />
<exclude within="*..*javassist*" />
</weaver>
<aspects>
<aspect name="org.springframework.beans.factory.aspectj.AbstractInterfaceDrivenDependencyInjectionAspect" />
</aspects>
</aspectj>
applicationContext.xml
...
<context:spring-configured />
<context:load-time-weaver />
<context:component-scan base-package="com.myapp" />
...
Best Solution
First I have to say that it is probably not a good idea to have resources, services or other beans injected into data model classes as dependencies. But that is a question of design.
To the usage of @Configurable I used it in cases where objects are instantiated from outside the Spring context - like custom tags in web applications, filters or servlets. The first way I tried to use them was by load time weaving like you do. That worked quite well but it had some drawbacks like hot code deployment while debugging did not work anymore.
I did also experience exactly the problem you describe and so I decided to switch from load time weaving to compile time. Therefor I installed the AJDT plugin in Eclipse and used the aspecjt support of Spring. That solved my problems.