Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

令和時代に「Spring入門」「Spring徹底入門」を読むとき気をつけるべきN個のこと

この記事について

事ある度に書いたり言ったりしている通り、2020年を迎えようとしている現在でも、信頼できるSpring関連書籍は下記の2冊しかありません。

2冊(以下「書籍」)とも超良書なのですが、どちらもリリースされたのが2016年で、対応しているSpringのバージョンが4.2と古くなっています。

2019年末時点での最新版はSpring 5.2です。この記事では、上記書籍を令和の今読む際、特に気をつけるべき点をいくつか紹介していきます。

4.x->5.xの差分すべてについては、GitHubのWikiを確認してください。

JDKは8以上を使うべし

Spring 5.0以降から、JDKのベースラインが8になりました(Spring 4はJDK 6ベース)。今からSpringを使おうと言う人が、JDK 6とか7を使おうとはしないと思いますが・・・。

Spring 5.2では、JDK 14までサポートされます。JDKとSpringのバージョン対応の詳細はGitHubのWikiを参照してください。

フィールドインジェクションではなくコンストラクタインジェクション+ @Autowired 省略で書くべし

Spring 4.2以前から、DIの方法は3つありました。

フィールドインジェクションの例
@Component
public class Hoge {
    @Autowired
    Fuga fuga;
}
セッターインジェクションの例
@Component
public class Hoge {
    private Fuga fuga;

    @Autowired
    public void setFuga(Fuga fuga) {
        this.fuga = fuga;
    }
}
コンストラクタインジェクションの例
@Component
public class Hoge {
    private final Fuga fuga;

    @Autowired
    public Hoge(Fuga fuga) {
        this.fuga = fuga;
    }
}

書籍でよく使われているのは、フィールドインジェクションです。おそらく、記述量が最も少ないからでしょう(紙面の都合もあるかも)。

Spring 4.3から、クラス内にコンストラクタがただ1つしかない場合は、 @Autowired が省略可能になりました。

コンストラクタインジェクションの例(4.3以降)
@Component
public class Hoge {
    private final Fuga fuga;

    // コンストラクタが1つしか無いので@Autowiredは省略可能!
    public Hoge(Fuga fuga) {
        this.fuga = fuga;
    }
}

クラスをイミュータブルにできるので、可能な限りコンストラクタインジェクションを使いましょう。

@RequestMapping ではなく @GetMapping などを使うべし

Spring MVCでコントローラークラス・メソッドを書くには @RequestMapping を使います。

4.2以前
@Controller
@RequestMapping("/hoge")
public class HogeController {

    @RequestMapping(value = "/index", method = RequestMethod.GET)
    public String index() {
        return "index";
    }
}

Spring 4.3から、 @GetMapping@PostMapping など各HTTPリクエストメソッドごとのアノテーションが導入されました。とても短く書けていいですね!

4.3以降
@Controller
@RequestMapping("/hoge") // ここは@RequestMappingのままでOK
public class HogeController {

    @GetMapping("/index") // @XxxMappingを使う!
    public String index() {
        return "index";
    }
}

Thymeleaf 3を使いHTML形式で書くべし(not XHTML)

書籍ではThymeleaf 2が使われています。Thymeleaf 2で画面を書くには、XHTML形式で書く必要があります。

ライブラリを追加すれば、2でもHTML形式で書くことは可能です。

2以前
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8" />
    <title>画面</title>
</head>
<body>
<form action="index.html" th:action="@{findByFirstName}">
    名キーワード:<input type="text" name="firstName" />
    <input type="submit" value="検索" />
</form>
...

Thymeleaf 3では、デフォルトでHTML形式で書くことができます。

3以降
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>画面</title>
</head>
<body>
<form action="index.html" th:action="@{findByFirstName}">
    名キーワード:<input type="text" name="firstName">
    <input type="submit" value="検索">
</form>
...

/ を忘れて実行時例外、なんてことが無くなって嬉しいですね!

WebMvcConfigurerAdapter クラスではなく WebMvcConfigurer インタフェースを使うべし

Spring 4.3以前では、Spring MVC関連のJava Configを作成する際、 WebMvcConfigurerAdapter クラスを継承することが多いです。

4.3以前
@Configuration
@EnableWebMvc
public class MvcConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        ...
    }
    ...
}

Spring 5.0からこのクラスは非推奨になり、このクラスが実装している WebMvcConfigurer インタフェースを使うことが推奨されています。

5.0以降
@Configuration
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        ...
    }
    ...
}

WebMvcConfigurerAdapter クラスは、 WebMvcConfigurer インタフェースを実装して、全メソッドを実装が空の状態でオーバーライドしたクラスです。Java 8ベースになったことで、 WebMvcConfigurer インタフェースの全メソッドが、実装が空のデフォルトメソッドになりました。これにより役目を終えたため、 WebMvcConfigurerAdapter クラスは非推奨になったのです。

WebMvcConfigurer のソースコード

