1. 概要

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

この投稿では、次のようなこれらの改善点のいくつかについて説明します。

  • 暗黙のコンストラクタインジェクション
  • Java8のデフォルトのインターフェースメソッドのサポート
  • 依存関係の解決の改善
  • キャッシュ抽象化の改良
  • 構成された@RequestMappingバリアント
  • @ Requestscope、@ Sessionscope、@ Applicationscope Annotations
  • @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. Java8のデフォルトのインターフェースメソッドのサポート

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は、デフォルトのインターフェースメソッドでのテストアノテーションをすでにサポートしており、Spring4.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に関する別の改善点は、アノテーション付きメソッドが public である必要があるという要件の緩和です—現在、それらは任意の可視性レベルを持っている可能性があります。

4. 依存関係の解決の改善

最新バージョンでは、 ObjectProvider も導入されています。これは、既存の ObjectFactory インターフェイスの拡張であり、getIfAvailablegetIfUniqueなどの便利な署名を使用して取得します。 Beanが存在する場合、または単一の候補を判別できる場合のみ(特に、一致する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 属性に注意してください。この属性は、値の計算中に同時スレッドをブロックするようにフレームワークに指示します。 これにより、同時アクセスの場合に、この集中的な操作が1回だけ呼び出されるようになります。

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

  • キャッシュ関連のアノテーションのSpEL式でBeanを参照できるようになりました(つまり、 @ beanName.method())。
  • ConcurrentMapCacheManagerおよびConcurrentMapCacheは、新しいstoreByValue属性を介したキャッシュエントリのシリアル化をサポートするようになりました。
  • @Cacheable @CacheEvict @CachePut 、および @Caching をメタ注釈として使用して、カスタム構成の注釈を作成できるようになりました。属性のオーバーライド。

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

Spring Framework 4.3では、 @RequestMapping アノテーションの次のメソッドレベルの合成バリアントが導入されています。これは、一般的なHTTPメソッドのマッピングを簡素化し、アノテーション付きハンドラーメソッドのセマンティクスをより適切に表現するのに役立ちます。

  • @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アノテーション

アノテーション駆動型コンポーネントまたはJavaConfigを使用する場合、 @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が表示されました。 これらを使用すると、グローバルに管理されている既存の属性にアクセスできます(つまり、 コントローラーの外側)。 これらの属性の値は、たとえば、javax.servlet.Filterまたはorg.springframework.web.servlet.HandlerInterceptorの登録済みインスタンスによって提供される場合があります。

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

}

このようなパラメーターは、メソッド引数に対応するアノテーションを付けて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は現在非推奨)
  • ジャクソン2.8(春4.3の時点でジャクソン2.6+に引き上げられた最小値)
  • OkHttp 3.x(引き続きOkHttp 2.xを並べてサポート)
  • Netty 4.1
  • アンダートウ1.4
  • Tomcat8.5.2および9.0M6

さらに、Spring 4.3は、更新されたASM5.1とObjenesis2.4をspring-core.jarに組み込みます。

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

InjectionPoint クラスは、Spring 4.3で導入された新しいクラスであり、は、メソッド/コンストラクターパラメーターまたはフィールドであるかどうかにかかわらず、特定のBeanが注入される場所に関する情報を提供します。

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

  • Field オブジェクト– Beanがフィールドに注入される場合、 getField()メソッドを使用して、Fieldオブジェクトとしてラップされた注入ポイントを取得できます。
  • MethodParameter – Beanがパラメーターに注入される場合、 getMethodParameter()メソッドを呼び出して、MethodParameterオブジェクトとしてラップされた注入ポイントを取得できます。
  • Member getMember()メソッドを呼び出すと、Memberオブジェクトにラップされた注入されたBeanを含むエンティティが返されます
  • クラス> –を使用して、Beanが注入されたパラメータまたはフィールドの宣言されたタイプを取得します。 getDeclaredType()
  • Annotation [] getAnnotations()メソッドを使用すると、フィールドまたはパラメーターに関連付けられた注釈を表すAnnotationオブジェクトの配列を取得できます。
  • AnnotatedElement getAnnotatedElement()を呼び出して、注入ポイントをAnnotatedElementオブジェクトとしてラップします。

このクラスが非常に役立つのは、所属するクラスに基づいてLoggerBeanを作成する場合です。

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

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

次に、BeanをAppointmentsControllerに挿入できます。

@Autowired
private Logger logger;

11. 結論

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

ボイラープレートを排除する便利なアノテーション、依存関係のルックアップとインジェクションの新しい便利な方法、およびWebとキャッシング機能内のいくつかの大幅な改善について説明しました。

記事のソースコードはGitHubにあります。