Springとは何か
SpringはオープンソースのJava EEアプリケーションフレームワークであり、主にBeanのライフサイクルを管理する軽量コンテナとして機能します。ここでいう「Bean」とは、Springコンテナによって管理されるJavaオブジェクトのことです。これらのオブジェクトはクラスのインスタンスであり、IoC(制御の反転)コンテナにより生成・管理されます。開発者は直接オブジェクトをnewで生成せず、代わりにSpringが依存関係を解決して適切なタイミングで提供します。
Springの利点
- モジュール間の結合度を低く(ローカプリング)、内部の凝集度を高く(ハイコヒージョン)保てる
- アノテーションまたはXMLによる宣言的トランザクション管理が可能で、ビジネスロジックとトランザクション処理を分離できる
- ユニットテストや統合テストが容易
- 他の優れたフレームワーク(例:MyBatis、Hibernate)との統合がシンプル
- JDBCやJMSなどの複雑なJava EE APIの利用を簡素化
Springの3層アーキテクチャにおける役割
Springはプレゼンテーション層、ビジネスロジック層、データアクセス層すべてに対応しており、全体を統合的に管理できます。
- Web層:Spring MVCを使用してHTTPリクエストを処理
- Service層:Beanの管理および宣言的トランザクションの制御
- DAO層:JdbcTemplateやORMサポート(JPA、Hibernate連携)を提供
制御の反転(IoC)と依存性の注入(DI)
IoCの基本原理
IoCでは、オブジェクトの生成とそのライフサイクル管理をアプリケーションコードから切り離し、Springコンテナに委譲します。コンテナは設定ファイルまたはアノテーションに基づいてBeanを生成し、内部のマップ構造に格納します。キーはBean ID、値は生成されたインスタンスです。
Beanの取得方法
// 方法1: Bean IDを指定
UserService userService = (UserService) context.getBean("userService");
// 方法2: 型のみを指定(同型のBeanが一つである必要あり)
UserService userService = context.getBean(UserService.class);
// 方法3: IDと型を両方指定
UserService userService = context.getBean("userService", UserService.class);
Beanの生成方式
- デフォルトコンストラクタ:
Class.forName().newInstance()を使用 - 静的ファクトリメソッド:
<bean id="calendar" class="CalendarFactory" factory-method="create"/> - インスタンスファクトリ:
<bean id="factory" class="CalendarFactory"/> <bean id="calendar" factory-bean="factory" factory-method="getInstance"/> - Spring専用ファクトリ(FactoryBean):
public class CalendarSpringFactory implements FactoryBean<Calendar> { public Calendar getObject() { return Calendar.getInstance(); } public Class<?> getObjectType() { return Calendar.class; } }
依存性の注入(DI)
Setter経由での注入
プロパティにsetterがある場合、<property>タグで値を注入できます。
<bean id="user" class="User">
<property name="name" value="田中"/>
<property name="age" value="30"/>
<property name="roles">
<list>
<value>ADMIN</value>
<value>USER</value>
</list>
</property>
</bean>
参照による注入
<bean id="userService" class="UserService">
<property name="userDao" ref="userDao"/>
</bean>
<bean id="userDao" class="UserDaoImpl"/>
自動ワイヤリング(autowire)
byType:型で自動解決byName:プロパティ名とBean IDが一致するものを注入
Pネームスペースの使用
<bean id="user" class="User" p:name="佐藤" p:age="25"/>
コンストラクタ注入
<bean id="userService" class="UserService">
<constructor-arg index="0" ref="userDao"/>
<constructor-arg name="timeout" value="3000"/>
</bean>
アノテーションによるIoC/DI
コンポーネントスキャンの設定
<context:component-scan base-package="com.example.service"/>
主要なアノテーション
@Component:汎用的なSpringコンポーネント@Service:サービス層のBean@Repository:DAO層のBean@Controller:Web層のコントローラ@Value:プリミティブ値や文字列を注入
@Service
public class UserService {
@Value("${app.timeout:5000}")
private long timeout;
@Autowired
private UserDao userDao;
}
AOP(アスペクト指向プログラミング)
基本概念
- Aspect:横断的関心事を実装するクラス
- Advice:特定のタイミングで実行される処理(前処理、後処理など)
- Pointcut:どのメソッドに対してAOPを適用するかを定義する式
- Join Point:メソッド呼び出しのような、AOPが適用可能なポイント
- Target:実際に処理を行うオブジェクト
- Weaving:アスペクトをターゲットオブジェクトに組み込むこと
プロキシ方式
- JDK動的プロキシ:インターフェースに基づいたプロキシ生成。対象クラスがインターフェースを実装している必要がある
- CGLIBプロキシ:サブクラスを作成してプロキシ化。インターフェース不要
XMLによるAOP設定
<aop:config>
<aop:pointcut id="serviceMethod" expression="execution(* com.example.service.*.*(..))"/>
<aop:aspect ref="loggingAspect">
<aop:before method="logBefore" pointcut-ref="serviceMethod"/>
</aop:aspect>
</aop:config>
アノテーションによるAOP
@Component
@Aspect
public class LoggingAspect {
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceLayer() {}
@Before("serviceLayer()")
public void logBefore(JoinPoint jp) {
System.out.println("メソッド開始: " + jp.getSignature());
}
@Around("serviceLayer()")
public Object measureTime(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
Object result = pjp.proceed();
System.out.println("実行時間: " + (System.currentTimeMillis() - start) + "ms");
return result;
}
}
Spring Bootと例外処理
グローバル例外ハンドリング
@RestControllerAdvice(basePackages = "com.example.controller")
public class GlobalExceptionHandler {
@ExceptionHandler(BusinessException.class)
public ResponseEntity<String> handleBusinessException(BusinessException e) {
return ResponseEntity.badRequest().body(e.getMessage());
}
}
この仕組みにより、コントローラ内で発生したカスタム例外が自動的にキャッチされ、適切なHTTPレスポンスとして返されます。Spring MVCは例外の型を検出し、対応する@ExceptionHandlerメソッドに引数として渡すことで、一元的なエラーハンドリングが実現できます。