Was ist neu in Spring 4.3?

1. Übersicht

Die Version Spring 4.3 brachte einige nette Verbesserungen in den Bereichen Core Container, Caching, JMS, Web MVC und Test-Submodule des Frameworks.

In diesem Beitrag werden wir einige dieser Verbesserungen diskutieren, darunter:

  • Implizite Konstruktorinjektion
  • Unterstützung für Java 8-Standardschnittstellenmethoden
  • Verbesserte Auflösung von Abhängigkeiten
  • Verfeinerungen der Cache-Abstraktion
  • Zusammengesetzte @ RequestMapping- Varianten
  • @Requestscope, @Sessionscope, @Applicationscope Annotations
  • Anmerkungen zu @RequestAttribute und @SessionAttribute
  • Unterstützung für Versionen von Bibliotheken / Anwendungsservern
  • die InjectionPoint- Klasse

2. Implizite Konstruktorinjektion

Betrachten Sie die folgende Serviceklasse:

@Service public class FooService { private final FooRepository repository; @Autowired public FooService(FooRepository repository) { this.repository = repository } }

Ein recht häufiger Anwendungsfall. Wenn Sie jedoch die Annotation @Autowired für den Konstruktor vergessen, löst der Container eine Ausnahme aus, die nach einem Standardkonstruktor sucht, es sei denn, Sie führen die Verkabelung explizit durch.

Ab 4.3 müssen Sie in einem solchen Einzelkonstruktorszenario keine explizite Injection-Annotation mehr angeben. Dies ist besonders elegant für Klassen, die überhaupt keine Anmerkungen enthalten:

public class FooService { private final FooRepository repository; public FooService(FooRepository repository) { this.repository = repository } }

In Spring 4.2 und niedriger funktioniert die folgende Konfiguration für diese Bean nicht, da Spring keinen Standardkonstruktor für FooService finden kann . Spring 4.3 ist intelligenter und verdrahtet den Konstruktor automatisch automatisch:

In ähnlicher Weise haben Sie möglicherweise bemerkt, dass @ Configuration- Klassen die Konstruktorinjektion in der Vergangenheit nicht unterstützt haben. Ab 4.3 ist dies der Fall , und natürlich können Sie @Autowired auch in einem Einzelkonstruktorszenario weglassen :

@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. Unterstützung von Java 8-Standardschnittstellenmethoden

Vor Spring 4.3 wurden Standardschnittstellenmethoden nicht unterstützt.

Dies war nicht einfach zu implementieren, da selbst der JavaBean-Introspector von JDK keine Standardmethoden als Zugriffsmethoden erkannte. Seit Spring 4.3 werden Getter und Setter, die als Standardschnittstellenmethoden implementiert sind, während der Injektion identifiziert, sodass sie beispielsweise als allgemeine Präprozessoren für Eigenschaften verwendet werden können, auf die zugegriffen wird, wie in diesem Beispiel:

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

Dieser Bean kann jetzt die Eigenschaft stringDate injiziert werden:

Gleiches gilt für die Verwendung von Testanmerkungen wie @BeforeTransaction und @AfterTransaction für Standardschnittstellenmethoden. JUnit 5 unterstützt bereits seine Testanmerkungen zu Standardschnittstellenmethoden, und Spring 4.3 folgt dem Beispiel. Jetzt können Sie die allgemeine Testlogik in einer Schnittstelle abstrahieren und in Testklassen implementieren. Hier ist eine Schnittstelle für Testfälle, die Nachrichten vor und nach Transaktionen in Tests protokolliert:

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

Eine weitere Verbesserung in Bezug auf Annotationen @BeforeTransaction, @AfterTransaction und @Transactional ist die Lockerung der Anforderung, dass die annotierten Methoden öffentlich sein müssen - jetzt können sie eine beliebige Sichtbarkeitsstufe haben.

4. Verbesserte Auflösung von Abhängigkeiten

In der neuesten Version wird auch der ObjectProvider eingeführt , eine Erweiterung der vorhandenen ObjectFactory- Schnittstelle mit praktischen Signaturen wie getIfAvailable und getIfUnique , um eine Bean nur dann abzurufen , wenn sie vorhanden ist oder wenn ein einzelner Kandidat ermittelt werden kann (insbesondere: ein primärer Kandidat bei mehreren passende Bohnen).

@Service public class FooService { private final FooRepository repository; public FooService(ObjectProvider repositoryProvider) { this.repository = repositoryProvider.getIfUnique(); } }

Sie können ein solches ObjectProvider- Handle für benutzerdefinierte Auflösungszwecke während der Initialisierung wie oben gezeigt verwenden oder das Handle in einem Feld für eine späte On-Demand-Auflösung speichern (wie Sie es normalerweise mit einer ObjectFactory tun ).

5. Verfeinerungen der Cache-Abstraktion

