Quoi de neuf au printemps 4.3?

Quoi de neuf au printemps 4.3?

1. Vue d'ensemble

La version Spring 4.3 a apporté quelques améliorations intéressantes dans les sous-modules de base du conteneur, de la mise en cache, de JMS, de Web MVC et du test.

Dans cet article, nous aborderons quelques-unes de ces améliorations, notamment:

  • Injection de constructeur implicite

  • Support des méthodes d'interface Java 8 par défaut

  • Résolution améliorée des dépendances

  • Améliorations de l'abstraction du cache

  • Variantes composées@RequestMapping

  • @Requestscope, @Sessionscope, @Applicationscope Annotations

  • Annotations@RequestAttribute et@SessionAttribute

  • Libraries/Application Servers Versions Support

  • la classeInjectionPoint

2. Injection de constructeur implicite

Considérez la classe de service suivante:

@Service
public class FooService {

    private final FooRepository repository;

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

Un cas d'utilisation assez courant, mais si vous oubliez l'annotation@Autowired sur le constructeur, le conteneur lèvera une exception à la recherche d'un constructeur par défaut, sauf si vous effectuez explicitement le câblage.

Ainsi, à partir de la version 4.3, il n'est plus nécessaire de spécifier une annotation d'injection explicite dans un tel scénario à constructeur unique. Ceci est particulièrement élégant pour les cours qui ne portent aucune annotation:

public class FooService {

    private final FooRepository repository;

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

Dans Spring 4.2 et les versions antérieures, la configuration suivante pour ce bean ne fonctionnera pas, car Spring ne pourra pas trouver de constructeur par défaut pourFooService. Spring 4.3 est plus intelligent et autorisera automatiquement le constructeur:


    
    

De même, vous avez peut-être remarqué que les classes@Configuration ne supportaient pas historiquement l'injection de constructeur. À partir de 4.3, ils le font, et ils permettent naturellement d'omettre@Autowired dans un scénario à un seul constructeur:

@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. Support des méthodes d'interface Java 8 par défaut

Avant Spring 4.3, les méthodes d'interface par défaut n'étaient pas prises en charge.

Cela n’a pas été facile à mettre en œuvre car même l’introspecteur JavaBean de JDK ne détectait pas les méthodes par défaut comme accesseurs. Depuis Spring 4.3, les getters et les setters implémentés en tant que méthodes d'interface par défaut sont identifiés lors de l'injection, ce qui permet de les utiliser par exemple comme préprocesseurs communs pour les propriétés accédées, comme dans cet exemple:

public interface IDateHolder {

    void setLocalDate(LocalDate localDate);

    LocalDate getLocalDate();

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

}

Ce bean peut maintenant avoir la propriétéstringDate injectée:


    

Il en va de même pour l'utilisation d'annotations de test comme@BeforeTransaction et@AfterTransaction sur les méthodes d'interface par défaut. JUnit 5 prend déjà en charge ses annotations de test sur les méthodes d'interface par défaut, et Spring 4.3 suit l'exemple. Vous pouvez maintenant résumer la logique de test commune dans une interface et l'implémenter dans des classes de test. Voici une interface pour les cas de test qui enregistre les messages avant et après les transactions dans les tests:

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

}

Une autre amélioration concernant les annotations@BeforeTransaction,@AfterTransaction et@Transactional est l'assouplissement de l'exigence selon laquelle les méthodes annotées doivent êtrepublic - maintenant elles peuvent avoir n'importe quel niveau de visibilité.

4. Résolution améliorée des dépendances

La dernière version introduit également lesObjectProvider, une extension de l'interfaceObjectFactory existante avec des signatures pratiques telles quegetIfAvailable etgetIfUnique pour récupérer un bean uniquement s'il existe ou si un un seul candidat peut être déterminé (en particulier: un candidat principal en cas de plusieurs beans correspondants).

@Service
public class FooService {

