Springフレームワークの核心概念と実装手法

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メソッドに引数として渡すことで、一元的なエラーハンドリングが実現できます。

タグ: Spring IoC DI AOP アノテーション

6月9日 20:40 投稿