简体   繁体   English

我可以在同一应用程序上下文中同时使用动态代理和CGLib代理吗?

[英]Can I use both dynamic proxies and CGLib proxies in the same application context?

I'm building and End to End testing framework for a production spring batch project. 我正在为生产春季批处理项目构建和端到端测试框架。 We'd like to use an in-memory embedded db (in our case hsqldb) for these tests since it will run much faster and have not environmental constraints. 我们希望使用内存嵌入式db(在我们的示例中为hsqldb)进行这些测试,因为它的运行速度更快并且没有环境限制。 Since the SQL syntax is slightly different between these db engines, we would like to use spring AOP to intercept the sql going to the database and take out/replace sql commands that are not supported. 由于这些数据库引擎之间的SQL语法略有不同,因此我们想使用spring AOP截取去往数据库的sql,并取出/替换不支持的sql命令。 (we've looked at paramaterizing the sql completely, but we have the incompatible commands reduced to only a few little things, such as the "(nolock)" hint. ) (我们已经研究过完全参数化SQL,但是我们将不兼容的命令简化为仅几样小东西,例如“((nolock)”提示)。)

I set up an AOP aspect for JDBCTemplate that works following a pretty standard aop pattern for logging sql: 我为JDBCTemplate设置了AOP方面,该方面遵循用于记录sql的相当标准的aop模式进行工作:

@Pointcut("execution(* org.springframework.jdbc.core.JdbcOperations.*(String, ..))")
public void modifyJdbcOperations() {
}

and it works great with this spring config setup: 它在此春季配置设置中效果很好:

<aop:aspectj-autoproxy proxy-target-class="true" >
    <aop:include name = "SQLModifierAspect"/>
</aop:aspectj-autoproxy>

<aop:config proxy-target-class="true">
</aop:config>

<bean id="SQLModifierAspect" class="e2e.framework.SQLModifierAspect" />

Then I tried to set up a similar pointcut for the a method on one of our DAO objects that is constructor injected: 然后,我尝试在构造函数注入的DAO对象之一上为a方法设置类似的切入点:

@Pointcut("execution(* com.*.dao.DateDao.buildSelectByDateCarryForward())")
public void modifyDateDao() {
}

But when I run the E2E framework with this pointcut I get: 但是,当我使用此切入点运行E2E框架时,我得到:

Caused by: java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given
at net.sf.cglib.proxy.Enhancer.emitConstructors(Enhancer.java:721) ~[cglib-2.2.jar:na]

I see that this is because I have configured to use CGLIB instead of Spring dynamic proxy based AOP. 我看到这是因为我已配置为使用CGLIB而不是基于Spring动态代理的AOP。 I read up on the differences here: http://docs.spring.io/spring/docs/3.0.0.M3/reference/html/ch08s06.html 我在这里阅读了不同之处: http : //docs.spring.io/spring/docs/3.0.0.M3/reference/html/ch08s06.html

I can't realistically refactor our entire production project to use property DI instead of constructor DI. 我不能现实地重构我们的整个生产项目以使用属性DI而不是构造函数DI。 If I switch back to Spring Dynamic Proxies, then the JdbcTemplate AOP doesn't work: 如果我切换回Spring Dynamic Proxies,则JdbcTemplate AOP不起作用:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jdbcSupportBI' defined in class path resource [e2e-overrides.xml]: Initialization of bean failed; nested exception is org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type '$Proxy51 implementing org.springframework.jdbc.core.JdbcOperations,org.springframework.beans.factory.InitializingBean,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised' to required type 'org.springframework.jdbc.core.JdbcTemplate' for property 'jdbcTemplate';

So my question is: can I somehow configure aspectj to use Spring Dynamic Proxies for some classes, and CGLIB for others? 所以我的问题是:我可以以某种方式配置Aspectj以将Spring Dynamic Proxies用于某些类,将CGLIB用于其他类吗? Is there another way around this problem that only requires minimal refactoring? 是否有其他方法可以解决此问题,而只需要最少的重构?

Update: My current workaround is to have a SqlPreparer class that I inject into Daos as needed. 更新:我当前的解决方法是要有一个SqlPreparer类,该类可以根据需要注入到Daos中。 I can make this have a default constructor. 我可以使它具有默认构造函数。 It adds an extra util class that doesn't do anything in production code, but it's not as invasive of a refactor: 它添加了一个额外的util类,该类在生产代码中不做任何事情,但是它不像重构那样具有侵入性:

/**
* Abstracted out of the GenericDao for AOP in the E2E tests
*/
public class SqlPreparer implements ISqlPreparer {

@Override
public String prepareSql(String sql) {
    return sql;
}
}

You could simply split your context into multiple contexts. 您可以简单地将上下文分为多个上下文。 One for your JdbcTemplate with aspects proxied through CGLIB and one for your DAO with aspects proxied through JDK proxies. 一种用于通过CGLIB代理的JdbcTemplate ,另一种通过JDK代理的DAO。

The error itself is because Spring seems to use the default CGLIB Enhancer behavior of proxying using the no-argument constructor of a class. 错误本身是因为Spring似乎使用默认的CGLIB Enhancer行为,即使用类的无参数构造函数进行代理。 Since your class doesn't have one, it fails. 由于您的班级没有一门课,因此失败了。 You could refactor your DataDao class and move constructor injection to field or setter injection and instead have a no-argument constructor. 您可以重构DataDao类,并将构造函数注入移至字段或setter注入,而使用无参数的构造函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM