2011-01-16 2 views
29

Я играю с идеей использования Spring @Configurable и @Autowire для ввода DAO в объекты домена, чтобы они не нуждались в непосредственном знании уровня персистентности.Весна автоволна с использованием @Configurable

Я пытаюсь следовать 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"); 
    } 

} 

В прикладном 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 3.0.5.

В другом коде (внутри метода в компоненте, который вводится в мой контроллер с помощью Spring, на самом деле), я делаю это:

Artist artist = new Artist(); 
artist.save(); 

Это дает мне NullPointerException пытается получить доступ к artistDao в Художника .спасти().

Любая идея, что я делаю неправильно?

Martin

+0

related;) http://techblog.bozho.net/?p=180 – Bozho

+0

Можете ли вы использовать аннотацию '@ Value' в своем классе« @ Configurable »Artist? – NightWolf

ответ

1

Возможно, используя @Repository аннотацию для DAO будет делать это.

+0

Согласен. Он должен использовать @Repository вместо – chris

+2

Как это может быть связано с '@ Configurable'? – axtavt

+5

Можете ли вы объяснить, почему это изменило бы ситуацию? – Paul

7

Чтобы использовать @Configurable, вам необходимо включить переплетение во времени (или другие виды ткачества). Убедитесь, что вы включили его правильно, как описано в 7.8.4 Load-time weaving with AspectJ in the Spring Framework.

+1

Это неправильно. Вам не нужна LTW для поддержки @Configurable. Spring Roo делает то, что хочет, и не использует LTW. Скорее всего, его проблема заключается в том, что он не компилирует код с помощью компилятора AspectJ и Spring Aspects. –

+4

@AdamGent Он сказал LTW (или другие виды плетения). , , Для Настраиваемой аннотации вам нужно либо ткачество, либо время компиляции. –

+0

@ JasperBlues вы правы, что LTW должен работать. Я никогда не мог заставить его работать в своей среде и думал, что я прочитал в * AspectJ в действии *, что с LTW невозможно было конструировать совет. –

4

Сначала включите ведение журнала отладки Spring. Для этого я использую Log4j. Я создал регистратор как так (с конфигурацией XML Log4j так что я могу использовать 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> 

Это позволит вам увидеть, что весна делает и когда.

Во-вторых, у вас есть Authentication, но я не вижу, где у вас есть bean named ArtistDAO. По умолчанию компонент компонента DAO будет называться «artistDaoImpl». Попробуйте изменить @Component к @Component("artistDao") и применяя @Autowired к сеттер вместо:

private ArtistDAO artistDao; 

@Autowired 
public void setArtistDao(ArtistDAO artistDao) 
{ 
    this.artistDao = artistDao; 
} 
3

Вы должны просто посмотреть, как Spring Roo делает это, так как это делает именно то, что вы хотите сделать.

Есть много вещей, которые могут вызвать NPE вашего иметь, но большую часть времени он должен делать с не компиляциями должным образом с AspectJ компилятором и не имея пружинные аспекты баночки в вашем Lib пути AspectJ (это отличается от вашего класса).

Сначала попробуйте заставить его работать с Maven и плагином компилятора AspectJ. Вот почему я рекомендую Spring Roo, поскольку он будет генерировать POM-файл с правильной настройкой.

Я нашел @Configurable не работает с LTW (несмотря на один из ответов, говорящих так). Вам нужно время компиляции для @Configurable, чтобы работать, потому что совет происходит в момент построения объекта (конструктор не может быть сконфигурирован с помощью Springs LTW).

+0

Какие проблемы у вас возникли при загрузке во времени? Я использовал его довольно успешно. Я использую LTW для тестирования интеграции и компиляции во время разворачивания. , Таким образом, мои отчеты об охвате тестов выглядят красиво, но мое развертывание является надежным. –

+0

Поскольку '@ Configurable' позволяет использовать обычные Java-конструкторы для создания экземпляра объекта. Совет применяется к конструктору объектов. ** Я думал, что вы можете применить совет конструктора с использованием плетения времени компиляции **, но, похоже, вы также можете сделать это с помощью LTW. Итак, вы правы. То, что вы не можете сделать (и именно поэтому я был в замешательстве), делает AspectJ ITD с LTW. –

+0

Ahhh, я вижу. , Не знал этого. –

1

try: @Configurable (autowire = Autowire.BY_TYPE). Автоподключено по умолчанию: <

1

У меня была аналогичная проблема, которую я разрешил сегодня. Важно то, что вам нужно включить вождение во время загрузки и убедиться, что загружены соответствующие классы aspectj. В вашем pom.xml вам нужно добавить aspectjweaver artifact:

... 
<dependency> 
    <groupId>org.aspectj</groupId> 
    <artifactId>aspectjweaver</artifactId> 
    <version>1.6.12</version> 
</dependency> 
.... 

Вы можете изменить версию, если вам нужно. Тогда я пошел бы на XSD маршрут в вас прикладном context.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-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> 
6

У меня была эта проблема с Tomcat 7 с помощью LTW пытается autowire бобы в моих классов предметной области.

Были обновлены документы doc для 3.2.x по адресу http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/aop.html#aop-configurable-container, которые показали, что вместо конфигурации xml можно использовать @EnableSpringConfigured.

Так что я следующая аннотация на моем объекте домена:

@Configurable(preConstruction=true,dependencyCheck=true,autowire=Autowire.BY_TYPE) 
@EnableSpringConfigured 

@EnableSpringConfigured является substitue для

<context:spring-configured /> 

и не забудьте добавить это в файл XML контекста:

<context:load-time-weaver weaver-class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver" aspectj-weaving="on"/> 

Конечно, мне нужно было установить Tomcat для первого времени загрузки.

Кроме того, я столкнулся с ошибкой в ​​3.2.0 (пустой указатель), поэтому мне нужно обновить до весны 3.2.1 (https://jira.springsource.org/browse/SPR-10108)

Все хорошо сейчас

0

Кроме того, убедитесь, что ваша версия AspectJ актуальна. Я потратил несколько часов на то, чтобы сделать эту работу, и причиной стала старая версия Aspectjweaver.jar. Я обновился до 1.7.2, и все работало как шарм.

3

У меня была такая же проблема, и мне не удалось получить код, работающий с @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; 
    } 

} 

Следующая в вашем весеннем контексте определяют аспект, так что springcontext будет закачиваться в аспекте

<bean class="[package_name].AutoInjectDependecyAspect" factory-method="aspectOf"/> 
Смежные вопросы