스프링19_AOP

charl hi·2022년 2월 7일
0

Spring

목록 보기
20/25

AOP

  • 관점 지향 프로그래밍

  • aspectJ 를 사용하기 위해 spring-aop 추가
    -> 그후 aspectJ 추가(이미 있음)

pom.xml

  • weaving : 완성된 코드에 내가 원하는 코드를 집어넣는 것
<org.aspectj-version>1.9.7</org.aspectj-version>
...
...
		<!-- spring-aop -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
				
		<!-- AspectJ -->
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>${org.aspectj-version}</version>
		</dependency>		
		
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>${org.aspectj-version}</version>
		</dependency>		
		


root-context.xml

->

	<!-- @Aspect 사용할 수 있도록 -->
	<aop:aspectj-autoproxy/>
	
	<!-- servlet-context 에서 이미 사용중?이기 때문에 false -->
	<context:component-scan base-package="com.kh.app24" use-default-filters="false">
		<context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/>
	</context:component-scan>	
	
  • 이러면 이제 @Asepct 를 사용한 클래스에 S가 붙는다!!



MyAspect

@EnableAspectJAutoProxy
@Component
@Aspect
@Slf4j
public class MyAspect {

	//advice, 조인포인트, 포인트컷
	//이 안에서 사용할 메소드를 advice라고 명명한다.
	
	//언제 : HomeController가 실행되기 전에 : @Before
	//대상 : "target(대상)"
	@Before("target(com.kh.app24.HomeController)")
	public void myAdvice01() {
		log.info("myAdvice01 called~~");
	}
	
}



원리?

  • 프록시 : HomeController를 감싸는 큰 네모가 프록시
  • 프록시 안에 myAdvice01()
  • home요청을 보내면 home으로 바로 가는 게 아니라 프록시로 감
  • ✨프록시가 요청을 대신 해줌 && 대신 그전(@Before)에 자기가 할 거 하고

1) 언제

  • @Before
  • @After : 에러가 나든 말든
  • @Around : before+after
  • @AfterReturning : ??
  • @AfterThrowing : 에러가 나면 aop 실행

2) 대상

  • ("target(대상)") : 대상에 클래스 또는 인터페이스 지정
  • within : 패키지 또는 클래스 지정
  • execution : 표현식(접근제한자 반환형 패키지명.클래스명.메소드명(매개변수))

@EnableAspectJAutoProxy
@Component
@Aspect
@Slf4j
public class MyAspect {

	//advice, 조인포인트, 포인트컷
	//이 안에서 사용할 메소드를 advice라고 명명한다.
	
	//언제 : HomeController가 실행되기 전에 : @Before
	//대상 : "target(대상)"
	@Before("target(com.kh.app24.HomeController)")
	public void myAdvice01() {
		log.info("Before =============");
	}
	
	@After("target(com.kh.app24.HomeController)")
	public void myAdvice02() {
		log.info("After ==============");
	}
	
}




My

MyController

@Controller
@RequestMapping("my")
@Slf4j
public class MyController {

	@Autowired
	private MyService service;
	
	
	@GetMapping("test")
	@ResponseBody
	public String test() {
		
		log.info("test method called...");
		service.test();
		
		return "test~~~";
	}
}


MyService

@Service
@Slf4j
public class MyService {

	@Autowired
	private MyDao dao;
	
	public void test() {
		log.info("test method called...");
		dao.test();
	}
	
}


MyDao

@Repository
@Slf4j
public class MyDao {

	@Autowired
	private SqlSession session;
	
	public void test() {
		log.info("test method called...");
	}

}




실습

MyService 전후에 하나씩 해보자

	@Before("target(com.kh.app24.aop.service.MyService)")
	public void myAdvice03() {
		log.info("MyService 클래스 실행 이전~~");
	}
	
	@After("target(com.kh.app24.aop.service.MyService)")
	public void myAdvice04() {
		long time = System.currentTimeMillis();
		log.info("현재시간(ms) ::: {}", time);
	}



