Что нового в весне 4.3?

Что нового в весне 4.3?

1. обзор

Релиз Spring 4.3 внес несколько приятных улучшений в основной контейнер, кеширование, JMS, Web MVC и тестовые подмодули платформы.

В этом посте мы обсудим некоторые из этих улучшений, в том числе:

  • Неявная инъекция конструктора

  • Поддержка методов интерфейса Java 8 по умолчанию

  • Улучшенное разрешение зависимостей

  • Улучшения Cache Abstraction

  • Составлено@RequestMapping Варианты

  • @Requestscope, @Sessionscope, @Applicationscope Аннотации

  • Аннотации@RequestAttribute и@SessionAttribute

  • Libraries/Application Servers Versions Support

  • классInjectionPoint

2. Неявная инъекция конструктора

Рассмотрим следующий класс обслуживания:

@Service
public class FooService {

    private final FooRepository repository;

    @Autowired
    public FooService(FooRepository repository) {
        this.repository = repository
    }
}

Довольно распространенный вариант использования, но если вы забудете аннотацию@Autowired в конструкторе, контейнер выдаст исключение, ищущее конструктор по умолчанию, если вы явно не выполните проводку.

Таким образом, начиная с 4.3, вам больше не нужно указывать явную аннотацию внедрения в таком сценарии с одним конструктором. Это особенно элегантно для классов, которые вообще не содержат аннотаций:

public class FooService {

    private final FooRepository repository;

    public FooService(FooRepository repository) {
        this.repository = repository
    }
}

В Spring 4.2 и ниже следующая конфигурация для этого bean-компонента не будет работать, потому что Spring не сможет найти конструктор по умолчанию дляFooService. Spring 4.3 умнее и автоматически связывает конструктор:


    
    

Точно так же вы могли заметить, что классы@Configuration исторически не поддерживали внедрение конструктора. Начиная с 4.3, они это делают, и они, естественно, также позволяют опускать@Autowired в сценарии с одним конструктором:

@Configuration
public class FooConfiguration {

    private final FooRepository repository;

    public FooConfiguration(FooRepository repository) {
        this.repository = repository;
    }

    @Bean
    public FooService fooService() {
        return new FooService(this.repository);
    }
}

3. Поддержка методов интерфейса Java 8 по умолчанию

До весны 4.3 стандартные методы интерфейса не поддерживались.

Это было нелегко реализовать, потому что даже интроспектор JavaBean JDK не обнаруживал методы по умолчанию как средства доступа. Начиная с Spring 4.3, методы получения и установки, реализованные как методы интерфейса по умолчанию, идентифицируются во время внедрения, что позволяет использовать их, например, в качестве общих препроцессоров для обращающихся свойств, как в этом примере:

public interface IDateHolder {

    void setLocalDate(LocalDate localDate);

    LocalDate getLocalDate();

    default void setStringDate(String stringDate) {
        setLocalDate(LocalDate.parse(stringDate,
          DateTimeFormatter.ofPattern("dd.MM.yyyy")));
    }

}

В этот bean-компонент теперь может быть введено свойствоstringDate:


    

То же самое касается использования тестовых аннотаций, таких как@BeforeTransaction и@AfterTransaction, в методах интерфейса по умолчанию. JUnit 5 уже поддерживает свои тестовые аннотации для методов интерфейса по умолчанию, и Spring 4.3 следует за ним. Теперь вы можете абстрагировать общую логику тестирования в интерфейсе и реализовать ее в тестовых классах. Вот интерфейс для тестовых случаев, который регистрирует сообщения до и после транзакций в тестах:

public interface ITransactionalTest {

    Logger log = LoggerFactory.getLogger(ITransactionalTest.class);

    @BeforeTransaction
    default void beforeTransaction() {
        log.info("Before opening transaction");
    }

    @AfterTransaction
    default void afterTransaction() {
        log.info("After closing transaction");
    }

}

Еще одно улучшение, касающееся аннотаций@BeforeTransaction,@AfterTransaction и@Transactional, - это ослабление требования, чтобы аннотированные методы былиpublic - теперь они могут иметь любой уровень видимости.

