Spring AOP with prototype beans

Viewed 351

I am using Spring AOP to fire metrics in our application. I have created an annotation @CaptureMetrics which has an @around advice associated with it. The advice is invoked fine from all the methods tagged with @CaptureMetrics except for a case when a method is invoked on a prototype bean.

The annotation has @Target({ElementType.TYPE, ElementType.METHOD})

PointCut expression:

@Around(value = "execution(* *.*(..)) && @annotation(captureMetrics)",
      argNames = "joinPoint,captureMetrics")

Prototype bean creation

@Bean
  @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
  public DummyService getDummyServicePrototypeBean(int a, String b) {
    return new DummyService(a, b);
  }

DummyService has a method called dummyMethod(String dummyString)

    @CaptureMetrics(type = MetricType.SOME_TYPE, name = "XYZ")
          public Response dummyMethod(id) throws Exception {
           // Do some work here
        }

When dummyService.dummyMethod("123") is invoked from some other service, the @Around advice is not called.

Config class

@Configuration
public class DummyServiceConfig {

  @Bean
  public DummyServiceRegistry dummyServiceRegistry(
      @Value("${timeout}") Integer timeout,
      @Value("${dummy.secrets.path}") Resource dummySecretsPath) throws IOException {
    ObjectMapper mapper = new ObjectMapper();
    Map<String, String> transactionSourceToTokens = mapper.readValue(
        dummySecretsPath.getFile(), new TypeReference<Map<String, String>>() {
        });
    DummyServiceRegistry registry = new DummyServiceRegistry();
    transactionSourceToTokens.forEach((transactionSource, token) ->
        registry.register(transactionSource,
            getDummyServicePrototypeBean(timeout, token)));

    return registry;
  }

  @Bean
  @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
  public DummyService getDummyServicePrototypeBean(int a, String b) {
    return new DummyService(a, b);
  }

}

Singleton Registry class

public class DummyServiceRegistry {
  private final Map<String, DummyService> transactionSourceToService = new HashMap<>();

  public void register(String transactionSource, DummyService dummyService) {
    this.transactionSourceToService.put(transactionSource, dummyService);
  }

  public Optional<DummyService> lookup(String transactionSource) {
    return Optional.ofNullable(transactionSourceToService.get(transactionSource));
  }
}

Any advice on this please?

Note:

  • The prototype Dummy service is used to call a third party client. It is a prototype bean as it has a state that varies based on whose behalf it is going to call the third party.

  • A singleton registry bean during initialization builds a map of {source_of_request, dummyService_prototype}. To get the dummyService prototype it calls getDummyServicePrototypeBean()

1 Answers

The configuration, registry and prototype dummy bean were correct.

I was testing the flow using an existing integration test and there instead of supplying a prototype Bean, new objects of DummyService were instantiated using the new keyword. It wasn't a spring managed bean.

Spring AOP works only with Spring managed beans.

Related