Spring bean-компонент для аспекта @Aspect равен нулю - PullRequest
31 голосов
/ 09 марта 2012

У меня следующая конфигурация пружины:

<context:component-scan base-package="uk.co.mysite.googlecontactsync.aop"/>

<bean name="simpleEmailSender" class="uk.co.mysite.util.email.simple.SimpleEmailSenderImplementation"/>

<aop:aspectj-autoproxy/>

Тогда у меня есть аспект:

@Aspect
public class SyncLoggingAspect {
    @Autowired
    private SimpleEmailSender simpleEmailSender

    @AfterReturning(value="execution(* uk.co.mysite.datasync.polling.Poller+.doPoll())", returning="pusher")
    public void afterPoll(Pusher pusher) {      
        simpleEmailSender.send(new PusherEmail(pusher));
    }
}

Этот аспект работает (я могу достичь точки останова на afterPoll), но simpleEmailSender имеет значение null. К сожалению, я не могу найти четкую документацию о том, почему это так. (Кстати, мой bean-компонент simpleEmailSender существует и правильно подключен к другим классам) Меня смущают следующие вещи:

  1. Является ли контекст: компонентное сканирование должно обрабатывать @Aspect? Если это так, то это будет бин с пружинным управлением, поэтому сработает autowired?
  2. Если context: component-scan не предназначен для создания аспектов, как создается мой аспект? Я думал, что aop: aspectj-autoproxy просто создает beanPostProcessor для прокси моего класса @Aspect? Как бы это сделать, если это не боб с пружинным управлением?

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

Ответы [ 9 ]

33 голосов
/ 12 марта 2012

Аспект является одноэлементным объектом и создается вне контейнера Spring.Решение с конфигурацией XML состоит в том, чтобы использовать фабричный метод Spring для получения аспекта.

<bean id="syncLoggingAspect" class="uk.co.demo.SyncLoggingAspect" 
     factory-method="aspectOf" />

В этой конфигурации аспект будет обрабатываться как любой другой компонент Spring, и автоматическое подключение будет работать как обычно.

Вы должны использовать фабричный метод также для объектов Enum и других объектов без конструктора или объектов, созданных вне контейнера Spring.

18 голосов
/ 18 апреля 2012

Другой вариант - добавить @Configurable к вашему классу аспектов, а не возиться с XML.

8 голосов
/ 06 сентября 2017

Чтобы Spring Boot использовал @Autowired с AspectJ, я нашел следующий метод.В классе конфигурации добавьте ваш аспект:

@Configuration
@ComponentScan("com.kirillch.eqrul")
public class AspectConfig {

    @Bean
    public EmailAspect theAspect() {
        EmailAspect aspect = Aspects.aspectOf(EmailAspect.class);
        return aspect;
    }

}

Затем вы можете успешно подключить ваши сервисы в вашем классе аспектов:

@Aspect
public class EmailAspect {

    @Autowired
    EmailService emailService;
4 голосов
/ 14 июля 2015

У меня нет 50 повторений, чтобы комментировать вопрос, так что вот еще один ответ, относящийся к @ Jitendra Vispute ответу.Официальный документ Spring упоминает:

Вы можете зарегистрировать классы аспектов как обычные bean-компоненты в вашей конфигурации Spring XML или автоматически определять их посредством сканирования пути к классам - как и любой другой bean-объект, управляемый Spring.Однако обратите внимание, что аннотации @Aspect недостаточно для автоопределения в пути к классам: для этого вам необходимо добавить отдельную аннотацию @Component (или, альтернативно, нестандартную аннотацию стереотипа, которая соответствует правилам сканера компонентов Spring). Источник: Spring '4.1.7.Release' документация .

Это будет означать, что добавление аннотации @Component и добавление @ComponentScan в вашу конфигурацию приведут к примеру @Jitendra VisputeРабота.Для примера весенней загрузки это работает, хотя я не возился с обновлением контекста. Пример весенней загрузки :

Приложение :

package sample.aop;
@SpringBootApplication
public class SampleAopApplication implements CommandLineRunner {
    // Simple example shows how an application can spy on itself with AOP
    @Autowired
    private HelloWorldService helloWorldService;
    @Override
    public void run(String... args) {
        System.out.println(this.helloWorldService.getHelloMessage());
    }
    public static void main(String[] args) throws Exception {
        SpringApplication.run(SampleAopApplication.class, args);
    }
}

Приложение также должно работать как простое приложение Spring Framework со следующими аннотациями вместо @SpringBootApplication:

