Комментарии 17
Ещё много изменений произошло в Actuator.
Знаю один из проектов, который ещё не переехал на СБ2 именно из-за Актуатора.
Кстати, раз уж речь зашла от миграции: отдельная и интересная тема — переезд с голого Спринга на Спринг Бут. Так на одном из проектов столкнулись с тем, что перестал работать откат транзакций при выбрасывании проверяемых исключений. Когда-то давно возникла необходимость откатывать спринговую транзакцию при выбрасывании этого исключения. Это было сделано с помощью AnnotationTransactionAttributeSource
примерно вот так:
public class CustomAttributeSource extends AnnotationTransactionAttributeSource {
@Override
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
return new DefaultTransactionAttribute() {
@Override
public boolean rollbackOn(Throwable ex) {
return super.rollbackOn(ex) || ex instanceof CustomCheckedException;
}
};
}
}
На чистом Спринге работало, после переезда на СБ1 транзакции откатываться перестали.
ещё не переехал на СБ2 именно из-за Актуатора
А что конкретно не дает переехать? Интересно узнавать о новых граблях от коллег по цеху.
Насчёт транзакций сам с таким не сталкивался, но уже не в первый раз слышу о подобных проблемах. Я бы в первую очередь выяснил, заходит ли выполнение в метод rollbackOn
, чтобы разбить область поиска на два взаимоисключающих участка:
- Если не заходит, то стоит покопать в сторону того, как регистрируется
CustomAttributeSource
: точно ли его видят регистрирующие бины (в том числе самописные), и точно ли эти бины сами активны (намекаю на соответствующие классы*AutoConfiguration
). - Если же выполнение заходит сюда, то надо убедиться, не обёрнуто ли целевое исключение в какое-либо другое (каковых в Spring'е целая иерархия). В случае обёртки (да и не только в нем) следует проверять на
instanceof
не само исключение, а его корень, например, через Throwables#getRootCause() из Guava.
Точно не скажу, разговор был формата курилки. Спросил про миграцию на СБ2, вылезло несколько проблем, а поскольку задача была не очень важной, то занимались ей в перерывах между основной работой.
Вот что запомнилось точно — проблемы со Спринг Датой. Начиная с версии 2 изменились названия ключевых методов в JpaRepository
:
interface JpaRepository<T, ID> {
//было
<T> T findOne(ID id);
<T> List<T> findAll(Iterable<ID> ids);
//стало
<T> Optional<T> findById(ID id);
<T> List<T> findAllById(Iterable<ID> ids);
}
В проекте несколько десятков репозиториев и тысячи обращений к указанным методам. Миграция "в лоб" (использование новых методов) зацепила бы каждый второй файл. Поэтому воспользовались возможностью подгонки репозиториев под свои нужды:
//основа для всех репозиториев
@NoRepositoryBean
public interface BaseJpaRepository<T, ID extends Serializable> extends JpaRepository<T, ID> {
// определяем метод findOne, аналогичный тёзке, существовавшему в версиях 1.*
@Deprecated
T findOne(ID id);
// тоже для findAll
@Deprecated
List<T> findAll(Iterable<ID> ids);
}
public class BaseJpaRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements BaseJpaRepository<T, ID> {
private JpaEntityInformation<T, ?> entityInfo;
private EntityManager entityManager;
public BaseJpaRepositoryImpl(JpaEntityInformation<T, ?> entityInfo, EntityManager entityManager) {
super(entityInfo, entityManager);
this.entityInfo = entityInfo;
this.entityManager = entityManager;
}
//обеспечиваем совместимость поведения
@Override
public T findOne(ID id) {
return findById(id).orElse(null);
}
@Override
public List<T> findAll(Iterable<ID> ids) {
return findAllById(ids);
}
}
//какой-нибудь репозиторий
interface SomeRepository extends BaseJpaRepository<SomeEntiy, Lond> {
}
И о чудо! Все ошибки компиляции исчезают, код работает как и прежде, а изменено всего 2 класса, а не 200. Теперь можно неспешно заменять устаревшее АПИ на новое, благо "Идея" заботливо подсветит все вызовы помеченные @Deprecated
.
У меня был схожий опыт с JPA, только нужно было отвязать прикладной код от походов в БД статическими методами Play 1.x, чтобы покрыть код unit-тестами без PowerMockito. Впрочем, тогда машстаб вышел более широким — таки пришлось задеть пару сотен классов. К счастью, правки оказались простыми.
default T findOne(ID id) {
return findById(id).orElse(null);
}
в BaseJpaRepository добавить.
Ответ переехал выше.
Спасибо! Очень понравился стиль изложения!
Честно, устал от косноязычных переводов про спринг бут на Хабре… Эта статья прям как глоток свежего воздуха!
Интересно когда это все рухнет под своим собственным весом.
Ну вот, пора уже про версию 3 повторить!
Spring Boot 2: чего не пишут в release notes