4. Улучшенное разрешение зависимостей

В новейшей версии также представленObjectProvider, расширение существующего интерфейсаObjectFactory с удобными сигнатурами, такими какgetIfAvailable иgetIfUnique, для получения bean-компонента, только если он существует или может быть определен единственный кандидат (в частности: основной кандидат в случае нескольких совпадающих bean-компонентов).

@Service
public class FooService {

    private final FooRepository repository;

    public FooService(ObjectProvider repositoryProvider) {
        this.repository = repositoryProvider.getIfUnique();
    }
}

Вы можете использовать такой дескрипторObjectProvider для целей настраиваемого разрешения во время инициализации, как показано выше, или сохранить дескриптор в поле для позднего разрешения по запросу (как вы обычно делаете сObjectFactory).

5. Улучшения Cache Abstraction

Абстракция кэша в основном используется для кэширования значений, которые потребляют ресурсы процессора и ввода-вывода. В конкретных случаях использования данный ключ может быть запрошен несколькими потоками (т.е. клиенты) параллельно, особенно при запуске. Поддержка синхронизированного кэша - давно востребованная функция, которая теперь реализована. Предположим следующее:

@Service
public class FooService {

    @Cacheable(cacheNames = "foos", sync = true)
    public Foo getFoo(String id) { ... }

}

Обратите внимание на атрибутsync = true, который сообщает инфраструктуре блокировать любые параллельные потоки, пока вычисляется значение. Это гарантирует, что эта интенсивная операция вызывается только один раз в случае одновременного доступа.

Spring 4.3 также улучшает абстракцию кэширования следующим образом:

  • Выражения SpEL в аннотациях, связанных с кэшем, теперь могут ссылаться на bean-компоненты (т.е. @beanName.method()).

  • ConcurrentMapCacheManager иConcurrentMapCache теперь поддерживают сериализацию записей кэша с помощью нового атрибутаstoreByValue.

  • @Cacheable,@CacheEvict,@CachePut и@Caching теперь можно использовать в качестве метааннотаций для создания пользовательских составных аннотаций с переопределением атрибутов.

6. Составлено@RequestMapping Варианты

Spring Framework 4.3 представляет следующие варианты аннотации@RequestMapping, составленные на уровне методов, которые помогают упростить сопоставления для общих методов HTTP и лучше выразить семантику метода аннотированного обработчика.

  • @GetMapping

  • @PostMapping

  • @PutMapping

  • @DeleteMapping

  • @PatchMapping

Например,@GetMapping - это более короткая форма выражения@RequestMapping(method = RequestMethod.GET). В следующем примере показан контроллер MVC, который был упрощен с помощью составной аннотации@GetMapping.

@Controller
@RequestMapping("/appointments")
public class AppointmentsController {

    private final AppointmentBook appointmentBook;

    @Autowired
    public AppointmentsController(AppointmentBook appointmentBook) {
        this.appointmentBook = appointmentBook;
    }

    @GetMapping
    public Map get() {
        return appointmentBook.getAppointmentsForToday();
    }
}

7. Аннотации@RequestScope,@SessionScope,@ApplicationScope

При использовании компонентов, управляемых аннотациями, или Java Config, аннотации@RequestScope,@SessionScope и@ApplicationScope могут использоваться для назначения компонента требуемой области. Эти аннотации не только устанавливают область действия bean-компонента, но также устанавливают режим прокси с областью действия наScopedProxyMode.TARGET_CLASS.

РежимTARGET_CLASS означает, что прокси-сервер CGLIB будет использоваться для проксирования этого bean-компонента и обеспечения возможности его внедрения в любой другой bean-компонент, даже с более широкой областью действия. РежимTARGET_CLASS позволяет проксировать не только интерфейсы, но и классы.

@RequestScope
@Component
public class LoginAction {
    // ...
}
@SessionScope
@Component
public class UserPreferences {
    // ...
}
@ApplicationScope
@Component
public class AppPreferences {
    // ...
}

