Spring Bootの概要
Springは、企業アプリケーション開発の複雑さを解決するために作られた、階層化された軽量なJavaオープンソースフレームワークです。その階層化されたアーキテクチャにより、ユーザーは必要なコンポーネントを選択できます。また、IoC(Inversion of Control)メカニズムはビジネスオブジェクトの置き換えの複雑さを低減し、コンポーネント間の結合を緩やかにします。AOP(Aspect-Oriented Programming)サポートにより、セキュリティ、トランザクション、ログなどの共通タスクを集中管理でき、再利用性を向上させます。さらに、ORMとサードパーティの永続化フレームワークとの良好な統合により、データベースアクセスの底層が簡素化されます。
Spring Bootは、Springプロジェクトを迅速に構築するためのフレームワークであり、開発者の設定作業を大幅に削減します。XML設定ファイルが不要になり、多くのハードウェアデバイスのドライバが同梱されています。その核となるのは「規約优于配置」(設定より規約)という理念で、デフォルトの設定を最大限に活用することで、手動設定を最小限に抑えます。Spring Bootはマイクロサービス向けのインターフェース開発に特化し、フロントエンドとの分離を図ります。
SpringとSpring Bootの比較
- Spring Bootは「規約优于配置」の原則に従い、SpringプロジェクトのXMLおよびJava設定を自動設定によって削減します。
- Spring Bootはスターター依存関係を導入することで、プロジェクトに必要な依存関係を自動的に追加し、手動での依存関係の管理を避け、アプリケーションの迅速な起動を可能にします。
- Spring Bootは様々なデフォルト設定とすぐに使える機能を提供することで、開発プロセスを大幅に簡素化し、テンプレートコードの記述を減らします。
- Spring Bootはマイクロサービス向けのインターフェース開発に特化し、フロントエンドとの分離を図ります。
Spring Bootのデフォルト設定ファイルは、application.ymlまたはapplication.propertiesでなければならず、かつ一意である必要があります。デフォルトではsrc/main/resourcesディレクトリから設定ファイルを探します。
設定ファイルの優先順位は、.properties > .yml > .yaml です。
Spring Bootでは、XML設定の代わりにアノテーションが使用されます。例えば、@Configurationで設定クラスを修飾し、その中でBeanを宣言します。@ComponentScanは、デフォルトで修飾されたクラスのパッケージをスキャンし、@Componentで修飾されたクラスをBeanとしてコンテナに登録します。@PropertySourceはプロパティリソースファイルを導入し、アプリケーション内で@Valueや@ConfigurationPropertiesを使用して値を取得します。@Importは@Configuration、ImportSelector、またはImportBeanDefinitionRegistrarで修飾された設定クラスを導入します。@ImportResourceはXML設定ファイルを導入します。
Springの核心:AOPとIoC
AOP(アスペクト指向プログラミング)
AOP(Aspect-Oriented Programming)は、直訳すると「アスペクト指向プログラミング」です。AOPはプログラミング思想であり、オブジェクト指向プログラミング(OOP)の補完的なものです。アスペクト指向プログラミングは、ソースコードを修正せずにプログラムに動的に共通機能を追加する技術です。
適用シーン:
- ログ記録
- トランザクション管理
- 権限検証
- パフォーマンス監視
核心概念:
- Joinpoint(接続点):インターセプト可能な点。Springでは、一般的にインターセプト可能なメソッドを指します。
- Pointcut(ポイントカット):Joinpointの一部で、インターセプトされるべき点。特定のルールに基づいてJoinpointからフィルタリングされた特定の接続点です。
- Advice(アドバイス):Pointcutをインターセプトした後に実行される強化処理。追加で実行される内容です。
- Target(ターゲット):ターゲットクラス。プロキシされるオブジェクトで、実際のビジネスロジックを実行します。
- Weaving(織り込み):アスペクトをターゲット関数に適用するプロセス。
- Proxy(プロキシ):プロキシオブジェクト。Targetのプロキシオブジェクトです。
- Aspect(アスペクト):通常はクラスで、ポイントカットとアドバイスを定義します。
Spring AOPには5種類のアドバイスがあります:
@Before(前置アドバイス):ターゲットメソッドの実行前に実行されます。@After(後置アドバイス):ターゲットメソッドの実行後に実行されます。@AfterReturning(戻り値アドバイス):ターゲットメソッドが正常に戻り値を返した後に実行されます。@AfterThrowing(例外アドバイス):ターゲットメソッドが例外をスローした後に実行されます。@Around(周囲アドバイス):ターゲットメソッドの実行前後で実行されます。このメソッドの核心パラメータはProceedingJoinPointで、手動でjoinPoint.proceed()を実行する必要があります。
// ログ記録用のポイントカット定義
@Pointcut("@annotation(com.example.aspect.Logging)")
public void loggingPointcut() {}
// @Aroundアドバイスでメソッド実行を囲む
@Around("loggingPointcut()")
public Object logAround(ProceedingJoinPoint jp) throws Throwable {
// メソッド開始ログ
System.out.println("メソッド開始: " + jp.getSignature().getName());
// 実行前の処理(例: パラメータのログ出力)
Object[] args = jp.getArgs();
if (args != null && args.length > 0) {
System.out.println("引数: " + Arrays.toString(args));
}
// ターゲットオブジェクトとメソッド情報の取得
Object targetObj = jp.getTarget();
Method method = jp.getSignature().getMethod();
try {
// メソッドの実行
Object result = jp.proceed();
// メソッド終了ログ
System.out.println("メソッド終了: " + method.getName() + ", 戻り値: " + result);
return result;
} catch (Exception e) {
// 例外発生時のログ
System.err.println("例外発生: " + method.getName() + ", エラー: " + e.getMessage());
throw e;
}
}
IoC(制御の反転)とDI(依存性注入)
制御の反転IoC(Inversion of Control)は**設計原則**であり、**DI(Dependency Injection)**はIoCを実現する**方法**の一つです。
IoCが導入されていないプログラムでは、オブジェクトの作成とオブジェクト間の依存関係はすべてプログラムにハードコードされています。オブジェクトの作成はプログラム自身が制御します。制御の反転後、オブジェクトの作成は第三者に移譲されます。制御の反転とは、依存オブジェクトの取得方法が反転したことを意味します。
利点:
- ロジックの実行と具体的な実装を分離します。
- モジュールの重点をその機能設計に置きます。
- モジュールをシステムから分離し、具体的な実装を気にせず、依存関係の参照に専念できます。
- モジュールの変更時に影響を与えないようにします。
IoCコンテナ
Spring IoCの実装は、Spring IoCコンテナを使用してインスタンス化されたオブジェクトを管理します。Spring IoCコンテナはBeanを管理するコンテナです。Springの定義では、すべてのIoCコンテナはBeanFactoryインターフェースを実装する必要があります。
package org.springframework.beans.factory;
import org.springframework.beans.BeansException;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;
public interface BeanFactory {
// プレフィックス
String FACTORY_BEAN_PREFIX = "&";
// 複数のgetBeanメソッド
Object getBean(String var1) throws BeansException;
<T> T getBean(String var1, Class<T> var2) throws BeansException;
Object getBean(String var1, Object... var2) throws BeansException;
<T> T getBean(Class<T> var1) throws BeansException;
<T> T getBean(Class<T> var1, Object... var2) throws BeansException;
<T> ObjectProvider<T> getBeanProvider(Class<T> var1);
<T> ObjectProvider<T> getBeanProvider(ResolvableType var1);
// Beanが存在するかどうか
boolean containsBean(String var1);
// Beanがシングルトンかどうか
boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;
// Beanがプロトタイプかどうか
boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;
// 型が一致するかどうか
boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;
// Beanの型を取得
@Nullable
Class<?> getType(String var1) throws NoSuchBeanDefinitionException;
@Nullable
Class<?> getType(String var1, boolean var2) throws NoSuchBeanDefinitionException;
// Beanのエイリアスを取得
String[] getAliases(String var1);
}
ソースコードには複数のgetBeanメソッドがあり、型または名前でBeanを取得できます。SpringはデフォルトでシングルトンBeanを管理することに注意してください。
具体的な注入プロセスは、以下のSpring Bootの起動プロセスを参照してください。
@Autowiredはプロパティに基づいて対応するBeanを見つけて注入します。しかし、注入したいのがインターフェースであり、そのインターフェースに複数の実装クラスがある場合、曖昧さが生じます。
@PrimaryはIoCコンテナに、同じ型のBeanが複数ある場合、優先して自分を使用するように指示します。
@Primaryが複数のクラスに修飾されている場合、@Primaryだけでは曖昧さを解消できません。@Qualifierの設定項目valueは文字列を必要とするため、Autowiredは型と名前の両方でBeanを見つけることができます。
インターセプタとフィルタ
| トリガー | 実装 | 依存 | ライフサイクル | 作用範囲 | その他 | |
| インターセプタ | Servletに入った後 | リフレクション(AOP) | 独立 | IoCコンテナ管理 | メソッドレベルまで | Spring管理下で、IoCコンテナの依存関係を呼び出せる |
| フィルタ | Servletに入る前 | コールバック関数 | Servlet | Servletコンテナ管理 | リクエストの前後 |
使用シーン:
- インターセプタ:ログイン検証、権限検証、ログ記録、パフォーマンス監視、Cookie処理など。
- フィルタ:リクエストパラメータのフィルタリング、文字エンコーディングの設定、URLレベルのアクセス制御、レスポンス情報の圧縮など。
スターター依存関係
Spring Bootでは、Starterは特定のタイプのアプリケーションを迅速に起動するための自己完結型で再利用可能な依存関係セットです。これらは、アプリケーションを構築するために必要なすべてのコンポーネントと設定を含む、事前設定された依存関係です。
Starterには通常、以下が含まれます:
- Spring Bootの自動設定
- 必須の依存関係
- 機能固有の依存関係
最も一般的な例はspring-boot-starter-webです。このStarterを使用すると、@SpringBootApplicationアノテーションでSpringアプリケーションを迅速に起動できます(詳細は以下のSpring Boot起動プロセスを参照)。
spring-boot-starter-webを使用すると、Spring BootはTomcatサーバーとSpring MVCフレームワークを自動的に設定し、手動で設定ファイルを追加する必要がありません。
spring-boot-starter-webには、Spring Bootプロジェクトを起動するために多くの必須依存関係が含まれています。例えば、Springフレームワーク、Spring Bootフレームワークなどです。これらの依存関係はアプリケーションを構築する基盤であり、それらがなければアプリケーションを構築できません。
Starterには、特定の機能を実現するための依存関係も含まれています。例えば、spring-boot-starter-data-jpaはSpring BootアプリケーションでJPAとHibernateを使用するために、spring-boot-starter-testはSpring Bootアプリケーションで単体テストを行うために使用されます。これらの依存関係は特定の機能を実現するために使用され、必要に応じて対応する依存関係を追加できます。
利点:
Starterを使用する利点は、アプリケーションの依存関係管理を大幅に簡素化し、手動で依存関係を追加する手間を省き、アプリケーションの起動を速めることができます。さらに、Starterはアプリケーションをより読みやすくモジュラー化できるようにします。なぜなら、それらはアプリケーションに含まれる機能を明確に指定しているからです。
Spring Bootの起動プロセス
Spring Bootの起動クラスは以下のようになります:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
注意点として、起動クラスがDemoApplicationであっても、SpringApplication.runに渡される設定クラスはDemoApplicationでなくても構いません。runに渡される設定クラスが、Spring Bootのデフォルトスキャンパスを決定します。つまり、その設定クラスのパス配下のすべてのパッケージです。@SpringBootApplicationアノテーションの核心は、@Configuration、@EnableAutoConfiguration、@ComponentScanの3つのアノテーションです。
@Configuration:これはJava設定クラスであることを示します。@ComponentScan:@Component(@Service、@Controller、@Mapperなど)で修飾されたBeanをスキャンし、IoCコンテナに登録します。このスキャンパスは、先ほど言及した渡された設定クラスのパスです。したがって、プロジェクトの対応するクラスに@Service、@Controller、@Mapperなどを追加するだけで、IoCコンテナに管理させることができます。@EnableAutoConfiguration:Spring Bootの自動設定メカニズムを有効にします。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
// 自動設定クラスを型で除外
@AliasFor(
annotation = EnableAutoConfiguration.class
)
Class<?>[] exclude() default {};
// 自動設定クラスを名前で除外
@AliasFor(
annotation = EnableAutoConfiguration.class
)
String[] excludeName() default {};
// スキャンパッケージを定義
@AliasFor(
annotation = ComponentScan.class,
attribute = "basePackages"
)
String[] scanBasePackages() default {};
// スキャンされるクラスを定義
@AliasFor(
annotation = ComponentScan.class,
attribute = "basePackageClasses"
)
Class<?>[] scanBasePackageClasses() default {};
@AliasFor(
annotation = ComponentScan.class,
attribute = "nameGenerator"
)
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
@AliasFor(
annotation = Configuration.class
)
boolean proxyBeanMethods() default true;
}
runメソッドでは、Spring Bootは多くの操作を実行します。デフォルトのTomcatサーバーの起動やSpring MVCの設定などが含まれます。この間、すべてのjarパッケージの自動設定クラス(AutoConfig)について、Spring Bootは導入されたjarパッケージのMETA-INFディレクトリにあるspring.factoriesファイル(*このファイルでは、key-valueの形式で設定クラスファイルの参照パスを示します*)とspring-autoconfigure-metadata.propertiesファイル(*このファイルでは、key-valueの形式で核心設定クラスを示し、Spring Bootがこれらのクラスが正しくロードできるかを迅速に判断し、対応する設定クラスを正常に導入するのを助けます*)をスキャンします。Spring Bootはクラスローダー(classLoader)を使用してこれらのパスをmapの形式で保存し、使用することで自動設定の効果を達成します。
Springキャッシュ
Spring Cacheの詳細は別の記事を参照してください。
Spring Beanは、一级缓存(レベル1キャッシュ)、二级缓存(レベル2キャッシュ)、三级缓存(レベル3キャッシュ)に分かれます。Springコンテナでは、Beanをリクエストするたびに、Springはまず一级、二级、三级キャッシュにそのBeanが存在するかをチェックします。存在する場合は、キャッシュ内のインスタンスオブジェクトを直接返します。存在しない場合は、Beanの作成を行います。
- singletonObjects キャッシュ:一级キャッシュ、または「シングルトンプール」とも呼ばれ、すべてのシングルトンBeanのインスタンスオブジェクトを格納するために使用されます。シングルトンBeanを初めて取得する必要がある場合、Springはまず一级キャッシュにそのBeanインスタンスが存在するかをチェックします。存在する場合は、そのインスタンスを直接返します。存在しない場合は、SpringはBeanの定義情報に基づいて新しいインスタンスを作成し、一级キャッシュに追加します。
- earlySingletonObjects キャッシュ:二级キャッシュ、または「早期シングルトンオブジェクトプール」とも呼ばれ、作成プロセス中のシングルトンBeanインスタンスを格納するために使用されます。シングルトンBeanの作成プロセス中に、そのBeanが他のBeanに依存していることが判明した場合、依存するBeanインスタンスを先に作成する必要があります。この場合、SpringはそのBeanを事前にインスタンス化し、二级キャッシュに追加します。依存するBeanインスタンスの作成が完了すると、SpringはそれをこのBeanインスタンスに注入し、二级キャッシュから削除します。
- singletonFactories キャッシュ:三级キャッシュ、または「シングルトンファクトリプール」とも呼ばれ、シングルトンBeanインスタンスを作成するためのObjectFactoryを格納するために使用されます。シングルトンBeanを作成する際に、そのBeanが他のBeanに依存していることが判明した場合、依存するBeanインスタンスを先に作成する必要があります。この場合、Springは依存するBeanを作成するためのObjectFactoryを三级キャッシュに保存します。依存するBeanインスタンスの作成が完了すると、SpringはそのObjectFactoryを使用してこのBeanインスタンスを作成し、三级キャッシュから削除します。
二级キャッシュと三级キャッシュの違い:
- オブジェクトの保存方法が異なります:二级キャッシュには作成中のBeanインスタンスが保存され、三级キャッシュにはBeanインスタンスを作成するためのObjectFactoryオブジェクトが保存されます。
- 使用タイミングが異なります:二级キャッシュは主に循環依存の問題を解決するために使用されます。つまり、2つ以上のBeanが互いに依存し、すべてがシングルトンである場合、二级キャッシュを介して循環依存の問題を解決する必要があります。一方、三级キャッシュは主にシングルトンBeanにプロトタイプ(prototype)タイプの依存関係が存在する場合に使用されます。つまり、シングルトンBeanがプロトタイプBeanに依存している場合、三级キャッシュを介して依存関係のインスタンスを作成する必要があります。
注意:
- 2.6バージョンから、プロジェクトに循環依存が存在する場合、Spring Bootは起動を拒否します!
- コンストラクタの循環依存は解決できません。
注: この図では、早期に公開されるのはシングルトンファクトリーであり、二级キャッシュにはこのファクトリーから取得されたオブジェクトが保存されます。
注意:
- シングルトンBean:Spring Beanはデフォルトでシングルトンであり、Spring Bootコンテナ内で再利用されます。
- プロトタイプBean:このBeanが使用されるたびに、Springが新しく作成します(
@Scope(value = BeanDefinition.SCOPE_PROTOTYPE)アノテーションで宣言できます)。
Spring MVC
MVC
MVCはモデル(Model)、ビュー(View)、コントローラ(Controller)の略で、ソフトウェア設計の規範です。
- ビジネスロジック、データ、表示を分離してコードを整理する方法です。
- MVCの主な役割は、ビューとビジネスロジック間の双方向の結合を低減することです。
- MVCは設計パターンではなく、アーキテクチャパターンです。もちろん、異なるMVCには違いがあります。
- Model(モデル):データモデル。表示するデータを提供するため、データと振る舞いを含みます。領域モデルまたはJavaBeanコンポーネント(データと振る舞いを含む)と見なすことができます。しかし、現在は一般的に分離されています:Value Object(データDao)とサービス層(振る舞いService)。つまり、モデルはモデルデータのクエリとモデルデータの状態更新機能を提供します。データとビジネスを含みます。
- View(ビュー):モデルの表示を担当します。通常、ユーザーが見るユーザーインターフェース、クライアントが見たいものです。
- Controller(コントローラ):ユーザーリクエストを受け取り、モデルに処理を委譲します(状態変更)。処理が完了したら、返されたモデルデータをビューに返し、ビューが表示を担当します。つまり、コントローラは调度員(スケジューラ)の仕事をします。
概念
Spring MVCはSpring Frameworkの一部であり、Javaで実装された軽量なWebフレームワークです。SpringMVCは、シンプル、便利、学びやすく、Springと無缝集成(Spring IoCとAOPを使用)しています。使用しやすく、Restfulスタイルをサポートし、例外処理、ローカライゼーション、国際化、データ検証、型変換、インターセプタなどが可能です。
Spring MVCの9大コンポーネントの中で、リクエスト処理とレスポンスの核心コンポーネントは以下の通りです:
- HandlerMapping(ハンドラーマッピング):SpringMVCには多くのリクエストがあり、それぞれのリクエストにはハンドラーが必要です。HandlerMappingの役割は、リクエストに対応するハンドラーHandlerとインターセプタを見つけることです。
- HandlerAdapter(ハンドラーアダプタ):HandlerAdaptersが行うことは、固定のServlet処理メソッド呼び出しが柔軟なHandlerをどのように処理するかを決定することです。
- ViewResolver(ビューリゾルバ):ViewResolversの主な役割は、Stringタイプのビュー名とロケールをViewタイプのビューに解析することです。
この記事の一部は個人的な理解であり、参考までにご利用ください。