SpringBoot BeanPostProcessor 在启动时未扫描 @Repository beans。

huangapple go评论69阅读模式
英文:

SpringBoot BeanPostProcessor is not scanning @Repository beans on start up

问题

I've built the following BeanPostProcessor Implementation:

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class InterceptRepositoryBeanPostProcessor implements BeanPostProcessor {

    public static final Logger logger = LoggerFactory.getLogger(InterceptRepositoryBeanPostProcessor.class);
    private final ApplicationContext context;
    private final MeterRegistry meterRegistry;

    @Autowired
    public InterceptRepositoryBeanPostProcessor(ApplicationContext context, MeterRegistry meterRegistry) {
        this.context = context;
        this.meterRegistry = meterRegistry;
        logger.info("Starting InterceptRepositoryBeanPostProcessor");
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        logger.info("post processing BEFORE initialization: {}", beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        logger.info("post processing AFTER initialization: {}", beanName);

        // If the bean is annotated with @Repository, wrap it in a proxy
        if (bean.getClass().isAnnotationPresent(Repository.class)) {
            logger.info("CREATING proxy with RepositoryInvocationMetricsHandler for {}",
                        beanName);
            return createRepositoryProxy(bean);
        }

        return bean;
    }

    /**
     * Create a proxy by wrapping the Repository implementation in a RepositoryInvocationMetricsHandler
     *
     * @param bean The Repository to create a proxy for
     * @return A new  proxy - RepositoryInvocationMetricsHandler
     */
    private Object createRepositoryProxy(Object bean) {
        logger.info("Creating repository proxy for bean: {}", bean.getClass().getSimpleName());
        Class<?> target = bean.getClass();
        ClassLoader classLoader = target.getClassLoader();
        Class<?>[] interfaces = target.getInterfaces();

        return Proxy.newProxyInstance(classLoader,
                                      interfaces,
                                      new RepositoryInvocationMetricsHandler(target, context, meterRegistry));
    }
}

It works well, and with the log messages I can see a lot of stuff being intercepted, however I'm interested in intercepting classes annotated with @Repository, and when I examine the log files, none of those components appear to be handled by the Processor at all.
What am I missing? It seems like they are handled in a different way perhaps?

This class is part of a separate package that is imported into my current project with maven, in case that is important. But it works as I said, and scans lots of objects, just not Repository objects.

英文:

I've built the following BeanPostProcessor Implementation:

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class InterceptRepositoryBeanPostProcessor implements BeanPostProcessor {
public static final Logger logger = LoggerFactory.getLogger(InterceptRepositoryBeanPostProcessor.class);
private final ApplicationContext context;
private final MeterRegistry meterRegistry;
@Autowired
public InterceptRepositoryBeanPostProcessor(ApplicationContext context, MeterRegistry meterRegistry) {
this.context = context;
this.meterRegistry = meterRegistry;
logger.info(&quot;Starting InterceptRepositoryBeanPostProcessor&quot;);
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
logger.info(&quot;post processing BEFORE initialization: {}&quot;, beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
logger.info(&quot;post processing AFTER initialization: {}&quot;, beanName);
// If the bean is annotated with @Repository, wrap it in a proxy
if (bean.getClass().isAnnotationPresent(Repository.class)) {
logger.info(&quot;CREATING proxy with RepositoryInvocationMetricsHandler for {}&quot;,
beanName);
return createRepositoryProxy(bean);
}
return bean;
}
/**
* Create a proxy by wrapping the Repository implementation in a RepositoryInvocationMetricsHandler
*
* @param bean The Repository to create a proxy for
* @return A new  proxy - RepositoryInvocationMetricsHandler
*/
private Object createRepositoryProxy(Object bean) {
logger.info(&quot;Creating repository proxy for bean: {}&quot;, bean.getClass().getSimpleName());
Class&lt;?&gt; target = bean.getClass();
ClassLoader classLoader = target.getClassLoader();
Class&lt;?&gt;[] interfaces = target.getInterfaces();
return Proxy.newProxyInstance(classLoader,
interfaces,
new RepositoryInvocationMetricsHandler(target, context, meterRegistry));
}
}

It works well, and with the log messages I can see a lot of stuff being intercepted, however I'm interested in intercepting classes annotated with @Repository, and when I examine the log files, none of those components appear to be handled by the Processor at all.
What am I missing? It seems like they are handled in a different way perhaps?

This class is part of a separate package that is imported into my current project with maven, in case that is important. But it works as I said, and scans lots of objects, just not Repository objects.

答案1

得分: 1

请注意,以下是您提供的内容的中文翻译:

"Instead of using a BeanPostProcessor, use an aspect with a pointcut expression. Using a BeanPostProcessor can be problematic, especially in the way you wrote it; yours might lead to proxying a proxy. Next to that, just writing an Aspect is probably easier and will delegate the proxy creation to Spring.

@Component
@Aspect
public class RepositoryInvocationMetricsAspect {

  private final ApplicationContext context;
  private final MeterRegistry meterRegistry;

  public RepositoryInvocationMetricsAspect(ApplicationContext ctx, MeterRegistry meterRegistry) {
    this.context=context;
    this.meterRegistry=meterRegistry;
  }

  @Pointcut(@within(@org.springframework.stereotype.Repository))
  public void repositories() {}

  @Around(&quot;repositories()&quot;)
  public Object recordMetrics(ProceedingJoinPoint pjp) {
    try {
      // start metrics
      return pjp.proceed();
    } finally {
      //end metrics
    }
  }
}

Something along those lines should do the trick."

英文:

Instead of using a BeanPostProcessor use an aspect with a pointcut expression. Using a BeanPostProcessor can be problematic especially in the way you wrote it, yours might lead to proxying a proxy. Next to that just writing an Aspect is probably easier and will delegate the proxy creation to Spring.

@Component
@Aspect
public class RepositoryInvocationMetricsAspect {

  private final ApplicationContext context;
  private final MeterRegistry meterRegistry;

  public RepositoryInvocationMetricsAspect(ApplicationContext ctx, MeterRegistry meterRegistry) {
    this.context=context;
    this.meterRegistry=meterRegistry;
  }

  @Pointcut(@within(@org.springframework.stereotype.Repository))
  public void repositories() {}

  @Around(&quot;repositories()&quot;)
  public Object recordMetrics(ProceedingJoinPoint pjp) {
    try {
      // start metrics
      return pjp.proceed();
    } finally {
      //end metrics
    }
  }
}

Something along those lines should do the trick.

huangapple
  • 本文由 发表于 2023年6月13日 15:30:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/76462600.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定