英文:
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("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.
答案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("repositories()")
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("repositories()")
public Object recordMetrics(ProceedingJoinPoint pjp) {
try {
// start metrics
return pjp.proceed();
} finally {
//end metrics
}
}
}
Something along those lines should do the trick.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论