    private final FooRepository repository;

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

Vous pouvez utiliser ce descripteurObjectProvider à des fins de résolution personnalisée lors de l'initialisation, comme indiqué ci-dessus, ou stocker le descripteur dans un champ pour une résolution à la demande tardive (comme vous le faites généralement avec unObjectFactory).

5. Améliorations de l'abstraction du cache

L'abstraction du cache est principalement utilisée pour mettre en cache des valeurs qui consomment du processeur et des E / S. Dans des cas d'utilisation particuliers, une clé donnée peut être demandée par plusieurs threads (c'est-à-dire clients) en parallèle, notamment au démarrage. La prise en charge du cache synchronisé est une fonctionnalité demandée depuis longtemps qui a maintenant été implémentée. Supposons ce qui suit:

@Service
public class FooService {

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

}

Remarquez l'attributsync = true qui indique au framework de bloquer tous les threads simultanés pendant le calcul de la valeur. Cela garantira que cette opération intensive n'est appelée qu'une fois en cas d'accès simultané.

Spring 4.3 améliore également l'abstraction de la mise en cache comme suit:

  • Les expressions SpEL dans les annotations liées au cache peuvent désormais faire référence à des beans (c'est-à-dire @beanName.method()).

  • ConcurrentMapCacheManager etConcurrentMapCache prennent désormais en charge la sérialisation des entrées de cache via un nouvel attributstoreByValue.

  • @Cacheable,@CacheEvict,@CachePut et@Caching peuvent désormais être utilisés comme méta-annotations pour créer des annotations composées personnalisées avec des remplacements d'attributs.

6. Variantes composées@RequestMapping

Spring Framework 4.3 présente les variantes suivantes composées au niveau de la méthode de l'annotation@RequestMapping qui aident à simplifier les mappages pour les méthodes HTTP courantes et à mieux exprimer la sémantique de la méthode de gestionnaire annotée.

  • @GetMapping

  • @PostMapping

  • @PutMapping

  • @DeleteMapping

  • @PatchMapping

Par exemple,@GetMapping est une forme plus courte de dire@RequestMapping(method = RequestMethod.GET). L'exemple suivant montre un contrôleur MVC qui a été simplifié avec une annotation@GetMapping composée.

@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. Annotations@RequestScope,@SessionScope,@ApplicationScope

Lorsque vous utilisez des composants pilotés par annotations ou Java Config, les annotations@RequestScope,@SessionScope et@ApplicationScope peuvent être utilisées pour affecter un composant à la portée requise. Ces annotations définissent non seulement la portée du bean, mais également le mode proxy de portée surScopedProxyMode.TARGET_CLASS.

Le modeTARGET_CLASS signifie que le proxy CGLIB sera utilisé pour le proxy de ce bean et s'assurer qu'il peut être injecté dans n'importe quel autre bean, même avec une portée plus large. Le modeTARGET_CLASS permet le proxy non seulement pour les interfaces mais aussi pour les classes.

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

8. Annotations@RequestAttribute et@SessionAttribute

Deux autres annotations pour injecter les paramètres de la requête HTTP dans les méthodesController sont apparues, à savoir@RequestAttribute et@SessionAttribute. Ils vous permettent d’accéder à certains attributs préexistants, gérés globalement (c.-à-d. en dehors desController). Les valeurs de ces attributs peuvent être fournies, par exemple, par des instances enregistrées dejavax.servlet.Filter ouorg.springframework.web.servlet.HandlerInterceptor.

Supposons que nous ayons enregistré l'implémentationHandlerInterceptor suivante qui analyse la requête et ajoute le paramètrelogin à la session et un autre paramètrequery à une requête:

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

}

De tels paramètres peuvent être injectés dans une instanceController avec les annotations correspondantes sur les arguments de méthode:

@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 prend en charge les versions de bibliothèque et les générations de serveurs suivantes:

  • Hibernate ORM 5.2 (supportant toujours les versions 4.2 / 4.3 et 5.0 / 5.1 également, 3.6 étant obsolète maintenant)

  • Jackson 2.8 (minimum élevé à Jackson 2.6+ à partir du printemps 4.3)

  • OkHttp 3.x (supportant toujours OkHttp 2.x côte à côte)

  • Netty 4.1

  • Undertow 1.4

  • Tomcat 8.5.2 et 9.0 M6

De plus, Spring 4.3 intègre l'ASM 5.1 et l'Objenesis 2.4 mis à jour enspring-core.jar.

10. InjectionPoint

La classeInjectionPoint est une nouvelle classe introduite dans Spring 4.3 quiprovides information about places where a particular bean gets injected, qu'il s'agisse d'un paramètre de méthode / constructeur ou d'un champ.

Les types d'informations que vous pouvez trouver en utilisant cette classe sont:

  • ObjetField - vous pouvez obtenir le point d'injection enveloppé comme un objetField en utilisant la méthodegetField() si le bean est injecté dans un champ

  • MethodParameter - vous pouvez appeler la méthodegetMethodParameter() pour obtenir le point d'injection enveloppé comme un objetMethodParameter si le bean est injecté dans un paramètre

  • Member - l'appel de la méthodegetMember() retournera l'entité contenant le bean injecté enveloppé dans un objetMember

  • Class<?> - obtenir le type déclaré du paramètre ou du champ où le bean est injecté, en utilisantgetDeclaredType()

  • Annotation[] - en utilisant la méthodegetAnnotations(), vous pouvez récupérer un tableau d'objets Annotation qui représentent les annotations associées au champ ou paramètre

  • AnnotatedElement - appelergetAnnotatedElement() pour obtenir le point d'injection enveloppé comme un objetAnnotatedElement

Un cas dans lequel cette classe est très utile est lorsque nous voulons créer des beansLogger en fonction de la classe à laquelle ils appartiennent:

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

Le bean doit être défini avec une portéeprototype afin qu'un enregistreur différent soit créé pour chaque classe. Si vous créez un beansingleton et l'injectez à plusieurs endroits, le Spring renverra le premier point d'injection rencontré.

Ensuite, nous pouvons injecter le bean dans nosAppointmentsController:

@Autowired
private Logger logger;

11. Conclusion

Dans cet article, nous avons présenté certaines des nouvelles fonctionnalités introduites avec Spring 4.3.

Nous avons abordé des annotations utiles qui éliminent le passe-partout, de nouvelles méthodes utiles de recherche et d'injection de dépendances et plusieurs améliorations substantielles au sein du Web et des fonctionnalités de mise en cache.

Vous pouvez trouver le code source de l'articleon GitHub.