PHP専門で8年SEをやっていたある日、Javaを業務で利用する機会があり勉強をはじめました。
そこでJavaで有名なフレームワークSpring Bootを使ったのですが、Spring Bootにはたくさんのアノテーションがあり、初学者である自分は混乱してしまいました。
アノテーションをまとめているチートシートを調べてみたら無かったので、勉強も兼ねていっそ自分で作ってしまおうと思った次第です。
以降、チートシートらしく読みやすくするべく、箇条書きの気軽さを残しつつ
- 簡単な説明を付けて
- 利用頻度が多いものは説明を多めに
- 混合しやすい似ているものは比較して
で、記述していきます。
Java標準のもの、Spring Boot、Spring Security、Spring MVC、Lombokなど複数のライブラリにまたがってアノテーションを紹介します。
記事の最後には アルファベット順に並べ一言の説明をつけた一覧も用意しています。
【全体を構成するもの】
@SpringBootApplication
SpringBootアプリケーションを作る際に必須のアノテーション。
これを設定することでアプリケーションの自動設定、コンポーネントスキャン、Bean定義をすべて有効になる。
実際には以下の3つのアノテーションを設定しているのと同等。
-
@Configuration:Javaベースの設定クラスであることを宣言する。@Bean定義などに使える(後でまた登場します) -
@EnableAutoConfiguration:Spring Bootの「自動設定」を有効化。依存関係に応じた設定を自動適用する -
@ComponentScan:現在のパッケージ以下を自動でスキャンし@Component,@Service,@Controller,@Repositoryなどを登録する
逆にSpringBootの自動構成を無効化して手動でMVC設定したい場合 @EnableWebMvc というアノテーションがある。
【DIに関するもの】
@Override
JavaSpringなどがなくても使えるJava標準のアノテーション。
親クラスやインターフェースのメソッドをオーバーライド(再定義)していることをコンパイラに教える。
public class Fruits {
public void color() {
System.out.println("無色");
}
}
public class Lemon extends Fruits {
@Override
public void color() {
System.out.println("黄色");
}
}
@Autowired
対象:クラスのフィールド
記述するとクラス内で「New」をする必要がなくなる。
使いたい他のクラスをインスタンス化して変数に設定してくれる。
使い方は以下の3つの方法がある( 結論:コンストラクタインジェクション が推奨)
①フィールドインジェクションでの利用
public class HogeController {
@Autowired
private HugaService service;
// 以降serviceオブジェクトが利用可
...
}
②セッターインジェクションでの利用
public class HogeController {
private HugaService service;
@Autowired
public setService(HugaService service) {
this.service = service;
}
// 以降serviceオブジェクトが利用可
...
}
③コンストラクタインジェクションでの利用
public class HogeController {
private final HugaService service;
@Autowired
public HogeController(HugaService service) {
this.service = service;
}
// 以降serviceオブジェクトが利用可
...
}
コンストラクタインジェクションでの利用(応用)
コンストラクタが1つの場合は @Autowired アノテーションを省略可能
また Lombok の @RequiredArgsConstructor アノテーションをつけるとコンストラクタの記述自体を省略可能
(※ @RequiredArgsConstructor は後でまた登場しますが大事なアノテーションです)
@RequiredArgsConstructor
public class HogeController {
private final HugaService service;
// 以降serviceオブジェクトが利用可
...
}
@Component
対象:クラス
全4種類 ある インスタンス化したいクラス に付与するアノテーションのうちの1つで、
もっとも基本的、特定の役割を持たない汎用的なもの。
この後登場する @Autowired を使いたいクラスを登録しておくイメージで、
これらをつけるとBeanとして定義される。
@Component
public class Utility {
public String format(String input) { ... }
}
@Controller
対象:クラス
同じくインスタンス化したいクラス に付与するアノテーション。
HTTPリクエストを受け取るクラスにつける。
@Controller
public class HelloController {
@GetMapping("/hello")
public String handle(Model model) { ... }
}
@Service
対象:クラス
同じくインスタンス化したいクラス に付与するアノテーション。
ビジネスロジックを担当するクラスにつける。
@Service
public class UserService {
public void registerUser(User user) { ... }
}
@Repository
対象:クラス
同じくインスタンス化したいクラス に付与するアノテーション。
データベースとのやりとり(DAO)をするクラスにつける。
@Repository
public class UserRepository {
public User findById(Long id) { ... }
}
4つのアノテーションのまとめ
| アノテーション | 主な用途 | よく使うクラス |
|---|---|---|
@Component |
汎用コンポーネント(共通処理など) | ユーティリティ、共通ヘルパー |
@Repository |
データアクセス層(DB関連) | DAO、リポジトリクラス |
@Service |
ビジネスロジック層(サービス処理) | サービスクラス |
@Controller |
プレゼンテーション層(Web受け口) | Webのコントローラ |
レイヤー構造イメージ
Controller ← @Controller
↓
Service Layer ← @Service
↓
Repository Layer ← @Repository
↓
DB / 外部API
@Configuration / @Bean
対象:クラス、メソッド
これまで登場した他のアノテーションを使うのが難しい場合にはJavaConfigという Beanを生成するクラス を使うのだが、そのクラスに付けるアノテーション。
そのクラス内でインスタンスを作成するメソッドには @Bean アノテーションがつく。
@Configuration
public class AppConfig {
@Bean
public MyService myService() {
return new MyServiceImpl();
}
}
@Scope("XXXXXX")
対象:クラス
()の中に決められたルールを指定することでインスタンスを生成(=破棄)するタイミングを指定することができる。
@Bean
@Scope("prototype")
public MyService myService() {
return new MyService();
}
代表的なものは以下
-
singleton:デフォルトでこれ、コンテナ内で1つだけインスタンスを共有 -
prototype:インスタンスが必要なたびに毎回新しいものを生成 -
request:HTTPリクエストごとに新しいインスタンスを生成
@Primary
対象:クラス
例えば同じインターフェースをimplementsしている2つのクラスがあった場合
依存注入する側(他のクラスを New をしているクラス、つまり @Autowired などを書くクラス)ではどのクラスが注入したいもの(Newしたいもの)かわからない。
その場合 @Primary が記述されたクラスが優先だと判断できる。
また @Qualifier アノテーションを使うと注入する側でクラスを明示的に選ぶことができる。
(使い方は検索)
【Controllerクラスにつけるもの】
@Controller / @RestController
対象:クラス
つけることでSpring Bootがそのクラスをコントローラだと認識する。
通常は @Controller を使うが、JSONやXMLなどを返すWebAPI用のコントローラでは @RestController を使う。
@RequestMapping
対象:メソッド
クライアントからのリクエストに対して動くメソッドを対応させることができる。
この仕組みを マッピング という。
@RequestMapping("/greet_morning")
public string greetAtMorning() {
return "Good morning.";
}
@RequestMapping("/greet_night")
public string greetAtNight() {
return "Good evening.";
}
@RequestMapping は属性を利用することでマッピングの条件を指定できる。
@RequestMapping(value="/greet_night", method=RequestMethod.GET, headers="Accept=application/*", params="id=0900")
しかし、ただ単にGETとPOSTくらいしか条件を指定しない場合は以下に紹介する @GetMapping と @PostMapping を利用すると method=RequestMethod.GET の部分を省略することができる。
@GetMapping / @PostMapping
対象:メソッド
それぞれ @RequestMapping のGET用とPOST用のもの。
よって以下の2つは機能的に全く同じ。文字数が減るのでこっちの2つを利用したほうがいいと思う。
@RequestMapping(value="/greet_morning", method=RequestMethod.GET)
@GetMapping(value="/greet_morning")
ちなみに @GetMapping と @PostMapping でも属性を利用することでマッピングの条件を指定できる。
@GetMapping(value = "/greet_morning", params = "id", produces = "application/json")
@RequestParam
対象:メソッドの引数
リクエストに含まれるパラメータを取得することができる。
Webアプリケーション開発ならよく使う。
先述の @XXXMapping 系のアノテーションと組み合わせ使う。
@GetMapping("/greet")
public String greet(@RequestParam String name) {
return "Hello, " + name;
}
他にも色々な属性があるがよく使うのは以下
-
required:必須かどうか -
defaultValue:パラメータが存在しない時のデフォルト値
属性はカンマ区切りで複数記述できる。
以下の様に属性を複数つけると初学者の可読性は一気に下がるが慣れていきたい。
以下の例では /search?q=apple なら "apple" を、
/search(パラメータ無し)なら "all" を返します。
@GetMapping("/keyword-search")
public String search(@RequestParam(value = "q", required = false, defaultValue = "all") String query) {
return "検索キーワード:" + query;
}
1行が長くなってきたら改行も検討しよう。
@PathVariable
対象:メソッドの引数
これも @RequestParam と同じ様にリクエストに含まれるパラメータを取得するものだが、
こちらはURLのパスそのものから値を取得する。つまり、
-
@RequestParamは?name=XXXの部分を取得 -
@PathVariableは/user/{XXX}の部分を取得
という違いがある。
同時に利用すると以下のような例になる。
以下では /users/5/orders?page=2 というURLが想定される。
{userId}の部分を @PathVariable で取得し、URLの最後の page=2 を @RequestParam で取得している。
@GetMapping("/users/{userId}/orders")
public String getUserOrders (
@PathVariable Long userId,
@RequestParam(defaultValue = "1") int page
) {
return "User ID: " + userId + ", Page: " + page;
}
@ModelAttribute / @RequestBody
対象:メソッドの引数
@RequestParam、@PathVariableに加えて、この2つもHTTPリクエストからパラメータを取得するものだが、
@ModelAttribute は フォーム送信された複数の値をまとめて1つのオブジェクトとして取得ができる。
<form method="post" action="/register">
<input name="name" />
<input name="email" />
</form>
このフォームから送られた値が以下で取得される。
@PostMapping("/register")
public String register(@ModelAttribute UserForm form) {
return "Welcome " + form.getName();
}
@RequestBody はフォーム送信ではなく JSONやXMLなどの構造化データをのオブジェクトとして取得する。
以下のような感じ。
{
"name": "Taro",
"email": "taro@example.com"
}
@PostMapping("/api/users")
public String createUser(@RequestBody UserDto user) {
return "Created: " + user.getName();
}
よって4つのアノテーションをまとめると以下のような表になる。
| 目的 | 使うアノテーション |
|---|---|
| パスから取得するを取りたい | @PathVariable |
| クエリパラメータを使う | @RequestParam |
| フォームデータをまとめてオブジェクト化 | @ModelAttribute |
| JSONをオブジェクト化 | @RequestBody |
※コントローラに渡されるリクエストデータの変換・整形・バリデーションをカスタマイズするためには、@InitBinderアノテーションをつけたメソッドを用意する。
@ControllerAdvice
対象:クラス
すべてのコントローラに共通の処理 を作りたい時、このアノテーションを用いる。
例外処理、バリデーションなどを行うクラスでの利用が想定される。
@ExceptionHandler
対象:メソッド
特定の例外 発生時に呼び出されるメソッドを定義する。
サービス全体で共通の例外であれば @ControllerAdvice アノテーションを使っているクラス内で用いられる。
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<String> handleIllegalArg(IllegalArgumentException ex) {
return ResponseEntity.badRequest().body("不正な引数: " + ex.getMessage());
}
【Repositoryクラスにつけるもの】
@Data
対象:クラス
Lombok のアノテーションであり、使うことで 多くのコードの記述を省略できる。
クラスに設定されたすべてのフィールドに対して必要なgetter/setter、 toString() メソッドなどを自動生成してくれる。
public class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{name='" + name + "'}";
}
}
上記のコードと同じ機能が以下のコードにまで省略される。
import lombok.Data;
@Data
public class Person {
private String name;
}
他にも equals() や hashCode() も自動で作られる。
Lombokには@Getter,@Setter,@ToString,@EqualsAndHashCode,@RequiredArgsConstructorなど多くの便利なアノテーションがあるが、@Dataを使うことですべてのアノテーションを省略することができる。
簡単なBeanの作成に向いている。
@◯◯ArgsConstructor
それぞれコンストラクタの記述を省略してくれるアノテーション。
@RequiredArgsConstructor
finalまたは@NonNullが付いたフィールドだけを引数に取るコンストラクタを自動生成する。
@RequiredArgsConstructor
public class User {
private final String username;
private final int age;
private String address;
}
以下が自動生成される。
public User(String username, int age) {
this.username = username;
this.age = age;
}
@NoArgsConstructor
引数なしのデフォルトコンストラクタを自動生成する。
@NoArgsConstructor
public class User {
private String username;
private int age;
}
以下が自動生成される。
public User() {
}
@AllArgsConstructor
すべてのフィールドを引数に取るコンストラクタを自動生成する。
@AllArgsConstructor
public class User {
private String username;
private int age;
}
public User(String username, int age) {
this.username = username;
this.age = age;
}
@Entity / @Id
対象:クラス/フィールド値
@Entity アノテーションを使うことでJPA(Java Persistence API)対象であることを示す。(「永続化対象」という呼び方)
つまりは、 クラス1つとテーブル1つとリンクさせるイメージ。
同時に @Id アノテーションを いずれかのフィールド値に設定することが必須となる。
@Id を書いたフィールド値が主キーとなる。主キーがないと永続化ができない。
基本的にはテーブル名とクラス名を同じにするが、
テーブル名とクラス名が別の場合は @Table アノテーションを使う。
@Table(name = "users") のようにして @Entity と並べてクラスに記述する。
自動裁判をする際には @GeneratedValue(strategy = GenerationType.IDENTITY) を同時に使うことが多い
@Entity
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private int price;
}
@Transient
対象:フィールド値
@Entity を使ったクラスにおいて、DBに保存しない値を指定するためのアノテーション。
一時的な計算結果などに用いたりする。
@Query / @Modifying / @Transactional
SQLを書くメソッドには @Query アノテーションが必要となる。
また更新(UPDATE)または削除(DELETE)のクエリの場合は @Modifying のアノテーションも併せて必要となる。
更新・削除の場合トランザクションが必要であるため、さらに併せて @Transactional 利用する。
public interface UserRepository extends JpaRepository<User, Long> {
@Transactional
@Modifying
@Query("UPDATE User u SET u.age = :age WHERE u.id = :id")
int updateAge(@Param("id") Long id, @Param("age") int age);
}
@JoinColumn / @OneToOne / @OneToMany / @ManyToOne
対象:フィールド値
どれも リレーション(テーブル間の関連) を定義するときに使うアノテーション。
リレーションの説明は割愛するが、記述が簡潔になる、整合性の確保が楽になるなどのメリットがある。
| アノテーション | 関係 | 意味(片側から見た関係) |
|---|---|---|
| @OneToOne | 1対1 | 「1人のユーザーに1つのプロフィール」など |
| @OneToMany | 1対多 | 「1人のユーザーに複数の投稿」など |
| @OneToMany | 多対1 | 「複数の投稿は1人のユーザーに属する」など |
| @JoinColumn | 外部キー指定 | 外部キー列(FK)をどのカラムにするか明示する |
以下のように書いておけば
@Entity
public class Post {
@Id
private Long id;
private String title;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
}
リポジトリ層、サービス層では記述が簡単になる。
Post post = postRepository.findById(1).get();
String userName = post.getUser().getName();
// JOIN不要で、投稿ID:1の投稿のユーザー名や名前をuserテーブルから取得できている
【バリデーションをするもの】
@Validated
対象:メソッドの引数 もしくは クラス
バリデーションをする際に利用するアノテーション。
利用方法が複数あるため、詳しくは割愛し、簡単な例を記載する。
メソッドに書く方法
フォームの値をバリデーションするクラスを作成しておく。
@PostMapping("/submit")
public String submitForm(@Validated @ModelAttribute UserForm form) {
// バリデーション済みの form を使える
return "OK";
}
public class UserForm {
@NotBlank
private String name;
@Email
private String email;
// getter/setter省略
}
クラスに書く方法
@Service
@Validated
public class UserService {
public void deleteUser(@Min(1) Long id) {
// idが0や負の数なら例外が発生する
}
}
バリデーションルール用のアノテーション
他にも多くあるがよく使う一部を紹介。
| アノテーション | 説明 |
|---|---|
| @NotNull | nullの禁止 |
| @NotBlank | 空文字・空白 禁止 |
| @Size | 長さ・サイズの範囲 |
| メールアドレス形式かどうか | |
| @Pattern | 正規表現による形式チェック |
【セキュリティ(SpringSecurity)】
@EnableWebSecurity
Spring SecurityのWebセキュリティサポートを有効になり、
認証・認可などのフィルターが適用される。
現在は以下のように SecurityFilterChain と併用して使うのが主流となっている。
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authz -> authz
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().permitAll()
)
.formLogin(Customizer.withDefaults()); // ログインフォームを有効化
return http.build();
}
}
@PreAuthorize / @PostAuthorize
@PreAuthorize はメソッドが呼び出される前にアクセス権をチェックし、
@PostAuthorize はメソッドの実行後にアクセス権をチェックする。
@AuthenticationPrincipal
認証済みのユーザー情報をメソッド引数に注入する。
@GetMapping("/profile")
public String getProfile(@AuthenticationPrincipal UserDetails userDetails) {
return "ユーザー名: " + userDetails.getUsername();
}
まとめ
| アノテーション | ライブラリ/分類 | 説明 |
|---|---|---|
@AllArgsConstructor |
Lombok | 全フィールドを引数に持つコンストラクタを自動生成 |
@AuthenticationPrincipal |
Spring Security | 認証済みユーザー情報を取得 |
@Autowired |
Spring Framework | 依存性注入 (DI) を行う |
@Bean |
Spring Framework | SpringコンテナにBean定義を登録 |
@Component |
Spring Framework | 汎用のDI対象クラスを定義 |
@Configuration |
Spring Framework | 設定クラスであることを明示 |
@Controller |
Spring MVC | Webリクエストを処理するクラスを定義 |
@ControllerAdvice |
Spring MVC | 例外処理やバインディング処理の共通化 |
@Data |
Lombok | Getter/Setter, toString などを自動生成 |
@EnableWebSecurity |
Spring Security | Spring Securityの設定を有効化 |
@Entity |
Spring Data JPA | JPAエンティティクラスを定義 |
@ExceptionHandler |
Spring MVC | 例外処理メソッドを定義 |
@GetMapping |
Spring MVC | GETリクエストをマッピング |
@Id |
Spring Data JPA | 主キーを表す |
@JoinColumn |
Spring Data JPA | 関連テーブルの結合列を指定 |
@ManyToOne |
Spring Data JPA | 多対一のリレーションを定義 |
@ModelAttribute |
Spring MVC | リクエストパラメータをオブジェクトにバインド |
@Modifying |
Spring Data JPA | 変更系のクエリを定義 |
@NoArgsConstructor |
Lombok | 引数なしコンストラクタを自動生成 |
@OneToMany |
Spring Data JPA | 一対多のリレーションを定義 |
@OneToOne |
Spring Data JPA | 一対一のリレーションを定義 |
@Override |
Java標準 | メソッドのオーバーライドを明示 |
@PathVariable |
Spring MVC | URLパスの変数部分を取得 |
@PostAuthorize |
Spring Security | メソッド呼び出し後の権限チェック |
@PostMapping |
Spring MVC | POSTリクエストをマッピング |
@PreAuthorize |
Spring Security | メソッド呼び出し前の権限チェック |
@Primary |
Spring Framework | 複数候補があるときに優先されるBeanを指定 |
@Query |
Spring Data JPA | 独自JPQLクエリを指定 |
@Repository |
Spring Framework | データアクセス層のクラスを定義 |
@RequestBody |
Spring MVC | リクエストのボディをJavaオブジェクトに変換 |
@RequestMapping |
Spring MVC | リクエストをメソッドにマッピング |
@RequestParam |
Spring MVC | リクエストパラメータを取得 |
@RequiredArgsConstructor |
Lombok | final フィールド用コンストラクタを自動生成 |
@RestController |
Spring MVC | REST API用コントローラ(Controller + ResponseBody) |
@Scope("XXXXXX") |
Spring Framework | Beanのスコープを定義(例: singleton, prototype) |
@Service |
Spring Framework | ビジネスロジック層のクラスを定義 |
@SpringBootApplication |
Spring Boot | アプリ全体の設定と自動構成を有効化 |
@Transactional |
Spring Framework / JPA | トランザクション管理を行う |
@Transient |
Spring Data JPA | 永続化対象外のフィールドを定義 |
@Validated |
Spring Framework | バリデーションを有効にする |