What’s New in Spring 4.3? – Spring 4.3有什么新内容?

最后修改: 2016年 7月 14日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

The Spring 4.3 release brought some nice refinements into core container, caching, JMS, Web MVC and testing submodules of the framework.

Spring 4.3版本为框架的核心容器、缓存、JMS、Web MVC和测试子模块带来了一些不错的改进。

In this post, we will discuss few of these improvements including:

在这篇文章中,我们将讨论其中的一些改进,包括。

  • Implicit Constructor Injection
  • Java 8 Default Interface Methods Support
  • Improved Resolution of Dependencies
  • Cache Abstraction Refinements
  • Composed @RequestMapping Variants
  • @Requestscope, @Sessionscope, @Applicationscope Annotations
  • @RequestAttribute and @SessionAttribute annotations
  • Libraries/Application Servers Versions Support
  • the InjectionPoint class

2. Implicit Constructor Injection

2.隐式构造函数注入

Consider the following service class:

考虑以下服务类。

@Service
public class FooService {

    private final FooRepository repository;

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

Quite a common use case, but if you forget the @Autowired annotation on the constructor, the container will throw an exception looking for a default constructor, unless you explicitly do the wiring.

这是很常见的情况,但是如果你忘记了构造函数上的@Autowired注解,容器就会抛出一个寻找默认构造函数的异常,除非你明确地进行布线。

So as of 4.3, you no longer need to specify an explicit injection annotation in such a single-constructor scenario. This is particularly elegant for classes which do not carry any annotations at all:

所以从4.3开始,你不再需要在这样的单一构造者的情况下指定一个显式注入注解。这对于那些根本不携带任何注解的类来说特别优雅。

public class FooService {

    private final FooRepository repository;

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

In Spring 4.2 and below, the following configuration for this bean will not work, because Spring will not be able to find a default constructor for FooService. Spring 4.3 is smarter and will autowire the constructor automatically:

在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>

Similarly, you may have noticed that @Configuration classes historically did not support constructor injection. As of 4.3, they do, and they naturally allow omitting @Autowired in a single-constructor scenario as well:

同样地,你可能已经注意到,@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 Default Interface Methods Support

3.Java 8默认接口方法支持

Before Spring 4.3, default interface methods were not supported.

在Spring 4.3之前,不支持默认接口方法。

This was not easy to implement because even JDK’s JavaBean introspector did not detect default methods as accessors. Since Spring 4.3, getters and setters implemented as default interface methods are identified during injection, which allows to use them for instance as common preprocessors for accessed properties, like in this example:

这并不容易实现,因为即使是JDK的JavaBean自省器也没有检测到默认方法作为访问器。从Spring 4.3开始,作为默认接口方法实现的getters和setters会在注入过程中被识别出来,这样就可以把它们作为访问属性的普通预处理器,就像本例中一样。

public interface IDateHolder {

    void setLocalDate(LocalDate localDate);

    LocalDate getLocalDate();

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

}

This bean may now have the stringDate property injected:

这个Bean现在可以注入stringDate属性了。

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

Same goes for using test annotations like @BeforeTransaction and @AfterTransaction on default interface methods. JUnit 5 already supports its test annotations on default interface methods, and Spring 4.3 follows the lead. Now you can abstract common testing logic in an interface and implement it in test classes. Here is an interface for test cases that logs messages before and after transactions in tests:

在默认接口方法上使用@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");
    }

}

Another improvement concerning annotations @BeforeTransaction, @AfterTransaction and @Transactional is the relaxation of the requirement that the annotated methods should be public — now they may have any visibility level.

关于注释@BeforeTransaction, @AfterTransaction@Transactional的另一项改进是放宽了注释方法应该是public的要求–现在它们可以有任何可见性级别。

4. Improved Resolution of Dependencies

4.改进依赖关系的解决

The newest version also introduces the ObjectProvider, an extension of the existing ObjectFactory interface with handy signatures such as getIfAvailable and getIfUnique to retrieve a bean only if it exists or if a single candidate can be determined (in particular: a primary candidate in case of multiple matching beans).

最新版本还引入了ObjectProvider,这是现有的ObjectFactory接口的扩展,具有方便的签名,如getIfAvailablegetIfUnique,只在一个bean存在或可以确定一个候选bean的情况下检索它(特别是:在有多个匹配bean的情况下的主要候选bean)。

