Spring autowired bean for @Aspect aspect is null

33,017

Solution 1

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.

Solution 2

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

Solution 3

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;

Solution 4

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 SpringApplicationContextHolder.getApplicationContext().getBean(SomeAspect.class);
    }

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

Solution 5

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);
    }
}
Share:
33,017
mogronalol
Author by

mogronalol

Updated on March 08, 2021

Comments

  • mogronalol
    mogronalol about 3 years

    I have the following spring configuration:

    <context:component-scan base-package="uk.co.mysite.googlecontactsync.aop"/>
    
    <bean name="simpleEmailSender" class="uk.co.mysite.util.email.simple.SimpleEmailSenderImplementation"/>
    
    <aop:aspectj-autoproxy/>
    

    Then I have an aspect:

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

    This aspect works (I can hit a breakpoint on afterPoll) but simpleEmailSender is null. Unfortunately I cannot find clear documentation on why this is. (For the record, my simpleEmailSender bean exists and is correctly wired into other classes) The following things confuse me:

    1. Is context:component-scan supposed to be picking up @Aspect? If it is then surely it would be a spring managed bean, thus autowired should work?
    2. If context:component-scan isn't for creating aspects, how is my aspect being created? I thought aop:aspectj-autoproxy just creates a beanPostProcessor to proxy my @Aspect class? How would it do this if it isn't a spring managed bean?

    Obviously you can tell I don't have an understanding of how things should be working from the ground up.

  • mogronalol
    mogronalol about 12 years
    from what I can see in the documentation this is for when you are using AspectJ. I am supposed to be using spring AOP. Is there something in my configuration that I have missing / need to add to make this the case?
  • mogronalol
    mogronalol about 12 years
    after trying it out you have indeed given me the solution, but now I am still confused because of my above point
  • Admin
    Admin almost 12 years
    Nice. Remember <context:spring-configured /> in the XML as well.
  • mag382
    mag382 over 10 years
    Thank you for this as it was the only annotation based example I could find.
  • Eric B.
    Eric B. over 10 years
    Thanks! @Configurable did the trick for me. No need for any separate JavaConfig or XML factory-method='aspect-of' with the @Configurable annotation.
  • Eric B.
    Eric B. about 10 years
    I've just encountered a situation where this fails; when the Spring context refreshes, Spring does not automatically update the references. I have posted a question at stackoverflow.com/q/22826526/827480 looking for a solution to this problem.
  • Jackie
    Jackie almost 10 years
    the spring doc is bulky. the configurable is for non singletons.
  • sudeepdino008
    sudeepdino008 almost 10 years
    CheckServicesPermissionsAspect.class? I don't understand what this is.
  • Wouter
    Wouter almost 10 years
    It was a copy from an existing project, but I forgot to generalize that bit, fixed now :)
  • user1366367
    user1366367 over 9 years
    For those arriving on this page using JavaConfig to configure your aspect, this worked for me: stackoverflow.com/a/22872161/1366367
  • oak
    oak over 8 years
    When weaven(with aspectj) on compile time this does not work for me. Do you have any experience with that?
  • sorrymissjackson
    sorrymissjackson over 8 years
    I think @Component annotation would be the right annotation for the SomeAspect class. You only want it to get discovered, but you are not creating beans in that class, which would be the semantics of @Configuration.
  • Wouter
    Wouter over 8 years
    You're probably right, I created this about 1.5-2 years ago, so I can't remember why I chose @Configuration.