8. Аннотации@RequestAttribute и@SessionAttribute

Появились еще две аннотации для внедрения параметров HTTP-запроса в методыController, а именно@RequestAttribute и@SessionAttribute. Они позволяют вам получить доступ к некоторым уже существующим атрибутам, управляемым на глобальном уровне (т.е. внеController). Значения для этих атрибутов могут предоставляться, например, зарегистрированными экземплярамиjavax.servlet.Filter илиorg.springframework.web.servlet.HandlerInterceptor.

Предположим, мы зарегистрировали следующую реализациюHandlerInterceptor, которая анализирует запрос и добавляет параметрlogin к сеансу и еще один параметрquery к запросу:

public class ParamInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request,
      HttpServletResponse response, Object handler) throws Exception {
        request.getSession().setAttribute("login", "john");
        request.setAttribute("query", "invoices");
        return super.preHandle(request, response, handler);
    }

}

Такие параметры могут быть введены в экземплярController с соответствующими аннотациями к аргументам метода:

@GetMapping
public String get(@SessionAttribute String login,
  @RequestAttribute String query) {
    return String.format("login = %s, query = %s", login, query);
}

9. Libraries/Application Servers Versions Support

Spring 4.3 поддерживает следующие версии библиотеки и поколения серверов:

  • Hibernate ORM 5.2 (по-прежнему поддерживает 4.2 / 4.3 и 5.0 / 5.1, а 3.6 уже не рекомендуется)

  • Джексон 2.8 (минимум поднят до Джексона 2.6+ начиная с весны 4.3)

  • OkHttp 3.x (все еще поддерживает OkHttp 2.x бок о бок)

  • Нетти 4.1

  • Undertow 1.4

  • Tomcat 8.5.2, а также 9.0 M6

Кроме того, Spring 4.3 включает обновленные версии ASM 5.1 и Objenesis 2.4 вspring-core.jar.

10. InjectionPointс

КлассInjectionPoint - это новый класс, представленный в Spring 4.3, которыйprovides information about places where a particular bean gets injected, будь то параметр метода / конструктора или поле.

Типы информации, которую вы можете найти с помощью этого класса:

  • ОбъектField - вы можете получить точку инъекции, обернутую как объектField, используя методgetField(), если bean-компонент вводится в поле

  • MethodParameter - вы можете вызвать методgetMethodParameter(), чтобы получить точку инъекции, обернутую как объектMethodParameter, если bean-компонент введен в параметр

  • Member - вызов методаgetMember() вернет сущность, содержащую внедренный bean-компонент, завернутый в объектMember

  • Class<?> - получить объявленный тип параметра или поля, в которое внедрен bean-компонент, используяgetDeclaredType()

  • Annotation[] - используя методgetAnnotations(), вы можете получить массив объектов Annotation, которые представляют аннотации, связанные с полем или параметром

  • AnnotatedElement - вызовgetAnnotatedElement(), чтобы точка инъекции была обернута как объектAnnotatedElement

Случай, в котором этот класс очень полезен, - это когда мы хотим создать bean-компонентыLogger на основе класса, к которому они принадлежат:

@Bean
@Scope("prototype")
public Logger logger(InjectionPoint injectionPoint) {
    return Logger.getLogger(
      injectionPoint.getMethodParameter().getContainingClass());
}

Компонент должен быть определен с областью действияprototype, чтобы для каждого класса создавался отдельный регистратор. Если вы создаете bean-компонентsingleton и вводите его в нескольких местах, Spring вернет первую встреченную точку внедрения.

Затем мы можем внедрить bean в нашAppointmentsController:

@Autowired
private Logger logger;

11. Заключение

В этой статье мы обсудили некоторые новые функции, появившиеся в Spring 4.3.

Мы рассмотрели полезные аннотации, которые исключают шаблон, новые полезные методы поиска и внедрения зависимостей, а также несколько существенных улучшений в Интернете и средствах кэширования.

Вы можете найти исходный код статьиon GitHub.