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

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

SpringBoot BeanPostProcessor is not scanning @Repository beans on start up

问题

I've built the following BeanPostProcessor Implementation:

  1. @Component
  2. @Order(Ordered.HIGHEST_PRECEDENCE)
  3. public class InterceptRepositoryBeanPostProcessor implements BeanPostProcessor {
  4. public static final Logger logger = LoggerFactory.getLogger(InterceptRepositoryBeanPostProcessor.class);
  5. private final ApplicationContext context;
  6. private final MeterRegistry meterRegistry;
  7. @Autowired
  8. public InterceptRepositoryBeanPostProcessor(ApplicationContext context, MeterRegistry meterRegistry) {
  9. this.context = context;
  10. this.meterRegistry = meterRegistry;
  11. logger.info("Starting InterceptRepositoryBeanPostProcessor");
  12. }
  13. @Override
  14. public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  15. logger.info("post processing BEFORE initialization: {}", beanName);
  16. return bean;
  17. }
  18. @Override
  19. public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  20. logger.info("post processing AFTER initialization: {}", beanName);
  21. // If the bean is annotated with @Repository, wrap it in a proxy
  22. if (bean.getClass().isAnnotationPresent(Repository.class)) {
  23. logger.info("CREATING proxy with RepositoryInvocationMetricsHandler for {}",
  24. beanName);
  25. return createRepositoryProxy(bean);
  26. }
  27. return bean;
  28. }
  29. /**
  30. * Create a proxy by wrapping the Repository implementation in a RepositoryInvocationMetricsHandler
  31. *
  32. * @param bean The Repository to create a proxy for
  33. * @return A new proxy - RepositoryInvocationMetricsHandler
  34. */
  35. private Object createRepositoryProxy(Object bean) {
  36. logger.info("Creating repository proxy for bean: {}", bean.getClass().getSimpleName());
  37. Class<?> target = bean.getClass();
  38. ClassLoader classLoader = target.getClassLoader();
  39. Class<?>[] interfaces = target.getInterfaces();
  40. return Proxy.newProxyInstance(classLoader,
  41. interfaces,
  42. new RepositoryInvocationMetricsHandler(target, context, meterRegistry));
  43. }
  44. }

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:

  1. @Component
  2. @Order(Ordered.HIGHEST_PRECEDENCE)
  3. public class InterceptRepositoryBeanPostProcessor implements BeanPostProcessor {
  4. public static final Logger logger = LoggerFactory.getLogger(InterceptRepositoryBeanPostProcessor.class);
  5. private final ApplicationContext context;
  6. private final MeterRegistry meterRegistry;
  7. @Autowired
  8. public InterceptRepositoryBeanPostProcessor(ApplicationContext context, MeterRegistry meterRegistry) {
  9. this.context = context;
  10. this.meterRegistry = meterRegistry;
  11. logger.info(&quot;Starting InterceptRepositoryBeanPostProcessor&quot;);
  12. }
  13. @Override
  14. public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  15. logger.info(&quot;post processing BEFORE initialization: {}&quot;, beanName);
  16. return bean;
  17. }
  18. @Override
  19. public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  20. logger.info(&quot;post processing AFTER initialization: {}&quot;, beanName);
  21. // If the bean is annotated with @Repository, wrap it in a proxy
  22. if (bean.getClass().isAnnotationPresent(Repository.class)) {
  23. logger.info(&quot;CREATING proxy with RepositoryInvocationMetricsHandler for {}&quot;,
  24. beanName);
  25. return createRepositoryProxy(bean);
  26. }
  27. return bean;
  28. }
  29. /**
  30. * Create a proxy by wrapping the Repository implementation in a RepositoryInvocationMetricsHandler
  31. *
  32. * @param bean The Repository to create a proxy for
  33. * @return A new proxy - RepositoryInvocationMetricsHandler
  34. */
  35. private Object createRepositoryProxy(Object bean) {
  36. logger.info(&quot;Creating repository proxy for bean: {}&quot;, bean.getClass().getSimpleName());
  37. Class&lt;?&gt; target = bean.getClass();
  38. ClassLoader classLoader = target.getClassLoader();
  39. Class&lt;?&gt;[] interfaces = target.getInterfaces();
  40. return Proxy.newProxyInstance(classLoader,
  41. interfaces,
  42. new RepositoryInvocationMetricsHandler(target, context, meterRegistry));
  43. }
  44. }

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.

  1. @Component
  2. @Aspect
  3. public class RepositoryInvocationMetricsAspect {
  4. private final ApplicationContext context;
  5. private final MeterRegistry meterRegistry;
  6. public RepositoryInvocationMetricsAspect(ApplicationContext ctx, MeterRegistry meterRegistry) {
  7. this.context=context;
  8. this.meterRegistry=meterRegistry;
  9. }
  10. @Pointcut(@within(@org.springframework.stereotype.Repository))
  11. public void repositories() {}
  12. @Around(&quot;repositories()&quot;)
  13. public Object recordMetrics(ProceedingJoinPoint pjp) {
  14. try {
  15. // start metrics
  16. return pjp.proceed();
  17. } finally {
  18. //end metrics
  19. }
  20. }
  21. }

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.

  1. @Component
  2. @Aspect
  3. public class RepositoryInvocationMetricsAspect {
  4. private final ApplicationContext context;
  5. private final MeterRegistry meterRegistry;
  6. public RepositoryInvocationMetricsAspect(ApplicationContext ctx, MeterRegistry meterRegistry) {
  7. this.context=context;
  8. this.meterRegistry=meterRegistry;
  9. }
  10. @Pointcut(@within(@org.springframework.stereotype.Repository))
  11. public void repositories() {}
  12. @Around(&quot;repositories()&quot;)
  13. public Object recordMetrics(ProceedingJoinPoint pjp) {
  14. try {
  15. // start metrics
  16. return pjp.proceed();
  17. } finally {
  18. //end metrics
  19. }
  20. }
  21. }

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:

确定