Spring autowired bean for @Aspect aspect is null

﹥>﹥吖頭↗ 提交于 2019-11-27 03:42:59

The aspect is a singleton object and is created outside the Spring container. A solution with XML configuration is to use Spring's factory method to retrieve the aspect.

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

With this configuration the aspect will be treated as any other Spring bean and the autowiring will work as normal.

You have to use the factory-method also on Enum objects and other objects without a constructor or objects that are created outside the Spring container.

Another option is to add @Configurable to your aspect class instead of messing around with XML.

For Spring Boot to use @Autowired with AspectJ I have found the following method. In configuration class add your aspect:

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

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

}

Then you can successfully autowire your services in your aspect class:

@Aspect
public class EmailAspect {

    @Autowired
    EmailService emailService;
other_paul

I dont have 50 rep to comment on a question so here is another answer relating to @ Jitendra Vispute answer. The official Spring doc mentions:

You may register aspect classes as regular beans in your Spring XML configuration, or autodetect them through classpath scanning - just like any other Spring-managed bean. However, note that the @Aspect annotation is not sufficient for autodetection in the classpath: For that purpose, you need to add a separate @Component annotation (or alternatively a custom stereotype annotation that qualifies, as per the rules of Spring’s component scanner).Source: Spring '4.1.7.Release' documentation.

This would mean that adding a @Component annotation and adding the @ComponentScan on your Configuration would make @Jitendra Vispute's example work. For the spring boot aop sample it worked, though I did not mess around with context refreshing.Spring boot aop sample:

Application:

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);
    }
}

The application should also run as plain Spring Framework application with the following annotations instead of @SpringBootApplication:

  • @Configuration
  • @EnableAspectJAutoProxy
  • @ComponentScan

and an AnnotationConfigApplicationContext instead of SpringApplication.

Service:

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;
    }
}

Monitor Aspect:

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);
    }
}
Wouter

Configuring @Autowired with java config only (so no XML based configuration) requires a bit of extra work than just adding @Configuration to the class, as it also needs the aspectOf method.

What worked for me was creating a new class:

@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;
    }
}

And then use that in you aspect in conjunction with using @DependsOn @Configured and @Autowired:

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

    @Autowired
    private SomeBean someBean;

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

The @DependsOn is needed because spring can't determine the dependency because the bean is used staticly.

This blog post explains it really well. Due to the fact that aspect singleton is created outside spring container you'd need to use factory-method=”aspectOf” that is only available after it is woven in by AspectJ ( not Spring AOP ) :

Notice factory-method=”aspectOf” that tells Spring to use a real AspectJ ( not Spring AOP ) aspect to create this bean. So that after the aspect is woven in it has an “aspectOf” method.

So that :

No matching factory method found: factory method 'aspectOf()' - That would mean that the aspect was not woven by AspectJ weaver.

From my experience with spring 3.1, if I don't use @Autowired but traditional setter for dependency injection, it gets injected and works as expected without aspectJ weaver. Although I'm encountering problems with the aspect being singleton... It results in 'perthis' instantiation model. .

Add @Component to aspect class and your dependencies should get injected automatically. and add context:component-scan for package where your aspect is in spring context file.

@Component
@Aspect
public class SomeAspect {
    /* following dependency should get injected */
    @Autowired
    SomeTask someTask;
    /* rest of code */  
}

Use compile time weaving, see for plugin example at: https://github.com/avner-levy/minimal_spring_hibernate_maven_setup/blob/master/pom.xml

The following combination of annotation and Spring config works for me thanks to notes above by Tobias/Willie/Eric:

Class:

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

XML:

<context:spring-configured />
<context:component-scan base-package="com.abc" />
Alan_Jin
@Configurable(autowire = Autowire.BY_TYPE)

Add this annotation to your Aspectj class. Then it will be handled by Spring IOC.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!