首页 文章

@Aspect方面的Spring autowired bean为null

提问于
浏览
29

我有以下 spring 配置:

<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存在并正确连接到其他类)以下事情使我感到困惑:

  • 上下文:组件扫描应该是@Aspect?如果它肯定是一个 spring 管理bean,那么自动装配应该工作吗?

  • 如果上下文:组件扫描是不是'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'一个Spring托管bean?

显然你可以告诉我,我不了解事情应该如何从头开始 .

9 回答

  • 4

    方面是单个对象,在Spring容器外部创建 . 使用XML配置的解决方案是使用Spring的工厂方法来检索方面 .

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

    使用此配置,该方面将被视为任何其他Spring bean,并且自动装配将正常工作 .

    您还必须在Enum对象和其他对象上使用factory方法,而不使用构造函数或在Spring容器外部创建的对象 .

  • 0

    另一个选择是将 @Configurable 添加到方面类而不是乱用XML .

  • 32

    对于使用@Autowired和AspectJ的Spring Boot,我发现了以下方法 . 在配置类中添加您的方面:

    @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;
    
  • 2

    我没有50个代表对一个问题发表评论,所以这里是另一个与@ Jitendra Vispute答案相关的答案 . Spring 季官方文件提到:

    您可以在Spring XML配置中将方面类注册为常规bean,或者通过类路径扫描自动检测它们 - 就像任何其他Spring管理的bean一样 . 但是,请注意@Aspect注释不足以在类路径中自动检测:为此,您需要添加单独的@Component注释(或者根据Spring的组件扫描程序的规则添加符合条件的自定义构造型注释) . 资料来源:Spring'4.1.7.Release'文档 .

    这意味着添加@Component注释并在Configuration上添加@ComponentScan将使@Jitendra Vispute的示例工作 . 对于 spring 靴aop样品它工作,虽然我没有搞乱上下文刷新 . 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);
        }
    }
    

    应用程序也应该作为普通的Spring Framework应用程序运行,并带有以下注释而不是@SpringBootApplication:

    • @Configuration

    • @EnableAspectJAutoProxy

    • @ComponentScan

    和AnnotationConfigApplicationContext而不是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);
        }
    }
    
  • 17

    仅使用java配置配置@Autowired(因此没有基于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无法确定依赖项,因为bean是静态使用的 .

  • 8

    这个blog post解释得很好 . 由于在 spring 容器外部创建了方面单例,你需要使用工厂方法=“aspectOf”,它只有在被AspectJ(不是Spring AOP)编织后才可用:

    注意factory-method =“aspectOf”告诉Spring使用真正的AspectJ(不是Spring AOP)方面来创建这个bean . 因此,在方面编织之后,它具有“aspectOf”方法 .

    以便 :

    找不到匹配的工厂方法:工厂方法'aspectOf()' - 这意味着该方面不是由AspectJ编织者编织的 .

    根据我在使用Spring 3.1的经验,如果我不使用@Autowired但传统的setter用于依赖注入,它会被注入并按预期工作而不使用aspectJ weaver . 虽然我遇到问题的方面是单身...它导致'perthis'实例化模型 . .

  • 0

    将@Component添加到aspect类,您的依赖项应自动注入 . 并添加上下文:组件扫描包,其中方面位于spring上下文文件中 .

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

    使用编译时编织,请参阅以下插件示例:https://github.com/avner-levy/minimal_spring_hibernate_maven_setup/blob/master/pom.xml

    以下注释和Spring配置的组合感谢Tobias / Willie / Eric的上述笔记:

    类:

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

    XML:

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

    将此注释添加到 Aspectj 类 . 然后它将由Spring IOC处理 .

相关问题