我想做的是在对当前会话执行的任何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
进行代理。
因此,我的问题是“ 如何截取自己创建的JdbcTemplate
或NamedParameterJdbcTemplate
?”;任何意见和建议将不胜感激。谢谢!
在带有@Configuration
注释的类中,将JdbcTemplate
定义为@Bean
:
@Configuration
public class JdbcConfiguration {
private DriverManagerDatasource ds = new DriverManagerDatasource();
@Bean
public JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(ds);
}
}
这样,通过将@Aspect
bean放入JdbcTemplate
,可以使Spring在AOP中拦截AOP时使用AOP代理它。您现在可以通过以下方式自动接线:
ApplicationContext
如果在两种情况下都以这种方式打印JDBC模板实例,则>]
@Autowired private JdbcTemplate jdbcTemplate;
然后您将看到自己创建的那个
System.out.println(jdbcTemplate + "\n " + jdbcTemplate.getClass());
同时您会看到自动注射的>]
org.springframework.jdbc.core.JdbcTemplate@3c71cf3e class org.springframework.jdbc.core.JdbcTemplate
发现差异?对于后者,如果存在针对它的方面,Spring会创建一个动态代理。仅当存在动态代理时,Spring AOP才能在其上注册方面建议。
我不是Spring用户,所以我不知道是否存在另一种规范的方式来创建JDBC模板,并根据需要自动为其创建动态代理。因此,除非您要手动创建代理(这是可能的,但不必要的复杂操作)或找到另一种方法,否则请使用依赖项注入(DI)和自动装配。那不是一开始就使用Spring的全部目的吗?创建可以注入的依赖关系对于像Spring这样的DI容器来说是一种反模式。
如果坚持非正统且难以测试(如何为调用构造函数的局部变量注入模拟?)方法,则始终可以将完整的AspectJ用作Spring AOP的替代方法。但我怀疑在这种情况下是否值得。