令和時代に「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
が省略可能になりました。
@Component
public class Hoge {
private final Fuga fuga;
// コンストラクタが1つしか無いので@Autowiredは省略可能!
public Hoge(Fuga fuga) {
this.fuga = fuga;
}
}
クラスをイミュータブルにできるので、可能な限りコンストラクタインジェクションを使いましょう。
@RequestMapping
ではなく @GetMapping
などを使うべし
Spring MVCでコントローラークラス・メソッドを書くには @RequestMapping
を使います。
@Controller
@RequestMapping("/hoge")
public class HogeController {
@RequestMapping(value = "/index", method = RequestMethod.GET)
public String index() {
return "index";
}
}
Spring 4.3から、 @GetMapping
・ @PostMapping
など各HTTPリクエストメソッドごとのアノテーションが導入されました。とても短く書けていいですね!
@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形式で書くことは可能です。
<!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形式で書くことができます。
<!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
クラスを継承することが多いです。
@Configuration
@EnableWebMvc
public class MvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
...
}
...
}
Spring 5.0からこのクラスは非推奨になり、このクラスが実装している WebMvcConfigurer
インタフェースを使うことが推奨されています。
@Configuration
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
...
}
...
}
WebMvcConfigurerAdapter
クラスは、 WebMvcConfigurer
インタフェースを実装して、全メソッドを実装が空の状態でオーバーライドしたクラスです。Java 8ベースになったことで、 WebMvcConfigurer
インタフェースの全メソッドが、実装が空のデフォルトメソッドになりました。これにより役目を終えたため、 WebMvcConfigurerAdapter
クラスは非推奨になったのです。
@NotBlank
ではなく、Bean Validationの @NotBlank
を使うべし
Hibernate Validatorの 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
パッケージ)は非推奨になりました。
CrudRepository
に互換性が無いので注意すべし
Spring Dataの Spring Data 2.xから、 CrudRepository
に定義されたメソッドの名前・戻り値などが変更されました。
変更点は java.util.Optional
対応、メソッド名変更などです。
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();
}
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();
}
PasswordEncoder
は必ず明示的に設定すべし
Spring Securityの Spring Security 4以前では、 PasswordEncoder
を明示的に指定しなかった場合、パスワードのハッシュ化が行われませんでした。
Spring Security 5以降では、 PasswordEncoder
を明示的に指定しなかった場合、 DelegatingPasswordEncoder
が使われるようになりました。これは、DBなどに保存されているパスワードのプレフィックスを読んで、適切な PasswordEncoder
に処理を委譲するものです。
<img width="866" alt="スクリーンショット 2019-12-31 11.03.14.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58650/d1e1471a-46c5-11ca-22e3-93370139848e.png">
本番環境で PasswordEncoder
を指定していない人はいないと思います(そう信じたい)。しかし、勉強用のコードでは簡略化のために指定しないことはあったかと思います。Spring Security 5.x以降では、必ず指定しましょう。 PasswordEncoder
をBean定義すればOKです。もちろん、DBなどに保存されているパスワードも同じアルゴリズムの 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勉強会で発表された資料を追加しておきます。どちらも貴重な資料ですので、ぜひ読んでみてください!
勉強会スライド
- 決済サービスのSpring Bootのバージョンを2系に上げた話(@b1a9idps)
- Spring Boot 1.5→2.1バージョンアップを経験して分かったハマりどころ(@kawakawaryuryu)
@b1a9idps さんのブログ一覧
- 決済サービスのSpring Bootのバージョンを2系に上げた
- Flyway 3.x -> 5.xに上げた
- Spring Boot 1.5.xから2.0.xに上げた ~Spring Web編~
- Spring Boot 1.5.xから2.0.xに上げた ~Spring Data編~
- Spring Boot 1.5.xから2.0.xに上げた ~Spring Test編~
2020-10-16追記
Spring Boot 2.3以降では、spring-boot-starter-webにHibernate Validatorが含まれなくなりました(Release Note)。
Hibernate Validatorを使いたい場合は、spring-boot-starter-validationを追加する必要があります。
WebSecurityConfigurerAdapter
が非推奨になった
(2022-06-16追記) Spring Securityの セキュリティ設定の書き方が大幅に変わりました。詳細は👇の記事をご参照ください。
まとめ
思い出したら順次追記していきます。
Discussion