我正在尝试为数据源切入点实现 Spring Boot AOP - 在运行任何查询之前,我需要在数据库连接中设置客户端上下文。
我正在尝试使用 DelegatingDataSource 的this方法。但我在服务器启动期间遇到以下错误
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。
编辑 1:AOP - 我尝试添加切入点
execution(public * javax.sql.DataSource+.getConnection(..))
。仅当 Spring 数据源与用户名/密码一起使用时,这才有效。一旦我使用 JNDI 部署在 Jboss 中,我就会收到 WildFlyDataSource
代理错误。因此,我没有考虑使用 AOP 方法,而是使用 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 创建错误。
创建带有名称的 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: 此问题的常见原因包括使用最终类或 不可见类;嵌套异常是 org.springframework.cglib.core.CodeGenerationException: java.lang.NoClassDefFoundError-->org/jboss/as/connector/subsystems/datasources/WildFlyDataSource
我还在初始化期间添加了 proxyTargetClass 标志
@EnableAspectJAutoProxy(proxyTargetClass = true)
感谢@M.Deinum 建议使用
BeanPostProcessor
并实施 DelegatingDatasource
来设置客户信息。请在下面找到我在 Spring Boot 中实现的实现this的代码片段,它与基于 JBoos JNDI 的连接或 Spring Boot URL 数据源连接配合得很好。
@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
来处理每个用户请求以在数据库连接会话中设置客户端上下文
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();
}
}
希望这对面临同样问题的人有帮助
@Karthikeyan 我有类似的用例,我使用 DelegatingDataSource 来拦截连接对象,以便我可以为其设置一些属性。但是,当我在生产中运行此代码时,会创建新的连接对象,并且它们永远不会终止/关闭。我有你上面提到的确切代码。想知道这是否是由于 new (MyDelegateDS) 每次调用时都会创建新连接? PS感谢您分享上面的片段