web-dev-qa-db-ja.com

@AspectアスペクトのSpring autowired Beanが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が存在し、他のクラスに正しく関連付けられています)次のことが混乱を招きます。

  1. Context:component-scanは@Aspectを取得するはずですか?それなら確かにそれは春の管理された豆になるでしょう、したがってautowiredはうまくいくでしょうか?
  2. Context:component-scanがアスペクトの作成用ではない場合、アスペクトはどのように作成されますか?私はaop:aspectj-autoproxyが@AspectクラスをプロキシするbeanPostProcessorを作成するだけだと思いましたか?春管理のBeanではない場合、どうすればよいでしょうか?

言うまでもなく、私は物事が最初からどのように機能すべきか理解していないと言うことができます。

35
mogronalol

アスペクトはシングルトンオブジェクトであり、Springコンテナの外部で作成されます。 XML構成のソリューションは、Springのファクトリメソッドを使用してアスペクトを取得することです。

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

この構成では、アスペクトは他のSpring Beanとして扱われ、自動配線は通常どおり機能します。

Springメソッドの外部で作成されたコンストラクターやオブジェクトのないEnumオブジェクトやその他のオブジェクトでも、factory-methodを使用する必要があります。

34
Espen

別のオプションは、XMLをいじる代わりに、アスペクトクラスに@Configurableを追加することです。

18
tobiasbayer

Spring BootがAspectJで@Autowiredを使用するために、私は次の方法を見つけました。構成クラスで、アスペクトを追加します。

@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;
12
Kirill Ch

構成 @ 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 @Configuredおよび@Autowiredと組み合わせて使用​​します。

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

    @Autowired
    private SomeBean someBean;

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

Beanは静的に使用されるため、Springは依存関係を判別できないため、@ DependsOnが必要です。

5
Wouter

質問にコメントする50人の担当者はいないので、ここに @ Jitendra Vispute 回答に関する別の回答を示します。 Springの公式ドキュメントには次のように記載されています。

Spring XML構成でアスペクトクラスを通常のBeanとして登録するか、他のSpring管理Beanと同じように、クラスパススキャンを通じてそれらを自動検出できます。ただし、@ Aspectアノテーションはクラスパスでの自動検出には十分ではないことに注意してください。そのためには、別個の@Componentアノテーション(または、Springのコンポーネントスキャナーのルールに従って修飾するカスタムステレオタイプアノテーション)を追加する必要があります。 出典:Spring '4.1.7.Release'のドキュメント

これは、@ Componentアノテーションを追加し、構成に@ComponentScanを追加すると、@ Jitendra Visputeの例が機能することを意味します。春のブート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);
    }
}

アプリケーションは、@ SpringBootApplicationの代わりに、次のアノテーションを含むプレーンなSpring Frameworkアプリケーションとしても実行する必要があります。

  • @構成
  • @EnableAspectJAutoProxy
  • @ComponentScan

springApplicationの代わりにAnnotationConfigApplicationContext。

サービス

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

これは ブログ投稿 でよく説明されています。アスペクトシングルトンがSpringコンテナーの外部で作成されるという事実により、AspectJ(Spring AOPではなく)に組み込まれた後でのみ使用できるfactory-method =” aspectOf”を使用する必要があります。

このBeanを作成するために実際のAspectJ(Spring AOPではない)アスペクトを使用するようにSpringに指示するfactory-method =” aspectOf”に注意してください。そのため、アスペクトが織り込まれた後、「aspectOf」メソッドがあります。

そのため :

一致するファクトリメソッドが見つかりません:ファクトリメソッド 'aspectOf()'-これは、アスペクトがAspectJウィーバーによって作成されなかったことを意味します。

Spring 3.1での私の経験から、@ Autowiredではなく従来のセッターを依存性注入に使用しない場合、それは注入され、aspectJ weaverがなくても期待どおりに機能します。アスペクトがシングルトンであるという問題が発生していますが、「perthis」インスタンス化モデルになります。 。

2
lisak

@Componentをアスペクトクラスに追加すると、依存関係が自動的に挿入されます。そして、あなたのアスペクトが春のコンテキストファイルにあるパッケージのcontext:component-scanを追加してください。

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

コンパイル時のウィービングを使用します。プラグインの例については、次を参照してください。 https://github.com/avner-levy/minimal_spring_hibernate_maven_setup/blob/master/pom.xml

上記のTobias/Willie/Ericのメモのおかげで、注釈とSpring構成の次の組み合わせがうまくいきます。

クラス:

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

XML:

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

この注釈をAspectjクラスに追加します。その後、Spring IOCによって処理されます。

0
Alan_Jin