@Service
public class FooService {

    private final FooRepository repository;

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

You may use such ObjectProvider handle for custom resolution purposes during initialization as shown above, or store the handle in a field for late on-demand resolution (as you typically do with an ObjectFactory).

你可以在初始化期间使用这样的ObjectProvider句柄来实现自定义解析的目的,如上所示,或者将句柄存储在一个字段中,以便后期按需解析(正如你通常对ObjectFactory所做的那样)。

5. Cache Abstraction Refinements

5.缓存抽象的细化

The cache abstraction is mainly used to cache values that are CPU and IO consuming. In particular use cases, a given key may be requested by several threads (i.e. clients) in parallel, especially on startup. Synchronized cache support is a long-requested feature that has now been implemented. Assume the following:

缓存抽象主要用于缓存那些消耗CPU和IO的值。在特殊的用例中,一个给定的键可能被几个线程(即客户端)并行请求,特别是在启动时。同步缓存支持是一个长期被要求的功能,现在已经实现了。假设如下。

@Service
public class FooService {

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

}

Notice the sync = true attribute which tells the framework to block any concurrent threads while the value is being computed. This will make sure that this intensive operation is invoked only once in case of concurrent access.

请注意sync = true属性,它告诉框架在计算值的时候要阻止任何并发线程。这将确保在并发访问的情况下,这个密集操作只被调用一次。

Spring 4.3 also improves the caching abstraction as follows:

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. Composed @RequestMapping Variants

6.组成的@RequestMapping变体

Spring Framework 4.3 introduces the following method-level composed variants of the @RequestMapping annotation that help to simplify mappings for common HTTP methods and better express the semantics of the annotated handler method.

Spring Framework 4.3引入了以下@RequestMapping注解的方法级组成变体,有助于简化常见HTTP方法的映射,并更好地表达注解的处理方法的语义。

  • @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.

例如,@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 Annotations

7.@RequestScope, @SessionScope, @ApplicationScope 注解

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.

当使用注解驱动的组件或Java Config时,@RequestScope@SessionScope@ApplicationScope注解可用于将组件分配到所需的范围。这些注解不仅可以设置Bean的作用域,还可以将作用域代理模式设置为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.

TARGET_CLASS模式意味着CGLIB代理将被用于代理这个Bean,并确保它可以被注入任何其他Bean中,甚至是更大的范围。TARGET_CLASS 模式不仅允许对接口进行代理,也允许对类进行代理.

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

8. @RequestAttribute and @SessionAttribute Annotations

8.@RequestAttribute@SessionAttribute 注释

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.

又出现了两个用于将HTTP请求的参数注入Controller方法中的注解,即@RequestAttribute@SessionAttribute。它们允许你访问一些预先存在的属性,全局管理(即在控制器之外)。这些属性的值可以由javax.servlet.Filterorg.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:

假设我们注册了以下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);
    }

}

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

这些参数可以被注入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

9.库/应用服务器版本支持

Spring 4.3 supports the following library versions and server generations:

Spring 4.3支持以下库的版本和服务器世代。

  • 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.

此外,Spring 4.3在spring-core.jar中嵌入了更新的ASM 5.1和Objenesis 2.4。

10. InjectionPoint

10.注射点

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.

InjectionPoint类是Spring 4.3中引入的一个新类,它提供了关于特定Bean被注入的地方的信息,无论是方法/构造函数参数还是字段。

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:

这个类非常有用的情况是,当我们想根据它们所属的类来创建LoggerBean。

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

必须用prototype范围来定义Bean,以便为每个类创建不同的记录器。如果你创建了一个singleton bean并在多个地方注入,Spring将返回第一个遇到的注入点。

Then, we can inject the bean into our AppointmentsController:

然后,我们可以将Bean注入到我们的AppointmentsController

@Autowired
private Logger logger;

11. Conclusion

11.结论

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

在这篇文章中,我们讨论了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.

我们已经涵盖了消除模板的有用注解、依赖性查询和注入的新的有用方法以及网络和缓存设施中的一些实质性改进。

You can find the source code for the article on GitHub.

你可以在GitHub上找到这篇文章的源代码