@Around

	/* @Around(대상)
	 * 리턴타입 : Object
	 * 파라미터 : ProceedingJoinPoint
	 * 예외 : Throwable
	 * Before, After 둘다 간섭 가능
	 * */
	@Around("target(com.kh.app24.aop.service.MyService)")
	public Object myAdvice05(ProceedingJoinPoint jp) throws Throwable {
		
		//before
		long start = System.currentTimeMillis();
		
		//타겟 메소드 호출
		Object obj = jp.proceed();
		
		//after
		long end = System.currentTimeMillis();
		
		long elapse = end - start;
		log.info("elapse : {}", elapse);
		
		return obj;
	}
	



within

  • "within(대상)" : 대상에 패키지 또는 클래스 지정
//	@Around("target(com.kh.app24.aop.service.MyService)")
//	@Around("target(com.kh.app24.aop.dao.MyDao)")
	@Around("within(com.kh.app24.aop..*)")
//	@Around("within(com..*)")
	public Object myAdvice05(ProceedingJoinPoint jp) throws Throwable {
		
		System.out.println("elapse check start ==========com.kh.app24.aop..");
		
		//before
		long start = System.currentTimeMillis();
//		long start = System.nanoTime();
		
		//타겟 메소드 호출
		Object obj = jp.proceed();
		
		//after
		long end = System.currentTimeMillis();
		
		long elapse = end - start;
		log.info("elapse : {}", elapse);
		
		return obj;
	}
	



execution

  • "execution(대상)" : 대상에 표현식(접근제한자 반환형 패키지명.클래스명.메소드명(매개변수))

  • public : 생략 가능

  • 리턴타입에 * : 리턴타입 상관없으면

  • 매개변수에 * : 매개변수 1개 이상

  • 매개변수에 .. : 매개변수 0개 이상

1)

	@Around("execution(public void com.kh.app24.aop.dao.MyDao.test())")
	public Object myAdvice05(ProceedingJoinPoint jp) throws Throwable {
		
		System.out.println("elapse check start ==========com.kh.app24.aop..");
		
		//before
		long start = System.currentTimeMillis();
//		long start = System.nanoTime();
		
		//타겟 메소드 호출
		Object obj = jp.proceed();
		
		//after
		long end = System.currentTimeMillis();
		
		long elapse = end - start;
		log.info("elapse : {}", elapse);
		
		return obj;
	}



2)

//	@Around("execution(public void com.kh.app24.aop.dao.MyDao.test())")
	//public 은 생략 가능
	//리턴타입 상관없으면 *
	//매개변수에 * : 매개변수 1개 이상
	//매개변수에 .. : 매개변수 0개 이상
	//패키지명, 클래스명, 메소드명 : 표현식으로 처리 가능
//	@Around("execution(* com.kh.app24.aop.dao.MyDao.select*(..))")
//	@Around("execution(* com.kh.app24.aop.dao.MyDao.te*(..))")
//	@Around("execution(* com.kh.app24.aop.dao.MyDao.*st(..))")
//	@Around("execution(* com.kh.app24.aop.dao.*Dao.*(..))")
//	@Around("execution(* com.kh.app24..*.*(..))")
//	@Around("execution(* com..*Dao*.*(..))")
	@Around("execution(* com..*.*(..))")
	public Object myAdvice05(ProceedingJoinPoint jp) throws Throwable {
		
		System.out.println("elapse check start ==========com.kh.app24.aop..");
		
		//before
		long start = System.currentTimeMillis();
//		long start = System.nanoTime();
		
		//타겟 메소드 호출
		Object obj = jp.proceed();
		
		//after
		long end = System.currentTimeMillis();
		
		long elapse = end - start;
		log.info("elapse : {}", elapse);
		
		return obj;
	}
	

0개의 댓글