Java 在目标而不是代理实例上调用了@Transactional的方法
我目前正在将我的一个项目从“自配置spring”迁移到spring boot。虽然大部分内容已经在工作,但我对Java 在目标而不是代理实例上调用了@Transactional的方法,java,spring,spring-boot,spring-transactions,Java,Spring,Spring Boot,Spring Transactions,我目前正在将我的一个项目从“自配置spring”迁移到spring boot。虽然大部分内容已经在工作,但我对@Transactional方法有一个问题,在调用该方法时,由于调用了“target”实例而不是“proxy”实例(我将尝试在下面详细说明),因此上下文不存在 首先是我的类层次结构的精简视图: @Entity public class Config { // fields and stuff } public interface Exporter { int star
@Transactional
方法有一个问题,在调用该方法时,由于调用了“target”实例而不是“proxy”实例(我将尝试在下面详细说明),因此上下文不存在
首先是我的类层次结构的精简视图:
@Entity
public class Config {
// fields and stuff
}
public interface Exporter {
int startExport() throws ExporterException;
void setConfig(Config config);
}
public abstract class ExporterImpl implements Exporter {
protected Config config;
@Override
public final void setConfig(Config config) {
this.config = config;
// this.config is a valid config instance here
}
@Override
@Transactional(readOnly = true)
public int startExport() throws ExporterException {
// this.config is NULL here
}
// other methods including abstract one for subclass
}
@Scope("prototype")
@Service("cars2Exporter")
public class Cars2ExporterImpl extends ExporterImpl {
// override abstract methods and some other
// not touching startExport()
}
// there are other implementations of ExporterImpl too
// in all implementations the problem occurs
检查这里的参数,我发现proxy
是id为16585的实例,target
是id为16606的实例
不幸的是,我没有深入到springs aop的东西,不知道它是否应该是这样的
我只是想知道为什么有两个实例在不同的方法上被调用。对setConfig()
的调用转到代理实例,而对dostartExport()
的调用到达目标实例,因此无法访问先前设置的配置
如前所述,该项目已迁移到spring boot,但我们之前已经使用了spring平台bom的雅典版本。从这里我可以看出,迁移之前没有特殊的AOP配置,迁移之后也没有显式设置值
为了解决这个问题(或至少以某种方式工作),我已经尝试了多种方法:
- 从子类中删除@Scope
- 将@Transactional从方法级别移动到类
- 重写子类中的startExport()并将@Transactional放在此处
- 将@enableSpectJautoproxy添加到应用程序类(我甚至无法登录-没有错误消息)
- 将spring.aop.proxy-target-class设置为true
- 以上是不同的组合
目前我没有线索知道如何让它恢复工作
提前谢谢
*希望有人能提供帮助*Spring Boot在您可能拥有基于接口(JDK动态代理)之前尝试创建一个基于类的cglib代理
因此,将创建Cars2ExporterImpl
的子类,覆盖所有方法并应用建议。但是,由于您的setConfig
方法是无法重写的final
,因此该方法将实际在代理上调用,而不是在代理实例上调用
因此,要么删除final
关键字,以便可以创建CgLib代理,要么显式禁用事务的基于类的代理。Add@EnableTransationManagement(proxy target class=false)
也应该起作用。除非有其他触发基于类的代理的东西 如果不直接调用该字段,而是在与startExport()
相同的实例上调用getConfig()
,会发生什么情况?并返回null。删除setConfig
上的final
关键字。已创建代理,但它是基于类的代理。导致在代理上调用setConfig
,并在代理实例上调用startExport
。或者将spring.aop.proxy目标类
切换到false
以拥有基于接口的代理。@M.Deinum就是这样。。。。我甚至还没有意识到这个方法是最终的。。。幸运的是,我将它复制到问题中,而不是重新键入它。…。@M.Deinum如果您将此作为答案发布,我将接受它。非常感谢!特别是与您的评论相比,更详细的解释!
@Inject
private Provider<Exporter> cars2Exporter;
public void scheduleExport(Config config) {
Exporter exporter = cars2Exporter.get();
exporter.setConfig(config);
exporter.startExport();
// actually I'm wrapping it here in a class implementing runnable
// and put it in the queue of a `TaskExecutor` but the issue happens
// on direct call too. :(
}
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();