委托数据源 Spring boot [英] DelegatingDataSource Spring boot
问题描述
我正在尝试为数据源切入点实现 Spring Boot AOP - 在运行任何查询之前,我需要在数据库连接中设置客户端上下文.
I am trying to implement Spring Boot AOP for data-source pointcut - where before running any query I need to set client context in DB connection.
我正在尝试这种使用 DelegatingDataSource 的方法.但是我在服务器启动过程中遇到以下错误
I was trying this approach of using DelegatingDataSource. But I am getting below error during server startup
org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'dataSource': Requested bean is currently in creation: Is there an unresolvable circular reference?
请让我知道基于 JNDI 的数据库查找的 DeletegatingDatasource.
Please let me know DeletegatingDatasource for JNDI based DB lookup.
编辑 1:AOP - 我试图添加切入点 execution(public * javax.sql.DataSource+.getConnection(..))
.这仅在 Spring 数据源与用户名/密码一起使用时才有效.一旦我使用 JNDI 在 Jboss 中部署,我就会收到 WildFlyDataSource
代理错误.因此,我想到使用 DelegatingDatasource
Edit 1: AOP - I tried to add pointcut execution(public * javax.sql.DataSource+.getConnection(..))
. This works only when Spring datasource is used with username/password. Once i deploy in Jboss with JNDI I am getting WildFlyDataSource
Proxy error. So, instead of AOP approach I thought of using DelegatingDatasource
// AOP Example
@Pointcut("execution(public * javax.sql.DataSource+.getConnection(..))")
void prepareConnectionPointcut() {
logger.debug("prepareConnectionPointcut");
}
@AfterReturning(pointcut = "prepareConnectionPointcut()", returning = "connection")
void afterPrepareConnection(Connection connection) {
// Set context in Connection - return same connection for query execution
}
但是当我在 JBoss 中部署此代码时 - 我收到 WildFlyDataSource 数据源 bean 创建错误.
But when i deploy this code in JBoss - I am getting WildFlyDataSource datasource bean creation error.
创建带有名称的 bean 时出错'org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration':不满足的依赖通过构造函数参数 0 表示;嵌套异常是org.springframework.beans.factory.BeanCreationException:错误使用在类路径资源中定义的名称dataSource"创建 bean[org/springframework/boot/autoconfigure/jdbc/JndiDataSourceAutoConfiguration.class]:bean 初始化失败;嵌套异常是org.springframework.aop.framework.AopConfigException:无法生成类的CGLIB子类org.jboss.as.connector.subsystems.datasources.WildFlyDataSource:此问题的常见原因包括使用 final 类或不可见类;嵌套异常是org.springframework.cglib.core.CodeGenerationException:java.lang.NoClassDefFoundError-->org/jboss/as/connector/subsystems/datasources/WildFlyDataSource
Error creating bean with name 'org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration': Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/JndiDataSourceAutoConfiguration.class]: Initialization of bean failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class org.jboss.as.connector.subsystems.datasources.WildFlyDataSource: Common causes of this problem include using a final class or a non-visible class; nested exception is org.springframework.cglib.core.CodeGenerationException: java.lang.NoClassDefFoundError-->org/jboss/as/connector/subsystems/datasources/WildFlyDataSource
我还在初始化期间添加了 proxyTargetClass 标志
I have also added proxyTargetClass flag during initialization
@EnableAspectJAutoProxy(proxyTargetClass = true)
@EnableAspectJAutoProxy(proxyTargetClass = true)
推荐答案
感谢@M.Deinum 推荐使用 BeanPostProcessor
&实现 DelegatingDatasource
来设置客户端信息.请在下面找到我已经实现的代码片段 this 在 Spring Boot 中,适用于基于 JBoos JNDI 的连接或 Spring Boot URL 数据源连接.
Thanks @M.Deinum for recommendation of using BeanPostProcessor
& Implement DelegatingDatasource
for setting client info. Please find snippet below which i have implemented to accomplish this in Spring Boot which works well with JBoos JNDI based connection or Spring Boot URL Datasource connection.
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
private static Logger logger = LoggerFactory.getLogger(MyBeanPostProcessor.class);
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof DataSource) {
// Check DataSource bean initialization & enclose it with DelegatingDataSource
logger.debug("MyBeanPostProcessor:: postProcessAfterInitialization:: DataSource");
DataSource beanDs = (DataSource) bean;
return new MyDelegateDS(beanDs);
}
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof DataSource) {
logger.debug("MyBeanPostProcessor:: postProcessBeforeInitialization:: DataSource");
}
logger.debug("MyBeanPostProcessor:: postProcessBeforeInitialization:: " + beanName);
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
}
我的 DelegatingDataSource
实现来处理每个用户在数据库连接会话中设置客户端上下文的请求
My implementation of DelegatingDataSource
to handle each user request to set client context in DB connection session
public class MyDelegateDS extends DelegatingDataSource {
private static Logger logger = LoggerFactory.getLogger(MyDelegateDS.class);
public MyDelegateDS(DataSource delegate) {
super(delegate);
logger.debug("MyDelegateDS:: constructor");
}
@Override
public Connection getConnection() throws SQLException {
logger.debug("MyDelegateDS:: getConnection");
// To do this context only for user Request - to avoid this during Server initialization
if (RequestContextHolder.getRequestAttributes() != null
&& ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest() != null) {
logger.debug("MyDelegateDS:: getConnection: valid user request");
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
.getRequest();
// Checking each user request & calling SP to set client context before invoking actual native query/SP
}
logger.debug("MyDelegateDS:: getConnection: Not User Request");
return super.getConnection();
}
}
希望对遇到同样问题的人有所帮助
Hope this is helpful for someone facing same problem
这篇关于委托数据源 Spring boot的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!