简体   繁体   中英

Spring. Registering Aspect with @Bean

I need some help with creating Aspect bean.

I have module A , B ... and module starter-x . I have a couple of Aspects declared in module starter-x, and configurations for them(like spring data repository monitoring aspect with configuration annotated with @ConditionalOnClass(Repository.class) etc).

Here's how example configuration looks like

@Configuration
@ConditionalOnClass(Repository.class)
public class RepositoryMonitoringConfiguration {

    @Bean
    @Qualifier("RepositoryCallCounter")
    public DatabaseCallCounter repositoryCounter(){
        return new RepositoryCallCounter();
    }


}

And i have class with @Aspect annotation(but not @Component , when i create bean with @Component not @Configuration , everything is ok)

So my question, is it possible to provide aspect bean in @Configuration class, without @Component annotation on it (I want to create cool starter with auto configuration)

It's possible, you just need to mark the configuration class like this:

@Configuration
@EnableAspectJAutoProxy
@ConditionalOnClass(Repository.class)
public class RepositoryMonitoringConfiguration {

  @Bean
  public DatabaseCallCounter repositoryCounter(){
    return new RepositoryCallCounter();
  }
}

I encountered same problem as you. And I figured out the cause.

The solution is to exclude your Config class from @Around like following code.

package hello.hellospring.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Slf4j @Aspect
public class TimeTraceAop {
    @Around("execution(* hello.hellospring..*(..)) && !target(your config class)")
    public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        log.info("START: " + joinPoint.toString());
        try {
            return joinPoint.proceed();
        } finally {
            long finish = System.currentTimeMillis();
            log.info("END: " + joinPoint + " " + (finish - start) + "ms");
        }
    }
}

You probably configured @Around to root package and its subpackages.
And that means @Around method is also applied to the configuration class.
So, when the spring tries to make a bean for not only AOP but also other else,
Spring finds AOP class in container that you want to make.
But, of course, there doesn't exist AOP class
if @Component is not applied to AOP class.
And Spring thinks AOP references AOP.
So Spring makes an error like following log.

***************************
APPLICATION FAILED TO START
***************************

Description:

The dependencies of some of the beans in the application context form a cycle:

   memberController defined in file [/Users/macbook/Desktop/git/hello-spring/build/classes/java/main/hello/hellospring/controller/MemberController.class]
      ↓
   memberService defined in class path resource [hello/hellospring/SpringConfig.class]
┌─────┐
|  timeTraceAop defined in class path resource [hello/hellospring/SpringConfig.class]
└─────┘


Action:

Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM