Spring 4.3の新機能

1概要

Spring 4.3リリースでは、コアコンテナ、キャッシング、JMS、Web MVC、そしてフレームワークのテストサブモジュールにいくつかの素晴らしい改良が加えられました。

この記事では、これらの改善点のいくつかについて説明します。

暗黙的なコンストラクタインジェクション

  • Java 8デフォルトインタフェースメソッドのサポート

  • 依存関係の改善された解決

  • キャッシュ抽象化の改良

  • 構成された @​​ RequestMapping バリアント

  • @ RequestScope @ SessionScope @ ApplicationScope アノテーション

  • @ RequestAttribute および @ 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以前では、Springは FooService のデフォルトコンストラクタを見つけることができないため、このBeanに対する次の設定は機能しません。 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 に関するもう1つの改善点は、アノテーション付きメソッドを public にするという要件の緩和です。

** 4依存関係の解決の向上

最新バージョンでは、既存の ObjectFactory インタフェースの拡張である getIfAvailable getIfUnique などの既存の ObjectFactory インタフェースを拡張して、Beanが存在する場合、または単一の候補を特定できる場合にのみ取得します(特に複数の場合は主候補)。マッチング豆)。

@Service
public class FooService {

    private final FooRepository repository;

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

上記のように初期化中にカスタム解決を目的としてそのような ObjectProvider ハンドルを使用するか、遅いオンデマンド解決のためにフィールドにハンドルを格納することができます(通常は ObjectFactory を使用して行うように)。

5キャッシュ抽象化の改良点

キャッシュ抽象化は、主にCPUとIOが消費する値をキャッシュするために使用されます。特定の使用例では、所与のキーは、特に起動時に、いくつかのスレッド(すなわちクライアント)によって並行して要求されることがある。

同期キャッシュのサポートは現在要求されている長い間要求されている機能です。次のように仮定します。

@Service
public class FooService {

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

}

sync = true 属性に注目してください。これは、値が計算されている間、フレームワークに並行スレッドをブロックするよう指示します。これにより、この集中的な操作が同時アクセスの場合に一度だけ呼び出されるようになります。

Spring 4.3では、キャッシュの抽象化も次のように改善されました。

  • キャッシュ関連アノテーション内のSpEL式は、Beanを参照することができる

(つまり、 @beanName.method() )。

  • ConcurrentMapCacheManager ConcurrentMapCache は現在、

新しい storeByValue 属性によるキャッシュエントリのシリアル化。

  • @ Cacheable @ CacheEvict @ CachePut 、および @ Caching は、

属性をオーバーライドしたカスタム合成注釈を作成するためのメタ注釈として使用されます。

6. 構成された @​​ RequestMapping バリアント

Spring Framework 4.3では、一般的なHTTPメソッドのマッピングを単純化し、アノテーション付きハンドラメソッドのセマンティクスをよりよく表現するのに役立つ、次のようなメソッドレベルで構成された @​​ RequestMapping アノテーションの変形が導入されています。

  • @ GetMapping

  • @ PostMapping

  • @ PutMapping

  • @ DeleteMapping

  • @ PatchMapping

たとえば、 @ GetMapping は、 @ RequestMapping(method = RequestMethod.GET) と言うより短い形式です。次の例は、 @ GetMapping という注釈を付けて単純化したMVCコントローラを示しています。

@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プロキシがこのBeanのプロキシとして使用され、より広いスコープであっても他のBeanに確実に挿入できることを意味します。 TARGET CLASS モードでは、インターフェースだけでなくクラスもプロキシーできます _. _

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

8. @ RequestAttribute および @ SessionAttribute アノテーション

HTTPリクエストのパラメータを Controller メソッドにインジェクトするためのさらに2つのアノテーション、つまり @ RequestAttribute @ SessionAttribute が登場しました。それらを使用すると、グローバルに(つまり Controller の外部で)管理されている既存の属性にアクセスできます。これらの属性の値は、例えば、 javax.servlet.Filter または org.springframework.web.servlet.HandlerInterceptor の登録済みインスタンスによって提供されます。

リクエストを解析してセッションに login パラメータを、リクエストに別の query パラメータを追加する、次の 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);
    }

}

そのようなパラメータは、メソッドの引数に対応するアノテーションを付けて Controller インスタンスに注入することができます。

@GetMapping
public String get(@SessionAttribute String login,
  @RequestAttribute String query) {
    return String.format("login = %s, query = %s", login, query);
}

9ライブラリ/アプリケーションサーバーのバージョンサポート

Spring 4.3は、次のライブラリバージョンとサーバー世代をサポートします。

  • Hibernate ORM 5.2(まだ4.2/4.3と5.0/5.1もサポートしています)

3.6今は廃止予定) ** Jackson 2.8(Spring 4.3以降はJackson 2.6まで引き上げられました)

  • OkHttp 3.x(OkHttp 2.xをサポートしています)

  • ネッティ4.1

  • Undertow 1.4

Tomcat 8.5.2および9.0 M6

さらに、Spring 4.3では、更新されたASM 5.1とObjenesis 2.4が spring-core.jar に埋め込まれています。

10 インジェクションポイント

InjectionPoint クラスは、Spring 4.3で導入された新しいクラスで、メソッド/コンストラクタパラメータでもフィールドでも、特定のBeanがインジェクトされる場所に関する情報を提供します。

このクラスを使用して見つけることができる情報の種類は次のとおりです。

  • Field オブジェクト - あなたは、注入点をラップとして得ることができます。

Beanがインジェクトされている場合は getField() メソッドを使用して Field オブジェクト フィールドに ** MethodParameter - getMethodParameter() メソッドを呼び出すことができます

以下の場合、 MethodParameter オブジェクトとしてラップされた注入点を取得します。 Beanがパラメータにインジェクトされている ** Member - getMember() メソッドを呼び出すとエンティティが返されます

Member オブジェクトにラップされた注入済みBeanを含む ** Class <?> - 宣言されたパラメータまたはフィールドの型を取得する

getDeclaredType()を使用して、インジェクトされたBean ** Annotation[] - getAnnotations()__メソッドを使うことで、

注釈を表すAnnotationオブジェクトの配列を取得します フィールドまたはパラメータに関連付けられている ** AnnotatedElement - インジェクションを取得するために getAnnotatedElement() を呼び出す

AnnotatedElement オブジェクトとしてラップされたポイント

このクラスが非常に便利な場合は、それらが属するクラスに基づいて Logger Beanを作成したい場合です。

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

クラスごとに異なるロガーが作成されるように、Beanを prototype スコープで定義する必要があります。 singleton Beanを作成して複数の場所に注入すると、Springは最初に見つかった注入ポイントを返します。

それから、Beanを AppointmentsController にインジェクトでき​​ます。

@Autowired
private Logger logger;

11結論

この記事では、Spring 4.3で導入されたいくつかの新機能について説明しました。

ボイラープレートを排除する便利なアノテーション、依存関係のルックアップとインジェクションの新しい便利な方法、そしてウェブとキャッシュ機能の中のいくつかの実質的な改善をカバーしました。

on GitHub の記事のソースコードを見つけることができます。