Spring autowired bean для аспекта @ Aspect имеет значение null
у меня есть следующая весенняя конфигурация:
<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. К сожалению, я не могу найти четкую документацию о том, почему это так. (Для записи мой simpleemailsender bean существует и правильно подключен к другим классам) меня смущают следующие вещи:
- является ли context: component-scan должен собирать @Aspect? Если это тогда, конечно, это будет spring managed bean, таким образом, autowired должен работать?
- если context: component-scan не предназначен для создания аспектов, как создается мой аспект? Я думал, что aop:aspectj-autoproxy просто создает beanPostProcessor для прокси-класса @Aspect? Как бы это сделать, если это не spring managed bean?
очевидно, вы можете сказать, что у меня нет понимания, как нужно работать с нуля.
9 ответов
аспект является одноэлементным объектом и создается вне контейнера Spring. Решение с конфигурацией XML заключается в использовании Заводского метода Spring для извлечения аспекта.
<bean id="syncLoggingAspect" class="uk.co.demo.SyncLoggingAspect"
factory-method="aspectOf" />
С этой конфигурацией аспект будет рассматриваться как любой другой Spring bean, и autowiring будет работать как обычно.
вы должны использовать factory-method также для объектов перечисления и других объектов без конструктора или объектов, созданных вне Spring контейнер.
для Spring Boot для использования @Autowired с AspectJ я нашел следующий метод. В классе конфигурации добавьте свой аспект:
@Configuration
@ComponentScan("com.kirillch.eqrul")
public class AspectConfig {
@Bean
public EmailAspect theAspect() {
EmailAspect aspect = Aspects.aspectOf(EmailAspect.class);
return aspect;
}
}
после этого вы можете успешно autowire ваши обслуживания в вашем классе аспекта:
@Aspect
public class EmailAspect {
@Autowired
EmailService emailService;
у меня нет 50 rep, чтобы прокомментировать вопрос, поэтому вот еще один ответ, касающийся @ Джитендра Vispute ответ. Официальный весенний документ упоминает:
вы можете зарегистрировать классы аспектов как обычные бобы в конфигурации Spring XML или автоопределить их с помощью сканирования classpath - как и любой другой управляемый Spring Боб. Однако обратите внимание, что аннотации @Aspect недостаточно для автоопределения в пути к классам: для этого необходимо добавить отдельная аннотация @Component (или, альтернативно, пользовательская аннотация стереотипа, которая квалифицируется в соответствии с правилами сканера компонентов Spring).Источник: Spring ' 4.1.7.Release ' documentation.
это означало бы, что добавление аннотации @Component и добавление @ComponentScan в вашу конфигурацию заставит работать пример @Jitendra Vispute. Для образца spring boot aop он работал, хотя я не возился с обновлением контекста.Весна загрузите образец aop:
приложение:
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);
}
}
настройка @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 @настроено и @Autowired:
@DependsOn("springApplicationContextHolder")
@Configuration
@Aspect
public class SomeAspect {
@Autowired
private SomeBean someBean;
public static SomeAspect aspectOf() {
return SpringApplicationContextProvider.getApplicationContext().getBean(SomeAspect.class);
}
@DependsOn необходим, потому что spring не может определить зависимость, потому что Боб используется статично.
этой блоге объясняет это очень хорошо. Из-за того, что аспект singleton создается вне контейнера spring, вам нужно будет использовать factory-method="aspectOf", который доступен только после того, как он вплетен AspectJ ( не Spring AOP ) :
уведомление factory-method= "aspectOf", который сообщает Spring использовать реальный AspectJ (не Spring AOP ) аспект для создания этого компонента. Так что после аспект сплетен в нем имеет "aspectOf" метод.
Так что :
не найден соответствующий заводской метод: заводской метод "aspectOf ()" - это это означало бы, что аспект не был соткан AspectJ weaver.
из моего опыта работы с spring 3.1, Если я не использую @Autowired, но традиционный сеттер для инъекции зависимостей, он вводится и работает, как ожидалось, без aspectJ weaver. Хотя я сталкиваюсь с проблемами с аспектом, являющимся синглтоном... Это приводит к "perthis" модель создания экземпляра. .
добавьте @Component в класс aspect, и ваши зависимости должны вводиться автоматически. и добавьте контекст: компонент-сканирование пакета, в котором ваш аспект находится в файле контекста spring.
@Component
@Aspect
public class SomeAspect {
/* following dependency should get injected */
@Autowired
SomeTask someTask;
/* rest of code */
}
используйте время компиляции, см. Пример плагина по адресу: https://github.com/avner-levy/minimal_spring_hibernate_maven_setup/blob/master/pom.xml
следующая комбинация аннотации и Spring config работает для меня благодаря Примечаниям выше Тобиаса / Вилли/Эрика:
класс:
package com.abc
@Configurable
@Aspect
public class MyAspect {
@Autowired
protected SomeType someAutoWiredField;
}
XML:
<context:spring-configured />
<context:component-scan base-package="com.abc" />
@Configurable(autowire = Autowire.BY_TYPE)
добавить эту аннотацию в свой Aspectj
класса. Затем он будет обработан весенним МОК.