Utilisation de @ Configurable
je suis en train de jouer avec l'idée d'utiliser le Printemps @Configurable
et @Autowire
injecter des Oad dans des objets de domaine pour qu'ils n'aient pas besoin d'une connaissance directe de la couche de persistance.
j'essaie de suivre http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop.html#aop-atconfigurablemais mon code ne semble pas avoir d'effet.
En Gros, Je avoir:
@Configurable
public class Artist {
@Autowired
private ArtistDAO artistDao;
public void setArtistDao(ArtistDAO artistDao) {
this.artistDao = artistDao;
}
public void save() {
artistDao.save(this);
}
}
Et:
public interface ArtistDAO {
public void save(Artist artist);
}
et
@Component
public class ArtistDAOImpl implements ArtistDAO {
@Override
public void save(Artist artist) {
System.out.println("saving");
}
}
Dans l'application de contexte.xml, j'ai:
<?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>
le balayage et l'initialisation du chemin de classe sont effectués par le module à ressort pour le jeu! cadre, bien que d'autres haricots autowired fonctionnent, donc je suis assez sûr que ce n'est pas la cause profonde. J'utilise le ressort 3.0.5.
dans un autre code (à l'intérieur d'une méthode en haricot qui est injecté dans mon contrôleur en utilisant le ressort, en fait), je fais ceci:
Artist artist = new Artist();
artist.save();
cela me donne une NullPointerException essayant d'accéder à l'artistDao dans Artist.enregistrer.)(
une idée de ce que je fais de mal?
Martin
10 réponses
Vous devez activer au moment du chargement de tissage (ou d'autres types de tissage) afin d'utiliser @Configurable
. Assurez-vous que vous avez activé correctement, comme décrit dans 7.8.4 tissage charge-temps à L'aide d'une attelle dans le cadre du ressort.
J'avais ce problème avec Tomcat 7 utilisant LTW essayant d'autowire beans dans mes classes de domaine.
il y a eu quelques mises à jour du doc pour 3.2.x à http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/aop.html#aop-configurable-container cela a révélé que l'on peut utiliser @EnableSpringConfigured à la place de la configuration xml .
J'ai donc l'annotation suivante sur mon domaine objet:
@Configurable(preConstruction=true,dependencyCheck=true,autowire=Autowire.BY_TYPE)
@EnableSpringConfigured
@EnableSpringConfigured is a substitute for
<context:spring-configured />
et n'oubliez pas de l'ajouter à votre contexte fichier xml:
<context:load-time-weaver weaver-class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver" aspectj-weaving="on"/>
bien sûr, J'avais besoin de configurer Tomcat pour le tissage du temps de charge en premier.
aussi, j'ai rencontré un bug dans 3.2.0 (pointeur null) donc j'ai dû mettre à jour vers le printemps 3.2.1 (https://jira.springsource.org/browse/SPR-10108)
tout va bien maintenant!
tout d'abord, activez la journalisation de débogage au printemps. J'utilise Log4j pour le faire. J'ai créé un logger comme so (avec la configuration Log4j xml pour que je puisse utiliser 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>
cela vous permettra de voir ce que le printemps fait et quand.
Deuxièmement, vous avez ArtistDAO autowired mais je ne vois pas où vous avez un haricot nommé ArtistDAO. Votre Fève de Composant DAO sera nommé "artistdaoipl" par défaut. Essayez de changer @Component
@Component("artistDao")
et en appliquant @Autowired
pour le setter plutôt:
private ArtistDAO artistDao;
@Autowired
public void setArtistDao(ArtistDAO artistDao)
{
this.artistDao = artistDao;
}
Vous devez juste regarder comment Spring Roo depuis qu'il a fait exactement ce que vous voulez faire.
Il ya beaucoup de choses qui peuvent causer le NPE votre avoir, mais la plupart du temps, il a à voir avec le fait de ne pas compiler correctement avec compilateur AspectJ et ne pas avoir le printemps jar dans votre chemin AspectJ lib (c'est différent de votre chemin classpath).
tout d'abord essayer de le faire fonctionner avec Maven et le compilateur AspectJ plugin. C'est pourquoi je recommande Spring Roo car il va générer un fichier POM avec la bonne configuration.
j'ai trouvé que @Configurable ne fonctionne pas vraiment avec LTW (malgré l'une des réponses le disant). Vous avez besoin de compiler le tissage de temps pour que @Configurable fonctionne parce que le Conseil se produit au moment de la construction de l'objet (le Conseil du constructeur ne peut pas être fait avec Springs LTW).
j'ai eu le même problème et je n'ai jamais réussi à faire fonctionner le code avec @Configurable et @Autowired. J'ai finalement décidé d'écrire un aspect moi-même qui traiterait les annotations @Configurable et @Autowired. Voici le 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 dans votre contexte de printemps définissez l'aspect de façon à ce que le contexte de printemps soit injecté dans l'aspect
<bean class="[package_name].AutoInjectDependecyAspect" factory-method="aspectOf"/>
peut-être en utilisant le @Repository annotation pour la DAO le faire.
essayez : @Configurable(autowire=Autowire.BY_TYPE). Autocâblés par défaut est off :<
j'ai eu un problème similaire, j'ai résolu aujourd'hui. L'important est que vous devez activer le tissage charge-temps et s'assurer que les classes appropriées d'aspectj sont chargées. Dans votre pom.xml, vous devez ajouter le artefact spectjweaver:
...
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.12</version>
</dependency>
....
vous pouvez changer la version si vous en avez besoin. Ensuite, je suivrais la route xsd dans votre contexte d'application.xml au lieu de la route DTD:
<?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>
veuillez également vérifier que votre version D'AspectJ est à jour. J'ai passé quelques heures à essayer de faire en sorte que ça marche, et la cause était une vieille version D'Aspectjweaver.pot. J'ai mis à jour 1.7.2 et tout a fonctionné comme un charme.
il y a un bug avec @Configurable et LTW. Si vous utilisez votre classe comme paramètre dans n'importe quelle méthode, le câblage automatique cesse de fonctionner. https://jira.spring.io/plugins/servlet/mobile#issue/SPR-8502