Springフレームワークにおける共通フィールド自動設定手法

技術要素:列挙型、カスタムアノテーション、AOP、リフレクション

実装背景:データ挿入・更新操作時に時刻や操作者情報を毎回手動設定するのは非効率的なため、自動化手法を実装します。

実装手順:

  1. 操作種別を識別するAutoFillアノテーションを定義
  2. アスペクトクラスでメソッド実行前のフィールド自動設定を実装
  3. リフレクションを用いた動的フィールド設定

アノテーション定義例:

package com.example.annotation;

import com.example.enums.DbOperationType;
import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {
    DbOperationType operationType();
}

// 操作種別列挙体
package com.example.enums;

public enum DbOperationType {
    UPDATE,
    INSERT
}

アスペクト実装例:

package com.example.aspect;

import com.example.annotation.AutoFill;
import com.example.enums.DbOperationType;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.time.LocalDateTime;

@Aspect
@Component
public class FieldAutoFillAspect {

    @Before("@annotation(autoFill)")
    public void populateFields(JoinPoint jp, AutoFill autoFill) {
        Object[] params = jp.getArgs();
        if (params.length == 0) return;
        
        Object targetObject = params[0];
        DbOperationType operation = autoFill.operationType();
        LocalDateTime currentTime = LocalDateTime.now();
        Long operatorId = getCurrentUserId();

        try {
            if (operation == DbOperationType.INSERT) {
                invokeSetter(targetObject, "setCreateTime", currentTime);
                invokeSetter(targetObject, "setCreateUser", operatorId);
            }
            if (operation == DbOperationType.INSERT || operation == DbOperationType.UPDATE) {
                invokeSetter(targetObject, "setUpdateTime", currentTime);
                invokeSetter(targetObject, "setUpdateUser", operatorId);
            }
        } catch (ReflectiveOperationException e) {
            handleReflectionError(e);
        }
    }

    private void invokeSetter(Object target, String methodName, Object value) throws ReflectiveOperationException {
        Method setter = target.getClass().getDeclaredMethod(methodName, value.getClass());
        setter.invoke(target, value);
    }
    
    private Long getCurrentUserId() {
        // 実装依存のユーザー取得ロジック
        return 1L;
    }
    
    private void handleReflectionError(Exception e) {
        // エラーハンドリング実装
    }
}

タグ: SpringAOP Javaアノテーション リフレクション DB操作自動化

7月27日 21:47 投稿