웹/Spring, Django

[Spring]DI/AOP

stubborngastropod 2023. 5. 4. 14:23
728x90

인터페이스

클래스에 포함하는 메서드의 구체적인 내용을 작성하지 않고 상수와 메서드 타입만 정의한 것. 다른 클래스에서 구현하는 것을 전제로 만들어짐

의존성 주입(DI)

의존하는 부분을 외부에서 주입하는 것(Dependency Injection)

'사용하는 객체' 클래스에서 '사용되는 객체' 클래스에 의존하거나 인터페이스에 의존할 수 있음. 스프링에서는 DI 컨테이너가 임의의 클래스를 인스턴스로 생성해 클래스에 주입

인터페이스를 이용해 의존성을 만듦 - 인스턴스를 명시적으로 생성(new)하지 않음 - 어노테이션을 클래스에 부여 - 스프링이 인스턴스 생성(시작 시 모든 패키지를 스캔하는 컴포넌트 스캔을 통해) - 인스턴스를 이용하는 곳에 어노테이션 부여(@Autowired)

인스턴스 생성 어노테이션: @Component, @Controller(애플리케이션 레이어), @Service(도메인 레이어), @Repository(인프라 레이어)

// interface
package com.example.demo.chapter03.used;

public interface Greet {
    void greeting();
}
// class
package com.example.demo.chapter03.used;

import org.springframework.stereotype.Component;

@Component
public class MorningGreet implements Greet {
    @Override
    public void greeting() {
        System.out.println("-------------");
        System.out.println("Good morning.");
        System.out.println("-------------");
    }
}
// class
package com.example.demo.chapter03.used;

import org.springframework.stereotype.Component;

@Component
public class EveningGreet implements Greet {
    @Override
    public void greeting() {
        System.out.println("-------------");
        System.out.println("Good evening.");
        System.out.println("-------------");
    }
}
// application
package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import com.example.demo.chapter03.used.Greet;

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args)
                .getBean(DemoApplication.class).execute();
    }
    @Autowired
    Greet greet;

    private void execute() {
        greet.greeting();
    }
}

관점 지향 프로그래밍(AOP)

실현해야 할 기능인 중심적 관심사와 본질적이진 않지만 필요한 기능인 횡단적 관심사 두 가지 요소로 구성

한 클래스에서 다른 클래스의 메서드를 호출할 때 메서드에서 횡단적 관심사를 따로 분리해 애스펙트와 어드바이스를 만듦. 실제 메서드를 호출할 때 자동생성된 인터셉터 AOP 프록시가 처리를 가로채고 메서드 및 어드바이스 호출을 제어

어드바이스의 종류: @Before(중심적 관심사 실행 이전), @AfterReturning(중심적 관심사 정상 종료 이후), @AfterThrowing(중심적 관심사의 예외 이후), @After(중심적 관심사 실행 후), @Around(중심적 관심사 호출 전후)

// aop class
package com.example.demo.chapter03.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;

@Aspect
@Component
public class SampleAspect {
    @Before("execution(* com.example.demo.chapter03.used.*Greet.*(..))")
    public void beforeAdvice(JoinPoint joinPoint) {
        System.out.println("===== Before Advice =====");
        System.out.println(new SimpleDateFormat("yyyy/MM/dd").format(new Date()));
        System.out.println(String.format("method:%s", joinPoint.getSignature().getName()));
    }

    @After("execution(* com.example.demo.chapter03.used.*Greet.*(..))")
    public void afterAdvice(JoinPoint joinPoint) {
        System.out.println("===== After Advice =====");
        System.out.println(new SimpleDateFormat("yyyy/MM/dd").format(new Date()));
        System.out.println(String.format("method:%s", joinPoint.getSignature().getName()));
    }

    @Around("execution(* com.example.demo.chapter03.used.*Greet.*(..))")
    public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("===== Around Advice =====");
        System.out.println("Before process");
        Object result = joinPoint.proceed();
        System.out.println("After process");
        return result;
    }
}
728x90