AOP (Aspect Oriented Programming)

지종권(JiJongKwon)·2024년 4월 19일
3
post-thumbnail

Spring 핵심 ?

spring의 핵심하면 떠오르는 그림이 있을 거 같다.

난 밑의 그림이 떠오른다.

삼각형 !!

여기에서 가장 중요한 특성을 뽑으라고 하면

난 IOC/DI 와 AOP라고 생각한다.

IOC : 제어 역전 원칙
주체가 사용자에게 있는 게 아닌, 스프링에게 있다.

즉, 난 내 비즈니스 로직만 신경쓰면 된다는 뜻이다.

DI : https://velog.io/@jijongkwon/DI-Dependency-Injection

DI는 위 링크를 참고하자 !

AOP

그럼 AOP는 뭘까 ??

코드 예시

@Configuration
public class HeroesConfig {
	
	@Bean
	public IronMan ironMan() {
		return new IronMan("토니 스타크");
	}
	
	@Bean
	public Hulk hulk() {
		return new Hulk();
	}

	@Bean
	public HulkBuster hulkBuster() {
		return new HulkBuster();
	}
	
	@Bean
	public Avengers avengers() {
		Avengers a = new Avengers(ironMan(), hulk());
		a.setHulk(hulk()); // aop 개입
		a.setName("뉴욕");
		return a;
	}
}

config 파일에서 보면

conponent scan으로 bean을 싱글톤으로 등록한다.

근데 뭔가 이상하지 않은가 ?

	@Bean
	public Avengers avengers() {
		Avengers a = new Avengers(ironMan(), hulk());
		a.setHulk(hulk()); // aop 개입
		a.setName("뉴욕");
		return a;
	}

여기에서 setHulk 부분에서 새로운 객체가 생성되어야 하지 않은가 ?

근데 container는 싱글톤으로 관리하기 때문에 새로운 객체를 생성하지 않는다.

근데 난 그런 설정을 한 적이 없다!!!

그럼 어떻게 ?

그게 바로 AOP를 적용한 것이다.

객체를 생성하기 전에 container에 빈이 있는지 확인하고 생성할지 안할지 결정하는 것!

그럼 AOP에 대해서 좀 더 알아보자

AOP 개요

AOP 영어로 풀어 쓰면 Aspect Oriented Programming

이 말 그대로 관점 지향 프로그래밍이다 !!

그럼 관점 지향 프로그래밍은 뭘까 ???

우리는 핵심 로직과 공통 로직이 있다.


핵심 로직은 ?

핵심은 말 그대로 서비스를 동작하기 위해 필요한 로직이다.


그럼 공통 로직은 ?

내가 무언 갈 하기전에 필요한 설정등을 해주는 공통 로직이 있다.


위에서 예시를 든 객체를 생성하기 전에 contatiner에서 빈을 확인한다는 지
, 로그인을 예로 들면 session에 로그인 정보가 있는지 없는지 확인해서 로직을 처리한다는지
등등 다양한 예시를 들 수 있다.

그런 것을 분리해서 알아서 관리해준다면 ?

우리는 핵심 로직에만 집중 할 수 있다!!

Spring AOP

스프링은 우리에게 필요한 공통 로직등을 이미 미리 설정되어 있다.

그래서 우리가 핵심 로직에만 집중 할 수 있는 것이다.

대표적으로

  1. 트랜잭션 관리 ( 커밋, 롤백 자동으로 처리 )
  2. 로깅 ( 스프링 실행하면 보이는 info, warn, error 이런거 많이 봤죠 ? )
  3. 보안 ( @PreAuthorize 등 메서드 실행 전에 권한 체크 )
  4. 예외처리 ( @AfterThrowing 등 예외처리 할 수 있죠 ? )

등등 이 있다.

Spring AOP 예시

구구단으로 예시를 들어보자

Maven 프로젝트이고, 단순한 테스트이다.

TimesTablesBean


@Component
@Slf4j
public class TimesTablesBean {
	
	// 구구단의 합을 반환
	public int getMultiSum(int num) {
		log.debug("getmultiSum 호출됨 = {}", num);
		int sum = 0;
		for(int i = 1; i < 10; i++) {
			sum += num * i;
		}
		return sum;
	}
}

예를 들어 3이 들어오면 3단에 관한 모든 모든 값의 합을 반환하는 코드이다.

AdAsepct

@Aspect
@Component
@Slf4j
public class AdviceTypeAspect {
	
	// 메서드 호출 시 전달받은 파라미터는 1 ~ 9 사이
	@Before("execution(int com..*.*CheckNum(..))")
	public void checkNum(JoinPoint joinPoint) {
		Object[] args = joinPoint.getArgs();
		
		List<Integer> numbers = new ArrayList<>();
		
		// 숫자 담기
		for(Object arg : args) {
			numbers.add(Integer.parseInt(arg.toString()));
		}
		
		// 범위체크
		for(int number : numbers) {
			if(number < 1 || number > 9) {
				throw new RuntimeException("구구단의 범위 초과");
			}
		}
	}
}

@Before("execution(int com..*.*CheckNum(..))")

여기에서 com 밑에 패키지에 모든 클래스에서 CheckNum문자가 뒤에 포함된 모든 메서드에 관하여 실행하기 전에

위의 코드를 실행시켜 범위를 확인할 수 있는 코드이다.

이 코드가 제대로 동작하는 지 확인해 보자

TestCode


	@Test
	public void getMultiSumTest() {
		int num = 3;
		
		// 정상흐름
		int result = sbean.getMultiSumCheckNum(num);
		assertEquals(result, 135);
		
		// 예외발생 ( 1 ~ 9 사이의 값이 아닌 다른 값 )
		assertThrows(RuntimeException.class, () ->{
			sbean.getMultiSumCheckNum(10);
		});
	}

결과는

성공 ~~


참고 자료
https://velog.io/@j_user0719/Spring-%ED%95%B5%EC%8B%AC-%EA%B5%AC%EC%A1%B0-POJOPSA

3개의 댓글

comment-user-thumbnail
2024년 4월 19일

아저씨 오타가 너무 많아요.. 코드에 심취한 나머지 코드는 멋지지만, 글이 잘 안읽혀집니다. . . 😢

답글 달기
comment-user-thumbnail
2024년 4월 24일

결과는... 성공~

답글 달기
comment-user-thumbnail
2024년 7월 14일

글에서 목소리가 들려요

답글 달기

관련 채용 정보