Hibernate Validatorの @NotBlank ではなく、Bean Validationの @NotBlank を使うべし

Spring 5からJava EE 8対応により、Bean Validationのバージョンが1.xから2.0(Hibernate Validator 6.0以降)に上がりました。

Spring 5でBean Validation 1.xを使うことも可能ですが、基本的には最新バージョンを使ったほうが良いと思います。

Bean Validation 2.0では、新しい制約アノテーションが追加されました。その一部は、Hibernate Validator独自のアノテーションだったものが、Bean Validation標準に取り入れられたものです。具体的には下記のアノテーションになります(すべて javax.validation.constraints パッケージ)。

  • @NotEmpty
  • @NotBlank
  • @Email

これに伴い、Hibernate Validator独自の @NotBlank@NotEmpty@Email (すべてorg.hibernate.validator.constraints パッケージ)は非推奨になりました。

Spring Dataの CrudRepository に互換性が無いので注意すべし

Spring Data 2.xから、 CrudRepository に定義されたメソッドの名前・戻り値などが変更されました。

変更点は java.util.Optional 対応、メソッド名変更などです。

1以前のCrudRepository
public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> {

    <S extends T> S save(S entity);

    <S extends T> Iterable<S> save(Iterable<S> entities);

    T findOne(ID id);

    boolean exists(ID id);

    Iterable<T> findAll();

    Iterable<T> findAll(Iterable<ID> ids);

    long count();

    void delete(ID id);

    void delete(T entity);

    void delete(Iterable<? extends T> entities);

    void deleteAll();
}
2以降のCrudRepository
public interface CrudRepository<T, ID> extends Repository<T, ID> {

    <S extends T> S save(S entity);

    <S extends T> Iterable<S> saveAll(Iterable<S> entities);

    Optional<T> findById(ID id);

    boolean existsById(ID id);

    Iterable<T> findAll();

    Iterable<T> findAllById(Iterable<ID> ids);

    long count();

    void deleteById(ID id);

    void delete(T entity);

    void deleteAll(Iterable<? extends T> entities);

    void deleteAll();
}

Spring Securityの PasswordEncoder は必ず明示的に設定すべし

Spring Security 4以前では、 PasswordEncoder を明示的に指定しなかった場合、パスワードのハッシュ化が行われませんでした。

Spring Security 5以降では、 PasswordEncoder を明示的に指定しなかった場合、 DelegatingPasswordEncoder が使われるようになりました。これは、DBなどに保存されているパスワードのプレフィックスを読んで、適切な PasswordEncoder に処理を委譲するものです。

スクリーンショット 2019-12-31 11.03.14.png

本番環境で PasswordEncoder を指定していない人はいないと思います(そう信じたい)。しかし、勉強用のコードでは簡略化のために指定しないことはあったかと思います。Spring Security 5.x以降では、必ず指定しましょう。 PasswordEncoder をBean定義すればOKです。もちろん、DBなどに保存されているパスワードも同じアルゴリズムの PasswordEncoder でハッシュ化してください。

PasswordEncoderの指定
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    ...

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

Spring Bootの内容はだいぶ変わっているので注意すべし

Spring Boot 1.x->2.xについては、変更点が多すぎて書ききれませんw

パッと思いつくだけでも、

  • 各種ライブラリのアップデート
    • Spring 4.x -> 5.x
    • Spring Data 1.x -> 2.x
    • Spring Security 4.x -> 5.x
    • Thymeleaf 2 -> 3
    • Hibernate -> 5.4
    • Jackson -> 2.10
    • Hibernate Validator 5.x -> 6.1
    • Flyway 4 -> 6
  • JDK 8対応
    • thymeleaf-extras-java8time追加済み
    • jackson-datatype-jdk8など追加済み
  • セキュリティの簡素化
    • セキュリティ関連のプロパティがほとんど削除された
  • Actuatorの改良
    • 内部アーキテクチャの抜本的変更
    • 認証・認可の変更
    • Micrometerの追加
    • プロパティの変更
  • プロパティのリネーム
    • 各種プロパティの名前が大幅に変更

・・・などなど。他にもいっぱいあるかも。

2020-02-12追記

JSUG勉強会で発表された資料を追加しておきます。どちらも貴重な資料ですので、ぜひ読んでみてください!

勉強会スライド

@b1a9idps さんのブログ一覧

2020-10-16追記

Spring Boot 2.3以降では、spring-boot-starter-webにHibernate Validatorが含まれなくなりました(Release Note)。

Hibernate Validatorを使いたい場合は、spring-boot-starter-validationを追加する必要があります。

まとめ

思い出したら順次追記していきます。

suke_masa
Java / Spring / Microservices / Kubernetes(CKAD) / IntelliJ IDEA
https://www.casareal.co.jp/ls
casareal
システム開発/評価・検証支援/品質改善支援サービスと現場に即した実践的なIT研修サービスを提供しています。
https://www.casareal.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away