#java #spring #spring-boot #spring-data-jpa #cglib
#java #spring #spring-boot #spring-data-jpa #cglib
Вопрос:
У меня есть следующая иерархия классов в моем приложении 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();
}
}
в таком случае все работает нормально.
Но когда я добавляю @Transactional(rollbackFor = Exception.class)
аннотацию к method2()
объявлению, например:
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();
}
}
и выполнить method2()
это не удается с NullPointerException
помощью method1()
из-за this.objectMapper
того NULL
, что;
Как позволить Spring правильно инициализировать private final ObjectMapper objectMapper
даже в случае @Transactional(rollbackFor = Exception.class)
добавления?
Кроме того, в случае @Transactional
аннотации класс this
является B$$EnhancerBySpringCGLIB
и без аннотации является простым B
. Итак, похоже, что CGLIB не может правильно инициализироваться private final ObjectMapper objectMapper
.. Есть ли какие-либо обходные пути, как это можно решить?
Комментарии:
1. Смотрите deinum.biz/2020-07-03-Autowired-Field-Null/#aop для более широкого объяснения. В основном из-за прокси, удалите
final
ключевое слово изmethod2
, иначе оно не будет работать.
Ответ №1:
Удалите final
в своем коде. Вы используете @Transactional
с CGLIB
. Как CGLIB
работает, это создает прокси, расширяя ваш класс. Поскольку приведенный ниже метод является окончательным, он не может его расширить, поскольку конечные классы не могут быть расширены.
@Transactional(rollbackFor = Exception.class)
public final void method2() {
method1();
}
Комментарии:
1. Спасибо за ваш ответ! Возможно ли это сделать с помощью reflection api или чего-то подобного? Потому что упомянутый код в моем примере является частью библиотеки 3rdparty.
2. Я думаю, вы можете использовать ReflectionUtils.SetField(«objectmapper»,this.getClass().getSuperclass(), new ObjectMapper());