공통 기능을 비즈니스 로직에서 분리하는 방법과, 실무에서 암복호화 솔루션이 WAS에 통합되는 구조를 이해합니다.
@Transactional, @Cacheable, 스프링 시큐리티 권한 체크가 모두 AOP 기반| 키워드 | 의미 | 예시 |
|---|---|---|
| Aspect | 공통 기능을 모듈화한 단위 | 암복호화 처리 모듈 |
| Advice | 실제 수행되는 공통 기능 코드 | 저장 전 암호화, 조회 후 복호화 |
| JoinPoint | 공통 기능을 적용할 수 있는 지점 | 메서드 호출 시점 |
| Pointcut | 실제 적용할 대상을 지정하는 조건 | DAO 계층 메서드 |
| Weaving | Aspect를 대상 코드에 결합하는 과정 | aspectjweaver가 담당 |
| 어노테이션 | 역할 |
|---|---|
@Aspect | 해당 클래스를 Aspect(공통 기능 모듈)로 선언 |
@Pointcut | 공통 기능을 적용할 대상 메서드 지정 |
@Before | 대상 메서드 실행 전에 수행 (예: 저장 전 암호화) |
@After | 대상 메서드 실행 후에 수행 (성공/실패 무관) |
@AfterReturning | 대상 메서드가 정상 반환된 후 수행 (예: 조회 후 복호화) |
@AfterThrowing | 대상 메서드에서 예외 발생 시 수행 (예: 오류 로깅) |
@Around | 대상 메서드 실행 전후를 모두 제어 — 가장 강력, 암복호화에 주로 사용 |
@EnableAspectJAutoProxy | 스프링에서 AOP 프록시 자동 생성 활성화 (설정 클래스에 선언) |
설정 클래스에 한 번만 선언하면 스프링이 프록시를 자동 생성합니다. (Spring Boot는 기본 활성화)
@Configuration @EnableAspectJAutoProxy public class AopConfig { // 별도 내용 없이 선언만으로 AOP 활성화 }
Pointcut을 메서드로 정의해두면 여러 Advice에서 이름으로 재사용할 수 있습니다.
@Aspect @Component public class DaoSecurityAspect { // com.example.dao 하위 모든 메서드를 대상으로 지정 @Pointcut("execution(* com.example.dao..*(..))") public void daoLayer() {} }
@Before("daoLayer()") public void encryptParams(JoinPoint jp) { // jp.getArgs()로 파라미터 접근 가능 System.out.println("[Before] " + jp.getSignature().getName() + " 호출 전 — 파라미터 암호화"); }
returning 속성으로 반환값을 파라미터로 받아 후처리할 수 있습니다.
@AfterReturning(pointcut = "daoLayer()", returning = "result") public void decryptResult(JoinPoint jp, Object result) { System.out.println("[AfterReturning] 조회 결과 복호화: " + result); }
throwing 속성으로 발생한 예외 객체를 받을 수 있습니다.
@AfterThrowing(pointcut = "daoLayer()", throwing = "ex") public void logError(JoinPoint jp, Exception ex) { System.out.println("[AfterThrowing] " + jp.getSignature().getName() + " 예외: " + ex.getMessage()); }
@After("daoLayer()") public void cleanup(JoinPoint jp) { System.out.println("[After] " + jp.getSignature().getName() + " 종료"); }
pjp.proceed() 호출 전이 "실행 전", 이후가 "실행 후"입니다. 반환값을 반드시 return 해야 합니다.
@Around("daoLayer()") public Object measureAndSecure(ProceedingJoinPoint pjp) throws Throwable { long start = System.currentTimeMillis(); // (실행 전) 파라미터 암호화 등 전처리 Object result = pjp.proceed(); // 실제 대상 메서드 실행 // (실행 후) 결과 복호화 등 후처리 long elapsed = System.currentTimeMillis() - start; System.out.println("[Around] 수행시간: " + elapsed + "ms"); return result; // 반환값을 돌려주지 않으면 호출자가 null을 받음! }
@Transactional, @Cacheable도 같은 원리로 만들어진 것// 1. 커스텀 어노테이션 정의 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Encrypt {} // 2. Aspect에서 어노테이션 기준으로 적용 @Aspect @Component public class EncryptAspect { @Around("@annotation(com.example.annotation.Encrypt)") public Object encrypt(ProceedingJoinPoint pjp) throws Throwable { // 암복호화 처리 return pjp.proceed(); } } // 3. 필요한 메서드에만 선언 @Encrypt public void saveUser(User user) { ... }
@Encrypt 암복호화 · @LogExecutionTime 수행시간 측정 · @Retry 재시도 · @CheckAuth 권한 체크 · @Masking 개인정보 마스킹| 라이브러리 | 역할 |
|---|---|
aspectjweaver.jar | AOP 위빙을 수행하는 오픈소스 런타임 라이브러리 (Eclipse Foundation) |
securedbagent.jar | DB 암복호화 상용 솔루션 에이전트 — Java WAS에 통합되어 암복호화 수행 |