Apa yang Baru pada Musim Bunga 4.3?

1. Gambaran keseluruhan

Rilis Spring 4.3 membawa beberapa penyempurnaan yang bagus ke dalam wadah teras, caching, JMS, Web MVC dan submodul pengujian kerangka.

Dalam catatan ini, kami akan membincangkan beberapa penambahbaikan ini termasuk:

  • Suntikan Pembina Tersirat
  • Java 8 Kaedah Antaramuka Lalai Sokongan
  • Penyelesaian Ketergantungan yang Lebih Baik
  • Penyempurnaan Abstraksi Cache
  • Terdiri @RequestMapping Kelainan
  • @Requestscope, @Sessionscope, @Aplicationscope Anotasi
  • @RequestAttribute dan @SessionAttribute anotasi
  • Sokongan Versi Perpustakaan / Pelayan Aplikasi
  • yang InjectionPoint kelas

2. Suntikan Pembina Tersirat

Pertimbangkan kelas perkhidmatan berikut:

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

Cukup biasa digunakan, tetapi jika anda terlupa anotasi @Autowired pada konstruktor, bekas akan membuang pengecualian untuk mencari konstruktor lalai, kecuali jika anda secara terang-terangan melakukan pendawaian.

Oleh itu, pada 4.3, anda tidak perlu lagi menentukan anotasi suntikan eksplisit dalam senario pembangun tunggal tersebut. Ini sangat elegan untuk kelas yang sama sekali tidak membawa anotasi:

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

Pada musim bunga 4.2 dan ke bawah, konfigurasi berikut untuk kacang ini tidak akan berfungsi, kerana musim bunga tidak akan dapat mencari pembina lalai untuk FooService . Musim bunga 4.3 lebih pintar dan akan mengaktifkan pembina secara automatik:

Begitu juga, anda mungkin menyedari bahawa kelas @Configuration secara historis tidak menyokong suntikan konstruktor. Pada 4.3, mereka melakukannya, dan secara semula jadi mereka membenarkan menghilangkan @Autowired dalam senario pembangun tunggal juga:

@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 Sokongan Kaedah Antaramuka Lalai

Sebelum Spring 4.3, kaedah antara muka lalai tidak disokong.

Ini tidak mudah dilaksanakan kerana bahkan introspector JavaBean JDK tidak mengesan kaedah lalai sebagai aksesor. Sejak Spring 4.3, getter dan setter yang dilaksanakan sebagai kaedah antara muka lalai dikenal pasti semasa suntikan, yang memungkinkan untuk menggunakannya sebagai preprocessor biasa untuk sifat yang diakses, seperti dalam contoh ini:

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

Kacang ini sekarang mempunyai sifat stringDate yang disuntikkan:

Begitu juga dengan penggunaan anotasi ujian seperti @BeforeTransaction dan @AfterTransaction pada kaedah antara muka lalai. JUnit 5 sudah menyokong anotasi ujiannya pada kaedah antara muka lalai, dan Spring 4.3 mengikuti petunjuknya. Sekarang anda boleh menyusun logik ujian biasa di antara muka dan menerapkannya di kelas ujian. Berikut adalah antara muka untuk kes ujian yang mencatat mesej sebelum dan selepas transaksi dalam ujian:

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

Penambahbaikan lain mengenai anotasi @BeforeTransaction, @AfterTransaction dan @Transactional adalah kelonggaran syarat bahawa kaedah anotasi harus terbuka - sekarang mereka mungkin mempunyai tahap keterlihatan.

4. Peningkatan Penyelesaian Ketergantungan

Versi terbaru juga memperkenalkan ObjectProvider , perpanjangan antara muka ObjectFactory yang ada dengan tandatangan berguna seperti getIfAvailable dan getIfUnique untuk mengambil kacang hanya jika ada atau jika calon tunggal dapat ditentukan (khususnya: calon utama sekiranya terdapat beberapa kacang sepadan).

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

Anda boleh menggunakan pegangan ObjectProvider seperti itu untuk tujuan resolusi tersuai semasa inisialisasi seperti yang ditunjukkan di atas, atau menyimpan pegangan di medan untuk penyelesaian permintaan atas permintaan (seperti yang biasa anda lakukan dengan ObjectFactory ).

5. Penyempurnaan Abstraksi Cache

Pengabaian cache terutama digunakan untuk menyimpan nilai yang memakan CPU dan IO. Dalam kes penggunaan tertentu, kunci yang diberikan mungkin diminta oleh beberapa utas (iaitu klien) secara selari, terutama pada permulaan. Sokongan cache yang disegerakkan adalah ciri yang lama diminta dan kini telah dilaksanakan. Andaikan perkara berikut:

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

Perhatikan atribut sync = true yang memberitahu kerangka untuk menyekat sebarang benang serentak semasa nilainya dihitung. Ini akan memastikan bahawa operasi intensif ini hanya dilakukan sekali sekiranya berlaku akses serentak.

Spring 4.3 juga meningkatkan pengabaian cache seperti berikut:

  • Ungkapan spEL dalam anotasi yang berkaitan dengan cache kini boleh merujuk kepada kacang (iaitu @ beanName.method () ).
  • ConcurrentMapCacheManager dan ConcurrentMapCache kini menyokong siri penyertaan cache melalui atribut storeByValue baru .
  • @Cacheable , @CacheEvict , @CachePut , dan @Caching kini dapat digunakan sebagai anotasi meta untuk membuat anotasi tersusun khas dengan penggantian atribut.

6. Varian @RequestMapping yang digubah

Spring Framework 4.3 memperkenalkan varian kaedah-kaedah berikut dari anotasi @RequestMapping yang membantu mempermudah pemetaan untuk kaedah HTTP biasa dan lebih baik menyatakan semantik kaedah pengendali anotasi.

  • @GetMapping
  • @Peta Pemetaan
  • @PutMapping
  • @HapusPemetaan
  • @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.

Anda boleh mendapatkan kod sumber untuk artikel di GitHub.