티스토리 뷰

Spring

Maven - Spring Project : AOP

˙ᵕ˙ 2020. 10. 1. 00:14
<AOP>
관점지향프로그래밍
핵심기능과 공통기능을 각각의 코드로 구현한 후 필요한 곳에서 적절하게
조합해서 완성된 코드로 실행되도록 하는 프로그래밍 기법

[용어]
1. core concern (핵심기능) - 비지니스로직(주업무)
2. cross-cutting concern(공통기능) - 부가기능(보조업무)
   => 로깅, 트랜잭션처리, 자원처리, 보안처리 ...
3. code
   core concern이 구현된 객체
4. advice
   cross-cutting concern이 구현된 객체
   
5. joinPoint
   code와 advice를 연결할 수 있도록 도와주는 설정정보 
   즉, advice를 적용할 지점에 대한 정보(메소드 호출, 필드값을 변경, ..)
6. Point-cut
   joinPoint의 부분집합으로 실제 advice가 적용되는 joinpoint를 의미
   aop를 적용할 조건을 의미 - 표현으로 정의
   [형식]
   execution(패키지정보 클래스정보 메소드정보 매개변정보)
	 * : 모든 것을 의미
	 .. : 매개변수가 있거나 없거나
	 execution(public void set*(..)) : 리턴 타입이 void이고 파라미터가 0개이상 
	 execution(* encore.bigdataShop.board.*.*())
	 	: encore.bigdataShop.board 패키지의 파라미터가 없는 모든 메소드
	 execution(* encore.bigdataShop.board..*.*())
	 	: encore.bigdataShop.board와 하위 패키지의 모든 클래스의
	 	파라미터가 없는 모든 메소드
   ex) UserDAO클래스의 get으로 시작하는 메소드가 호출되기 전에 공통모듈을 실행
7. weaving
   code, advice, point-cut을 조합해서 어플리케이션이 적절하게 실행될 수 있도록

AOP

  • spring-aop, spring-aspects 라이브러리 다운

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>4.2.4.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
	<version>4.2.4.RELEASE</version>
</dependency>

< UserVO.java >

package aop.exam;

public class UserVO {
	private String id;
	private String password;
	private String name;
	private String role;
	
	// setter,getter
}

< AOPClient.java>

package aop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AOPClient {
	public static void main(String[] args) {
		ApplicationContext factory
		  = new  ClassPathXmlApplicationContext("config/aopbean.xml");
		DAO dao  = (DAO)factory.getBean("dao");
		UserVO vo =  new UserVO();
		dao.getUser(vo);
		dao.getUserList(vo);
		dao.addUser(vo);
	}
}

< DAO.java >

package aop;

import java.util.ArrayList;

public interface DAO {
	public ArrayList<UserVO> getUserList(UserVO vo);
	public UserVO getUser(UserVO vo);
	public void addUser(UserVO vo);
	public void deleteUser(UserVO vo);
}

< LogAdvice.java >

package aop;

// 모든 클래스에 적용할 공통모듈 - 비지니스 로직 외적인 부분이지만 
//							늘 많은 메소드의 호출 전 후로 사용되는 기능
public class LogAdvice {
	public void log() {
		System.out.println("=========로그기록=========");
	}
}

< UserDAO.java >

package aop;

import java.util.ArrayList;

public class UserDAO implements DAO {
	public ArrayList<UserVO> getUserList(UserVO vo) {
		System.out.println("########################");
		System.out.println("##### getUserList() 호출... #####");
		System.out.println("########################");
		return null;
	}
	public UserVO getUser(UserVO vo) {
		System.out.println("########################");
		System.out.println("##### getUser() 호출... #####");
		System.out.println("########################");
		return null;
	}
	public void addUser(UserVO vo) {
		System.out.println("########################");
		System.out.println("##### addUser() 호출... #####");
		System.out.println("########################");
	}	
	public void deleteUser(UserVO vo) {
		System.out.println("########################");
		System.out.println("##### deleteUser() 호출... #####");
		System.out.println("########################");
	}
}
  • 설정파일 생성

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">

	<!-- 나의 비지니스 로직(핵심모듈) -->
	<bean id="dao" class="aop.UserDAO"/>
	
	<!-- 공통 관심사항이 정의된 빈 -->
	<bean id="logAdvice" class="aop.LogAdvice"/>
	
	<!-- AOP적용 -->
	<aop:config>
		<!-- aop패키지에 UserDAO클래스의 get으로 시작하는 메소드가
			호출되기 전 로그를 기록할 수 있도록 조건을 정의
			조건을 표현식으로  -->
		<aop:pointcut expression="execution(* aop.*.get*(..))" 
			id="mygetPointcut"/>
		<!-- 공통관심사를 어느 시점에 적용할 것인지 즉, pointcut으로 등록된
			조건을 만족하는 모든 메소드들이 실행되기 전에 공통관심모듈이
			실행되도록 설정 -->
		<!-- ref속성은 공통관심모듈 즉, advice빈을 의미 -->
		<aop:aspect id="aop01" ref="logAdvice">
			<aop:before method="log" pointcut-ref="mygetPointcut"/>
		</aop:aspect>
	</aop:config>
	
