«1. Обзор

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

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

    Внедрение неявного конструктора. Поддержка методов интерфейса Java 8 по умолчанию. Улучшенное разрешение зависимостей. Уточнения абстракции кэша. и аннотации @SessionAttribute Версии библиотек/серверов приложений Поддержка класса 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 умнее и автоматически подключает конструктор:

<beans>
    <bean class="com.baeldung.spring43.ctor.FooRepository" />
    <bean class="com.baeldung.spring43.ctor.FooService" />
</beans>

Точно так же вы могли заметить, что классы @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 по умолчанию

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

Это было непросто реализовать, потому что даже интроспектор JDK JavaBean не обнаруживал методы по умолчанию в качестве методов доступа. Начиная с 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 инъекции:

<bean id="dateHolder" 
  class="com.baeldung.spring43.defaultmethods.DateHolder">
    <property name="stringDate" value="15.10.1982"/>
</bean>

То же самое касается использования тестовых аннотаций, таких как @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, — это смягчение требования о том, что аннотированные методы должны быть общедоступными — Теперь они могут иметь любой уровень видимости.

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

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

@Service
public class FooService {

    private final FooRepository repository;

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

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

5. Уточнения абстракции кэша

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

@Service
public class FooService {

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

}

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

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

  • SpEL expressions in cache-related annotations can now refer to beans (i.e. @beanName.method()).
  • ConcurrentMapCacheManager and ConcurrentMapCache now support the serialization of cache entries via a new storeByValue attribute.
  • @Cacheable, @CacheEvict, @CachePut, and @Caching may now be used as meta-annotations to create custom composed annotations with attribute overrides.

«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<String, Appointment> get() {
        return appointmentBook.getAppointmentsForToday();
    }
}

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

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

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

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

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

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

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);
    }

}

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

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

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

9. Поддержка версий библиотек/серверов приложений

  • Hibernate ORM 5.2 (still supporting 4.2/4.3 and 5.0/5.1 as well, with 3.6 deprecated now)
  • Jackson 2.8 (minimum raised to Jackson 2.6+ as of Spring 4.3)
  • OkHttp 3.x (still supporting OkHttp 2.x side by side)
  • Netty 4.1
  • Undertow 1.4
  • Tomcat 8.5.2 as well as 9.0 M6

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

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

10. InjectionPoint

Класс InjectionPoint — это новый класс, представленный в Spring 4.3, который предоставляет информацию о местах, куда вводится конкретный компонент, будь то параметр метода/конструктора или поле.

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

Объект Field — вы можете получить точку внедрения, обернутую как объект Field, используя метод getField(), если bean-компонент вводится в поле MethodParameter — вы можете вызвать метод getMethodParameter() для получения точки внедрения, обернутой как объект MethodParameter, если bean-компонент вводится в параметр Member — вызов метода getMember() вернет сущность, содержащую внедренный bean-компонент, обернутый в Member object Class\u003c?\u003e — получить объявленный тип параметра или поля, куда был введен bean-компонент, используя getDeclaredType() Annotation[] — используя метод getAnnotations(), вы можете получить массив объектов Annotation, которые представляют аннотации, связанные с полем или параметром AnnotatedElement — вызовите getAnnotatedElement(), чтобы получить точку внедрения в виде объекта AnnotatedElement

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

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

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

@Autowired
private Logger logger;

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

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

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

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