  • @ Configuration
  • @ EnableAspectJAutoProxy
  • @ ComponentScan

и AnnotationConfigApplicationContext вместо SpringApplication.

Служба :

package sample.aop.service;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class HelloWorldService {
    @Value("${name:World}")
    private String name;
    public String getHelloMessage() {
        return "Hello " + this.name;
    }
}

Аспект монитора :

package sample.aop.monitor;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class ServiceMonitor {
    @AfterReturning("execution(* sample..*Service.*(..))")
    public void logServiceAccess(JoinPoint joinPoint) {
        System.out.println("Completed: " + joinPoint);
    }
}
4 голосов
/ 16 сентября 2013

Настройка @ Autowired только с настройкой java (поэтому конфигурация не основана на XML) требует немного дополнительной работы, чем просто добавление @ Configuration в класс, так как для него также требуется aspectOf способ.

Для меня сработало создание нового класса:

@Component
public class SpringApplicationContextHolder implements ApplicationContextAware {

    private static ApplicationContext applicationContext = null;

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
       this.applicationContext = applicationContext;
    }
}

И затем используйте это в своем аспекте в сочетании с использованием @ DependsOn @Configured и @Autowired:

@DependsOn("springApplicationContextHolder")
@Configuration
@Aspect
public class SomeAspect {

    @Autowired
    private SomeBean someBean;

    public static SomeAspect aspectOf() {
        return SpringApplicationContextProvider.getApplicationContext().getBean(SomeAspect.class);
    }

@DependsOn необходим, потому что spring не может определить зависимость, потому что компонент используется статически.

2 голосов
/ 03 июля 2014

Добавьте @Component к классу аспектов, и ваши зависимости должны быть введены автоматически. и добавьте контекст: компонент-сканирование для пакета, где ваш аспект находится в файле контекста весны.

@Component
@Aspect
public class SomeAspect {
    /* following dependency should get injected */
    @Autowired
    SomeTask someTask;
    /* rest of code */  
}
2 голосов
/ 12 июля 2012

Это сообщение в блоге объясняет это очень хорошо.В связи с тем, что аспект-синглтон создается вне контейнера Spring, вам нужно будет использовать factory-method = ”aspectOf”, который доступен только после его добавления AspectJ (не Spring AOP):

Обратите внимание на factory-method = ”aspectOf”, который сообщает Spring, чтобы использовать настоящий аспект AspectJ (не Spring AOP) для создания этого bean-компонента.Чтобы после сплетения аспекта у него был метод «aspectOf».

Чтобы:

Не найдено подходящего фабричного метода: фабричный метод 'aspectOf ()'- Это означало бы, что аспект не был сплетен ткачом AspectJ.

Из моего опыта с пружиной 3.1, если я не использую @Autowired, но традиционный установщик для внедрения зависимости, он внедряется и работаеткак и следовало ожидать, без аспекта.Хотя я сталкиваюсь с проблемами, связанными с тем, что аспект является синглтоном ... Это приводит к "пертиской" модели реализации..

0 голосов
/ 29 сентября 2018
@Configurable(autowire = Autowire.BY_TYPE)

Добавьте эту аннотацию к вашему Aspectj классу.Тогда он будет обработан Spring IOC.

0 голосов
/ 16 ноября 2015

Используйте ткачество времени компиляции, см. Пример плагина по адресу: https://github.com/avner-levy/minimal_spring_hibernate_maven_setup/blob/master/pom.xml

Следующая комбинация аннотации и конфигурации Spring работает для меня благодаря примечаниям Тобиаса / Вилли / Эрика:

Класс:

package com.abc
@Configurable
@Aspect
public class MyAspect {
   @Autowired
   protected SomeType someAutoWiredField;
}

XML:

<context:spring-configured />
<context:component-scan base-package="com.abc" />
...