Die Cache-Abstraktion wird hauptsächlich zum Zwischenspeichern von Werten verwendet, die CPU und E / A verbrauchen. In bestimmten Anwendungsfällen kann ein bestimmter Schlüssel von mehreren Threads (dh Clients) parallel angefordert werden, insbesondere beim Start. Die Unterstützung für synchronisierten Cache ist eine seit langem angeforderte Funktion, die jetzt implementiert wurde. Nehmen Sie Folgendes an:

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

Beachten Sie das Attribut sync = true , das das Framework anweist, alle gleichzeitigen Threads zu blockieren, während der Wert berechnet wird. Dadurch wird sichergestellt, dass dieser intensive Vorgang bei gleichzeitigem Zugriff nur einmal aufgerufen wird.

Spring 4.3 verbessert auch die Caching-Abstraktion wie folgt:

  • SpEL-Ausdrücke in Cache-bezogenen Annotationen können jetzt auf Beans verweisen (dh @ beanName.method () ).
  • ConcurrentMapCacheManager und ConcurrentMapCache unterstützen jetzt die Serialisierung von Cache-Einträgen über ein neues storeByValue- Attribut.
  • @Cacheable , @CacheEvict , @CachePut und @Caching können jetzt als Meta-Annotationen verwendet werden, um benutzerdefinierte zusammengesetzte Annotationen mit Attributüberschreibungen zu erstellen.

6. Zusammengesetzte @ RequestMapping- Varianten

In Spring Framework 4.3 werden die folgenden auf Methodenebene zusammengesetzten Varianten der Annotation @RequestMapping eingeführt , mit denen Zuordnungen für gängige HTTP-Methoden vereinfacht und die Semantik der mit Annotationen versehenen Handlermethode besser ausgedrückt werden können.

  • @ GetMapping
  • @ PostMapping
  • @ PutMapping
  • @ DeleteMapping
  • @PatchMapping

For example, @GetMapping is a shorter form of saying @RequestMapping(method = RequestMethod.GET). The following example shows an MVC controller that has been simplified with a composed @GetMapping annotation.

@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 Annotations

When using annotation-driven components or Java Config, the @RequestScope, @SessionScope and @ApplicationScope annotations can be used to assign a component to the required scope. These annotations not only set the scope of the bean but also set the scoped proxy mode to ScopedProxyMode.TARGET_CLASS.

TARGET_CLASS mode means that CGLIB proxy will be used for proxying of this bean and ensuring that it can be injected in any other bean, even with a broader scope. TARGET_CLASS mode allows proxying not only for interfaces but classes too.

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

8. @RequestAttribute and @SessionAttribute Annotations

Two more annotations for injecting parameters of the HTTP request into Controller methods appeared, namely @RequestAttribute and @SessionAttribute. They allow you to access some pre-existing attributes, managed globally (i.e. outside the Controller). The values for these attributes may be provided, for instance, by registered instances of javax.servlet.Filter or org.springframework.web.servlet.HandlerInterceptor.

Suppose we have registered the following HandlerInterceptor implementation that parses the request and adds login parameter to the session and another query parameter to a request:

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

Such parameters may be injected into a Controller instance with corresponding annotations on method arguments:

@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 supports the following library versions and server generations:

  • 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

Furthermore, Spring 4.3 embeds the updated ASM 5.1 and Objenesis 2.4 in spring-core.jar.

10. InjectionPoint

The InjectionPoint class is a new class introduced in Spring 4.3 which provides information about places where a particular bean gets injected, whether it is a method/constructor parameter or a field.

The types of information you can find using this class are:

  • Field object – you can obtain the point of injection wrapped as a Field object by using the getField() method if the bean is injected into a field
  • MethodParameter – you can call getMethodParameter() method to obtain the injection point wrapped as a MethodParameter object if the bean is injected into a parameter
  • Member – calling getMember() method will return the entity containing the injected bean wrapped into a Member object
  • Class – obtain the declared type of the parameter or field where the bean in injected, using getDeclaredType()
  • Annotation[] – by using the getAnnotations() method, you can retrieve an array of Annotation objects which represent the annotations associated with the field or parameter
  • AnnotatedElement – call getAnnotatedElement() to get the injection point wrapped as an AnnotatedElement object

A case in which this class is very useful is when we want to create Logger beans based on the class to which they belong:

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

The bean has to be defined with a prototype scope so that a different logger is created for each class. If you create a singleton bean and inject in multiple places, the Spring will return the first encountered injection point.

Then, we can inject the bean into our AppointmentsController:

@Autowired private Logger logger;

11. Conclusion

In this article, we discussed some of the new features introduced with Spring 4.3.

We've covered useful annotations that eliminate boilerplate, new helpful methods of dependency lookup and injection and several substantial improvements within the web and caching facilities.

Den Quellcode für den Artikel finden Sie auf GitHub.