首页 > 解决方案 > 如何拦截自己创建实例的JdbcTemplate

问题描述

我想要做的是在为当前会话执行的任何DQL(“SELECT ...”)或DML (INSERT/UPDATE/DELETE ...)之后收集数据库统计值。
目前,我利用Spring AOP来实现这一点,如下所示:

@Aspect
@Component
public class StatisticalValueCollector {
    @After("execution(* org.springframework.jdbc.core..*JdbcOperations.*(String, ..))")
    public void collectStatisTicalValues(JoinPoint jp) {
        //Collect DB statistical values
    }
 }

它适用于两者JdbcTemplate并由NamedParameterJdbcTemplate注释@Autowired,但是当我自己创建它们的实例ㄋ时,它不起作用。

工作示例:

@Autowired
JdbcTemplate jdbcTemplate;
...
List<Map<String, Object>> result = jdbcTemplate.queryForList("SELECT ...");

不工作的例子:

DriverManagerDatasource ds = new DriverManagerDatasource();
...
JdbcTemplate jdbcTemplate = new JdbcTemplate (ds);
List<Map<String, Object>> result = jdbcTemplate.queryForList("SELECT ...");

据我所知,似乎如果JdbcTemplate是由 Spring 创建的,则可以根据这篇文章进行代理 - AOP: Able to Intercept JDBCTemplate calls but not NamedParameterJdbcTemplate calls

因此,我的问题是“如何拦截JdbcTemplateNamedParameterJdbcTemplate自己创建? ”;
任何意见和建议将不胜感激。谢谢!

更新
我还调查了p6spydatasource-proxy等不同的方法,似乎唯一的解决方案是使用纯AspectJ或其他方法?

标签: javaspringspring-bootaopjdbctemplate

解决方案


如果在这两种情况下,您都像这样打印 JDBC 模板实例

System.out.println(jdbcTemplate + "\n  " + jdbcTemplate.getClass());

然后对于您自己创建的那个,您将看到

org.springframework.jdbc.core.JdbcTemplate@3c71cf3e
  class org.springframework.jdbc.core.JdbcTemplate

而对于自动注入的,您会看到

org.springframework.jdbc.core.JdbcTemplate@8f39224
  class org.springframework.jdbc.core.JdbcTemplate$$EnhancerBySpringCGLIB$$59a5407f

指出不同?对于后者,如果存在针对它的方面,则 Spring 创建一个动态代理。只有当有一个动态代理时,Spring AOP 才有东西可以注册它的方面建议。

我不是 Spring 用户,所以我不知道是否有另一种规范的方式来创建 JDBC 模板,根据需要自动为其创建动态代理。因此,除非您想手动创建代理(这是可能的但不必要的复杂)或找到另一种方法来执行此操作,否则只需使用依赖注入 (DI) 和自动连接。这不是首先使用 Spring 的全部意义吗?创建可以注入的依赖项对于像 Spring 这样的 DI 容器来说是一种反模式。

如果您坚持使用非正统且难以测试(如何为调用构造函数的局部变量注入模拟?)方法,则始终可以使用完整的 AspectJ 作为 Spring AOP 的替代方案。但我怀疑在这种情况下是否值得。


推荐阅读