【问题标题】:How to intercept JdbcTemplate whose instance is created by myself如何拦截自己创建实例的JdbcTemplate
【发布时间】:2019-10-09 08:07:17
【问题描述】:

我想要做的是在任何 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
    }
 }

它对JdbcTemplateNamedParameterJdbcTemplate 都非常有效,由@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 或其他方法?

【问题讨论】:

  • 你好。你问了一个问题,我回答了。所以请检查我的答案,如果你认为它是正确的,请接受+upvote(我当然这样做)。

标签: java spring spring-boot aop jdbctemplate


【解决方案1】:

如果在这两种情况下,您都像这样打印 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 的替代方案。但我怀疑在这种情况下这样做是否值得。

【讨论】:

  • 感谢您的回复!我知道我不能用 Spring AOP 代理 Spring 创建的对象。所以我会考虑你的建议。
【解决方案2】:

在使用@Configuration 注释的类中,将JdbcTemplate 定义为@Bean

@Configuration
public class JdbcConfiguration {

    private DriverManagerDatasource ds = new DriverManagerDatasource();

    @Bean
    public JdbcTemplate jdbcTemplate() {
        return new JdbcTemplate(ds);
    }
}

这样,当在@Aspect 中拦截它时,您可以通过将JdbcTemplate bean 放入ApplicationContext 来启用Spring 使用AOP 代理它。您现在可以使用以下命令对其进行自动装配:

@Autowired private JdbcTemplate jdbcTemplate;

【讨论】:

  • 是的,当然,但问题是如何将 AOP 与 自动连接的 JDBC 模板结合使用。
  • 您不能将 AOP 用于使用 new 创建的实例。我只是给了你一种方法来拦截 your JdbcTemplate 的方法,将其设为 Spring 管理的 @Bean
  • @kriagaex,您可能在错误的答案下发布了它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-05
  • 2021-12-27
  • 2021-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多