</beans>
  • get 메소드에서만 표시된다.

  • 결과 (get 메소드 실행 전에 LogAdvice의 log 메소드가 실행)

  • 예제

[aop.exam패키지 작성]
	aop패키지의 모든 클래스를 copy
	LogAdvice는 제외

[공통관심모듈]
- CalcAdvice작성
- 랜덤수를 발생시켜서 멤버변수에 셋팅 하는 메소드(setNum) 
- 1부터 랜덤수까지의 합을 계산하는 calc메소드 정의

[설정파일작성] - aopconfig02
- aop.exam 패키지의 모든 클래스의 모든 메소드 적용
- 공통관심모듈, 핵심모듈, 설정 정의
- setNum 은 메소드 호출 전에 실행
- calc는 메소드 호출 후에 실행

< CalcAdvice.java >

package aop.exam;

import java.util.Random;

public class CalcAdvice {
	int num = 0;
	
	public void setNum() {
		Random ran = new Random();
		num = ran.nextInt(100) + 1;
		System.out.println("1~100사이 랜덤 수 발생 : " +num);
	}
	public void calc() {
		int sum = 0;
		for(int i=1; i<=num; i++) {
			sum += i;
		}
		System.out.println("1부터 "+ num + "까지의 합 : " + sum);
	}
}

< aopconfig02.xml >

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">

	<bean id="dao" class="aop.exam.UserDAO"/>
	<bean id="calcadvice" class="aop.exam.CalcAdvice"/>
	
	<aop:config>
		<aop:pointcut expression="execution(* aop.exam.*.*(..))" id="setNum"/>
		<aop:pointcut expression="execution(* aop.exam.*.*(..))" id="calc"/>
		
		<aop:aspect id="aop01" ref="calcadvice">
			<aop:before method="setNum" pointcut-ref="setNum"/>
			<aop:after method="calc" pointcut-ref="calc"/>
		</aop:aspect>
	</aop:config>
</beans>
  • AOPClient.java 실행

어노테이션 사용하기

  • annotation 설정 파일 설정

< annoaop.xml >

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">

	<context:component-scan base-package="aop"/>
	
	<!-- aop를 어노테이션으로 사용하는 경우 aop작업을 수행하는 proxy가 자동으로 
		감지해서 aop등록된 것을 확인하고 동작할 수 있도록 등록 -->
	<aop:aspectj-autoproxy/>
</beans>

< logAdvice.java >

package aop.anno;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Service;

// 모든 클래스에 적용할 공통모듈 - 비지니스 로직 외적인 부분이지만 
//							늘 많은 메소드의 호출 전 후로 사용되는 기능

@Service
// aop를 적용하는 advice임을 나타내주어야 한다.
@Aspect
public class LogAdvice {
	// 어노테이션으로 포인트 컷을 정의하는 경우 메소드를 반드시 한 개 정의해서
	// 메소드 위에 패턴을 정의
	// - 메소드 위에 @Pointcut이라는 어노테이션 선언
	// - 아래와 같이 pointcut을 정의하면 메소드명을 pointcut으로 인식
	@Pointcut("execution(* aop.anno.*.get*(..))")
	public void mylogPointcut() {}
	
	// 위에서 정의한 pointcut을 적용(메소드 실행 후)
	// ()를 포함한 메소드명이 포인트컷명
	@After("mylogPointcut()")
	public void log() {
		System.out.println("=========로그기록=========");
	}
}
  • AOPClient.java 실행

  • get 메소드 실행시에만 log 메소드 실행

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함