settooltiptext - settitle java
El bean autoajustado de primavera para el aspecto @Aspect es nulo (8)
Tengo la siguiente configuración de primavera:
<context:component-scan base-package="uk.co.mysite.googlecontactsync.aop"/>
<bean name="simpleEmailSender" class="uk.co.mysite.util.email.simple.SimpleEmailSenderImplementation"/>
<aop:aspectj-autoproxy/>
Entonces tengo un aspecto:
@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));
}
}
Este aspecto funciona (puedo alcanzar un punto de interrupción en afterPoll) pero simpleEmailSender es nulo. Desafortunadamente no puedo encontrar documentación clara sobre por qué es esto. (Para el registro, mi bean simpleEmailSender existe y está conectado correctamente a otras clases) Las siguientes cosas me confunden:
- ¿El contexto: componente-scan se supone que está recogiendo @Aspect? Si es así, seguramente sería un frijol administrado por la primavera, por lo que debería funcionar el autoenlace.
- Si context: componente-scan no es para crear aspectos, ¿cómo se está creando mi aspecto? Pensé que aop: aspectj-autoproxy simplemente crea un beanPostProcessor para proxy mi clase @Aspect? ¿Cómo sería esto si no es un frijol administrado por primavera?
Obviamente puedes decir que no entiendo cómo deberían funcionar las cosas desde cero.
Agregue @Component a la clase de aspecto y sus dependencias deben ser inyectadas automáticamente. y agregue contexto: componente-escaneo para el paquete donde su aspecto está en el archivo de contexto de primavera.
@Component
@Aspect
public class SomeAspect {
/* following dependency should get injected */
@Autowired
SomeTask someTask;
/* rest of code */
}
Configurar @Autowired con java config (para que no haya ninguna configuración basada en XML) requiere un poco de trabajo adicional que simplemente agregar @Configuration a la clase, ya que también necesita el método aspectOf.
Lo que funcionó para mí fue crear una nueva clase:
@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;
}
}
Y luego use eso en su aspecto junto con el uso de @DependsOn @Configured y @Autowired:
@DependsOn("springApplicationContextHolder")
@Configuration
@Aspect
public class SomeAspect {
@Autowired
private SomeBean someBean;
public static SomeAspect aspectOf() {
return SpringApplicationContextProvider.getApplicationContext().getBean(SomeAspect.class);
}
El @DependsOn es necesario porque Spring no puede determinar la dependencia porque el bean se usa estáticamente.
El aspecto es un objeto singleton y se crea fuera del contenedor Spring. Una solución con configuración XML es usar el método de fábrica de Spring para recuperar el aspecto.
<bean id="syncLoggingAspect" class="uk.co.demo.SyncLoggingAspect"
factory-method="aspectOf" />
Con esta configuración, el aspecto se tratará como cualquier otro Spring Bean y el autoenvío funcionará normalmente.
También debe usar el método de fábrica en los objetos Enum y otros objetos sin un constructor u objetos que se creen fuera del contenedor de Spring.
Esta publicación en el blog lo explica muy bien. Debido a que el aspecto singleton se crea fuera del contenedor de resorte, necesitarás usar factory-method = "aspectOf" que solo está disponible una vez que haya sido diseñado por AspectJ (no por Spring AOP):
Observe fábrica-método = "aspectOf" que le dice a Spring que use un aspecto AspectJ real (no Spring AOP) para crear este bean. Entonces, después de que el aspecto se haya tejido, tiene un método "aspectOf".
Así que eso :
No se encontró ningún método de fábrica coincidente: método de fábrica ''aspectOf ()'' - Eso significa que el aspecto no fue tejido por el tejedor AspectJ.
A partir de mi experiencia con la primavera 3.1, si no utilizo @Autowired pero setter tradicional para la inyección de dependencia, se inyecta y funciona como se esperaba sin el aspectoJ weaver. Aunque estoy teniendo problemas con el aspecto de singleton ... Resulta en el modelo de creación de instancias ''perthis''. .
No tengo 50 representantes para comentar una pregunta, así que aquí hay otra respuesta relacionada con la respuesta de @ Jitendra Vispute . El documento oficial de Spring menciona:
Puede registrar clases de aspecto como beans normales en su configuración Spring XML, o autodetectarlas a través del escaneo de classpath, al igual que cualquier otro bean gestionado por Spring. Sin embargo, tenga en cuenta que la anotación @Aspect no es suficiente para la autodetección en el classpath: para ello, debe agregar una anotación @Component separada (o una anotación de estereotipo personalizada que califique, según las reglas del escáner de componentes de Spring). Fuente: documentación de Spring ''4.1.7.Release'' .
Esto significaría que agregar una anotación @Component y agregar @ComponentScan en su Configuración haría que el ejemplo de @Jitendra Vispute funcione. Para la muestra aop de arranque de primavera, funcionó, aunque no metí la pata refrescando el contexto. Spring boot aop muestra :
Aplicación :
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);
}
}
La aplicación también debería ejecutarse como una aplicación simple de Spring Framework con las siguientes anotaciones en lugar de @SpringBootApplication:
- @Configuración
- @EnableAspectJAutoProxy
- @ComponentScan
y un AnnotationConfigApplicationContext en lugar de SpringApplication.
Servicio :
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;
}
}
Aspecto del monitor :
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);
}
}
Otra opción es agregar @Configurable
a su clase de aspecto en lugar de jugar con XML.
Para que Spring Boot use @Autowired con AspectJ, he encontrado el siguiente método. En la clase de configuración agrega tu aspecto:
@Configuration
@ComponentScan("com.kirillch.eqrul")
public class AspectConfig {
@Bean
public EmailAspect theAspect() {
EmailAspect aspect = Aspects.aspectOf(EmailAspect.class);
return aspect;
}
}
Luego, puede autoconectar exitosamente sus servicios en su clase de aspecto:
@Aspect
public class EmailAspect {
@Autowired
EmailService emailService;
Use el tiempo de compilación, vea ejemplos de complementos en: https://github.com/avner-levy/minimal_spring_hibernate_maven_setup/blob/master/pom.xml
La siguiente combinación de anotación y configuración Spring funciona para mí gracias a las notas anteriores de Tobias / Willie / Eric:
Clase:
package com.abc
@Configurable
@Aspect
public class MyAspect {
@Autowired
protected SomeType someAutoWiredField;
}
XML:
<context:spring-configured />
<context:component-scan base-package="com.abc" />