Ответ 1
Чтобы использовать @Configurable
, вам необходимо включить временное плетение (или другие виды плетения). Убедитесь, что вы включили его правильно, как описано в 7.8.4 Тесное время загрузки с AspectJ в Spring Framework.
Я играю с идеей использования Spring @Configurable
и @Autowire
для ввода DAO в объекты домена, чтобы они не нуждались в непосредственном знании уровня персистентности.
Я пытаюсь следовать http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop.html#aop-atconfigurable, но мой код, похоже, не имеет эффекта.
В принципе, у меня есть:
@Configurable
public class Artist {
@Autowired
private ArtistDAO artistDao;
public void setArtistDao(ArtistDAO artistDao) {
this.artistDao = artistDao;
}
public void save() {
artistDao.save(this);
}
}
и
public interface ArtistDAO {
public void save(Artist artist);
}
и
@Component
public class ArtistDAOImpl implements ArtistDAO {
@Override
public void save(Artist artist) {
System.out.println("saving");
}
}
В application-context.xml у меня есть:
<?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>
Сканирование и инициализация маршрута класса выполняется модулем Spring для Play! хотя, несмотря на то, что другие работающие в режиме beans работают, поэтому я уверен, что это не основная причина. Я использую Spring 3.0.5.
В другом коде (внутри метода в bean, который был введен в мой контроллер с помощью Spring), я делаю это:
Artist artist = new Artist();
artist.save();
Это дает мне исключение NullPointerException, пытающееся получить доступ к ArtistDao в Artist.save().
Любая идея, что я делаю неправильно?
Martin
Чтобы использовать @Configurable
, вам необходимо включить временное плетение (или другие виды плетения). Убедитесь, что вы включили его правильно, как описано в 7.8.4 Тесное время загрузки с AspectJ в Spring Framework.
У меня возникла проблема с Tomcat 7 с использованием LTW, пытающегося autowire beans в мои классы домена.
В документе doc для 3.2.x появилось несколько обновлений http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/aop.html#aop-configurable-container, в котором показано, что вместо xml-конфигурации можно использовать @EnableSpringConfigured.
Итак, у меня есть следующая аннотация для моего объекта Domain:
@Configurable(preConstruction=true,dependencyCheck=true,autowire=Autowire.BY_TYPE)
@EnableSpringConfigured
@EnableSpringConfigured является заменой для
<context:spring-configured />
и не забудьте добавить это в свой XML файл контекста:
<context:load-time-weaver weaver-class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver" aspectj-weaving="on"/>
Конечно, мне нужно было сначала настроить Tomcat для загрузки времени загрузки.
Кроме того, я столкнулся с ошибкой в 3.2.0 (нулевой указатель), поэтому мне нужно было перейти на Spring 3.2.1 (https://jira.springsource.org/browse/SPR-10108)
Теперь все хорошо!
Сначала включите ведение журнала отладки Spring. Для этого я использую Log4j. Я создал такой регистратор (с конфигурацией Log4j xml, поэтому я могу использовать 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>
Это позволит вам увидеть, что делает Spring и когда.
Во-вторых, у вас есть Authentication, но я не вижу, где у вас есть bean с именем ArtistDAO. По умолчанию ваш компонент DAO bean будет называться "artistDaoImpl". Попробуйте изменить @Component
на @Component("artistDao")
и вместо этого примените @Autowired
к установщику:
private ArtistDAO artistDao;
@Autowired
public void setArtistDao(ArtistDAO artistDao)
{
this.artistDao = artistDao;
}
Вы должны просто посмотреть, как Spring Roo делает это, поскольку делает именно то, что вы хотите сделать.
Есть много вещей, которые могут привести к тому, что NPE будет иметь, но большую часть времени он должен делать, не компилируя должным образом с помощью AspectJ компилятора и не имея Spring Apects jar в вашем пути AspectJ lib (это отличается от вашего пути к классам).
Сначала попробуйте заставить его работать с Maven и плагином компилятора AspectJ. Вот почему я рекомендую Spring Roo, поскольку он будет генерировать POM файл с правильной настройкой.
Я нашел, что @Configurable не работает с LTW (несмотря на один из ответов, говорящих так). Вам нужно скомпилировать время для работы @Configurable для работы, потому что совет выполняется при времени построения объекта (конструктор не может быть сконфигурирован с помощью Springs LTW).
У меня была такая же проблема, и мне не удалось получить код, работающий с @Configurable и @Autowired. Наконец, я решил написать сам аспект, который будет обрабатывать аннотации @Configurable и @Autowired. Вот код:
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;
}
}
Далее в вашем контексте spring определите аспект так, чтобы текст springcontext был введен в аспект
<bean class="[package_name].AutoInjectDependecyAspect" factory-method="aspectOf"/>
Возможно, используя @Repository аннотация для DAO сделает это.
попробуйте: @Configurable (autowire = Autowire.BY_TYPE). Автоустановка по умолчанию отключена: <
У меня была аналогичная проблема, которую я разрешил сегодня. Важно то, что вам нужно включить вождение во время загрузки и убедиться, что загружены соответствующие классы aspectj. В вашем pom.xml вам нужно добавить артефакт анимированного изображения:
...
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.12</version>
</dependency>
....
Вы можете изменить версию, если вам нужно. Тогда я бы отправил xsd-маршрут в ваш application-context.xml вместо 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>
Также убедитесь, что ваша версия AspectJ актуальна. Я потратил несколько часов на то, чтобы сделать эту работу, и причиной стала старая версия Aspectjweaver.jar. Я обновился до 1.7.2, и все работало как прелесть.
Есть ошибка с @Configurable и LTW. Если вы используете свой класс в качестве параметра любым способом, автоматическая проводка перестает работать. https://jira.spring.io/plugins/servlet/mobile#issue/SPR-8502