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