英文:
Spring CGLIB, transactions and private final field initialization
问题
我在我的Spring Boot应用程序中有以下的类层次结构:
public abstract class A {
private final ObjectMapper objectMapper = new ObjectMapper();
public void method1(Object object) {
this.objectMapper.writeValueAsString(object);
}
}
@Component
public class B extends A {
public void method2() {
method1();
}
}
在这种情况下,一切都正常工作。
但是当我在method2()的声明中添加@Transactional(rollbackFor = Exception.class)注解,就像这样:
public abstract class A {
private final ObjectMapper objectMapper = new ObjectMapper();
public void method1() {
this.objectMapper; // 总是NULL
}
}
@Component
public class B extends A {
@Transactional(rollbackFor = Exception.class)
public void method2() {
method1();
}
}
并且执行method2()时,由于this.objectMapper为NULL,method1()中会出现NullPointerException错误;
如何让Spring在添加了@Transactional(rollbackFor = Exception.class)的情况下,正确地初始化private final ObjectMapper objectMapper?
此外,使用@Transactional注解时,this的类是B$$EnhancerBySpringCGLIB,而没有注解时则是普通的B。因此,看起来CGLIB无法正确初始化private final ObjectMapper objectMapper... 是否有任何解决方法?
英文:
I have the following class hierarchy in my Spring Boot application:
public abstract class A {
private final ObjectMapper objectMapper = new ObjectMapper();
public void method1(Object object) {
this.objectMapper.writeValueAsString(object);
}
}
@Component
public class B extends A {
public void method2() {
method1();
}
}
in such case everything is working fine.
But when I add @Transactional(rollbackFor = Exception.class) annotation to method2() declaration, like for example:
public abstract class A {
private final ObjectMapper objectMapper = new ObjectMapper();
public void method1() {
this.objectMapper; // always NULL
}
}
@Component
public class B extends A {
@Transactional(rollbackFor = Exception.class)
public void method2() {
method1();
}
}
and execute method2() it fails with NullPointerException in method1() because of this.objectMapper is NULL;
How to let Spring correctly initialize the private final ObjectMapper objectMapper even in case of @Transactional(rollbackFor = Exception.class) is added?
Also, in case of @Transactional annotation the class of this is B$$EnhancerBySpringCGLIB and without annotation is just plain B. So, looks like CGLIB unable to properly initialize private final ObjectMapper objectMapper.. Is there any workarounds how it can be solved?
答案1
得分: 1
Sure, here's the translated code:
在你的代码中移除 `final` 关键字。你正在使用带有 `CGLIB` 的 `@Transactional`。`CGLIB` 的工作原理是通过扩展你的类来创建代理。由于下面的方法是 final 的,它无法进行扩展,因为 final 类无法被扩展。
@Transactional(rollbackFor = Exception.class)
public void method2() {
method1();
}
英文:
Remove the final in your code. You are using @Transactional with CGLIB. How CGLIB works is it creates a proxy by extending your class. Since the below method is final it cannot extend it, since final classes cannot be extended.
@Transactional(rollbackFor = Exception.class)
public final void method2() {
method1();
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论