framework/spring AOP(관점지향)

[springAOP] 4. 스키마기반의 AOP 만들어 사용하기 | Advice클래스

jeri 2024. 7. 30. 11:44
반응형

01. DTO클래스

Student 클래스
package xyz.itwill07.aop;

import lombok.Data;

@Data
public class Student {
	private int num;
	private String name;
}

02. [핵심관심모듈] : DAO클래스 - 포함(의존)관계 : 부

(부모) StudentDAO 인터페이스
package xyz.itwill07.aop;

import java.util.List;

public interface StudentDAO {
	int insertStudent(Student student);
	Student selectStudent(int num);
	List<Student> studentList();
}
(자식) StudentDAOImpl 클래스
package xyz.itwill07.aop;

import java.util.List;

//핵심관심모듈(Core Concern Module) : 핵심관심코드만 이용하여 메소드를 작성한 클래스
//=> 핵심관심코드 : 데이타 처리를 위한 필수적인 명령
public class StudentDAOImpl implements StudentDAO{

	@Override
	public int insertStudent(Student student) {
		System.out.println("*** StudentDAOImpl 클래스의 insertStudent(Student student) 메소드 호출 ***");
		return 0;
	}
	@Override
	public Student selectStudent(int num) {
		System.out.println("*** StudentDAOImpl 클래스의 selectStudent(int num) 메소드 호출 ***");
		return null;
	}
	@Override
	public List<Student> selectstudentList() {
		System.out.println("*** StudentDAOImpl 클래스의 selectstudentList() 메소드 호출 ***");
		return null;
	}
}

03. [핵심관심모듈] : Service클래스 - 포함(의존)관계 : 주

(부모) StudentService 인터페이스
package xyz.itwill07.aop;

import java.util.List;

public interface StudentService {
	void addStudent(Student student);
	Student getStudent(int num);
	List<Student> getstudentList();

(자식) StudentServiceImpl 클래스
package xyz.itwill07.aop;

import java.util.List;

import lombok.Setter;

//핵심관심모듈
@Setter
public class StudentServiceImpl implements StudentService{
	private StudentDAO studentDAO;

	@Override
	public void addStudent(Student student) {
		System.out.println("*** StudentServiceImpl 클래스의 addStudent(Student student) 메소드 호출 ***");
		studentDAO.insertStudent(student);
	}
	@Override
	public Student getStudent(int num) {
		System.out.println("*** StudentServiceImpl 클래스의 getStudent(int num) 메소드 호출 ***");
		return studentDAO.selectStudent(num);
	}
	@Override
	public List<Student> getstudentList() {
		System.out.println("*** StudentServiceImpl 클래스의 getstudentList() 메소드 호출 ***");
		return studentDAO.selectstudentList();
	}
}

04. [횡단관심모듈] : Advice클래스

StudentAdvice 클래스
package xyz.itwill07.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

//횡단관심모듈(CrossCutting Concern Module) : 횡단관심코드만 이용하여 메소드를 작성한 클래스 - Advice 클래스
//=> 횡단관심코드 : 데이타 처리 명령을 제외한 보조적인 기능을 제공하는 명령
//=> 로그 처리, 보안(권한) 처리, 트렌젝션 처리, 예외 처리 등의 명령
public class StudentAdvice {
	private static final Logger logger = LoggerFactory.getLogger(StudentAdvice.class);


	
    //1.
	//타겟메소드의 명령 실행전에 삽입되어 실행될 명령을 작성한 메소드 - Before Advice 메소드
	// => JoinPoint : 핵심관심코드를 기준으로 횡단관심코드가 삽입되어 동작될 위치를 표현
	//타겟메소드(Target Method) : 핵심관심모듈의 메소드 중 PointCut 표현식으로 지정되어 횡단관심코드를
	// => PointCut 표현식 : 핵심관심모듈의 메소드 중 원하는 메소드만 지정하기 위한 언어
	public void beforeLog() {
		logger.info("[before]핵심관심코드 동작 전 삽입되어 실행될 횡단관심코드");
	}


	//2.
    //타겟메소드의 명령 실행전에 삽입되어 실행될 명령을 작성한 메소드 - Before Advice 메소드
	// => JoinPoint : 핵심관심코드를 기준으로 횡단관심코드가 삽입되어 동작될 위치를 표현
	//타겟메소드(Target Method) : 핵심관심모듈의 메소드 중 PointCut 표현식으로 지정되어 횡단관심코드를
	// => PointCut 표현식 : 핵심관심모듈의 메소드 중 원하는 메소드만 지정하기 위한 언어
	public void beforeLog() {
		logger.info("[before]핵심관심코드 동작 전 삽입되어 실행될 횡단관심코드");
	} 
    
    
    //3.
    //타겟메소드의 명령 실행후에 예외와 상관없이 무조건 삽입되어 실행될 명령을 작성한 메소드
	// => After Advice 메소드
	public void afterLog() {
		logger.info("[after]핵심관심코드 동작 후 무조건 삽입되어 실행될 횡단관심코드");
	}


    //4.
	//타겟메소드의 명령이 정상적으로 실행된 후에 삽입되어 실행될 명령을 작성한 메소드
	// => After Returning Advice 메소드
	public void afterReturningLog() {
		logger.info("[after-returning]핵심관심코드가 정삭적으로 동작된 후 삽입되어 실행될 횡단관심코드");
	}
    

	//5.
	//타겟메소드의 명령 실행시 예외가 발생된 경우에만 삽입되어 실행될 명령을 작성한 메소드
	// => After Throwing Advice 메소드
	public void afterThrowingLog() {
		logger.info("[after-throwing]핵심관심코드 동작시 예외가 발생된 경우 삽입되어 실행될 횡단관심코드");
	}
    
    
    //6.
	//타겟메소드의 명령이 실행 전과 후에 삽입되어 실행될 명령을 작성한 메소드
	// => Around Advice 메소드
	public void aroundLog(ProceedingJoinPoint joinPoint) throws Throwable {
		logger.info("[around]핵심관심코드 동작 전 삽입되어 실행될 횡단관심코드");
		joinPoint.proceed();//타겟메소드 호출 - 핵심관심코드 실행
		logger.info("[around]핵심관심코드 동작 후 삽입되어 실행될 횡단관심코드");
	}


}

 

 

 

05. 💖Spring Bean Configuration File

[07-1.aop.xml]
  • AopProxy 클래스 - Aspect역할하기 위해서는??? : AOP 네임스페이스 추가하기

<?xml version="1.0" encoding="UTF-8"?>
<!-- AOP 네임스페이스가 추가되었음-->
<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>"
	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.xsd>">



	<!-- 핵심관심모듈로 작성된 클래스를 Spring Bean으로 등록 -->
	<!-- StudentDAOImpl 클래스 Spring Bean으로 등록 -->
	<bean class="xyz.itwill07.aop.StudentDAOImpl" id="studentDAO"/>
	<!-- StudentServiceImpl 클래스 Spring Bean으로 등록 => 클래스 내 studentDAO 필드에 StudentDAOImpl 객체 의존성 주입 -->
	<bean class="xyz.itwill07.aop.StudentServiceImpl" id="studentService">
		<property name="studentDAO" ref="studentDAO"/>
	</bean>

	<!-- 횡단관심모듈로 작성된 클래스를 Spring Bean으로 등록 -->
	<bean class="xyz.itwill07.aop.StudentAdvice" id="studentAdvice"/>
    
    
    
    

	<!-- Spring AOP(Aspect Oriented Programming - 관점 지향 프로그래밍) : AspectJ 컴파일러에
	의해 프로그램 실행 시 핵심관심코드와 횡단관심코드가 결합(Weaving)되어 동작되기 위한 기능 제공 -->
	<!-- Spring AOP 기능을 사용하기 위해서는 aspectjrt 라이브러리와 aspectjweaver 라이브러리가
	프로젝트에 빌드 처리 => 메이븐 사용 : pom.xml 수정 -->

	<!-- => aspectjrt 라이브러리 : runtime - 실행할 때만 사용-->
	<!-- => aspectjweaver 라이브러리 : weaving - 결과물을 합쳐줌 -->
    <!-- => 즉, 개발자가 핵심관심코드와 횡단관심코드를 직접 만들어 사용하기 위해서는
	코드를 합치는 작업(weaving)을 해야하므로 반드시 aspectjweaver 라이브러리 필요 -->

	<!-- Spring Bean Configuration File에서 Spring AOP 기능을 구현하고자 할 경우
	AOP 네임스페이스를 추가하여 spring-aop.xsd 파일의 엘리먼트로 설정  -->
	<!-- config: Spring AOP 관련 설정을 제공하기 위한 엘리먼트 -->
	<aop:config>
		<!-- aspect : 핵심관심코드에 횡단관심코드를 원하는 위치(JoinPoint)에 삽입되어 실행
		되도록 설정하기 위한 엘리먼트 -->
		<!-- => 횡단관심코드가 삽입될 위치(JoinPoint)를 하위 엘리먼트로 설정 -->
		<!-- => 하위 엘리먼트 : before, after, after-returning, after-throwing, around -->
		<!-- ref 속성 : 횡단관심모듈로 작성된 Advice 클래스에 대한 Spring Bean의 식별자
		(beanName)를 속성값으로 설정 -->
      	<!-- studentAdvice의 클래스의 메소드를 제공받아 십입처리할게요! -->
		<aop:aspect ref="studentAdvice">
<!--🖤[JoinPoint] aop:before - 핵심관심코드 실행 전-->
			<!-- before : 핵심관심코드 실행 전에 횡단관심코드를 삽입하여 실행되도록 설정하기 위한 엘리먼트 -->
			<!-- method 속성 : Advice 클래스의 메소드명(횡단관심코드가 작성된 메소드)을 속성값으로 설정 -->
			<!-- pointcut 속성 : 핵심관심모듈의 메소드 중 횡단관심모듈의 메소드가 삽입될 타겟메소드를 지정하기 위한 PointCut 표현식을 속성값으로 설정 -->
			<!-- => [execution 함수] 또는 [within 함수]에 검색패턴문자와 연산자를 사용하여 타겟메소드 지정 -->
			<!-- => PointCut 표현식으로 사용 가능한 [검색패턴문자] : ..(0개 이상), *(1개 이상), ?(0개 또는 1개) -->
			<!-- => PointCut 표현식으로 사용 가능한 [연산자] : !(Not), &&(And), ||(Or) -->

			<!-- [execution] 함수를 이용하여 타겟메소드를 지정하는 방법 -->
			<!-- => execution 함수에 메소드의 머릿부를 표현하여 타겟메소드 지정 -->
			<!-- 형식)execution([접근지정자] 반환형 [패키지.클래스.]메소드명(자료형,자료형,...) -->
			<!-- => 클래스 대신 인터페이스 사용 가능 - 인터페이스를 상속받은 모든 자식클래스 표현 -->
			<!-- => 반환형 또는 매개변수의 자료형이 클래스(인터페이스)인 경우 패키지를 포함하여 표현 -->
			<!-- => 반환형: 없음, 메소드명:핵심관심모듈 중 addStudent, 매개변수명: xyz.itwill07.aop.Student -->

			<!-- <aop:before method="beforeLog" pointcut="execution(void addStudent(xyz.itwill07.aop.Student))"/> -->
			<!-- <aop:before method="beforeLog" pointcut="execution(* *(..))"/> --> <!--모든 반환형, 모든 메소드, 모든 매개변수(0개이상) -->
			<!-- <aop:before method="beforeLog" pointcut="execution(* xyz.itwill07.aop..*(..))"/> --><!--xyz.itwill07.aop 내에 있는(0개이상) 모든 메소드-->
			<!-- <aop:before method="beforeLog" pointcut="execution(* xyz.itwill07.aop.StudentDAO.*(..))"/> --><!--xyz.itwill07.aop.StudentDAO 내에 있는(0개이상) 모든 메소드-->
			<!-- <aop:before method="beforeLog" pointcut="execution(xyz.itwill07.aop.Student *(..))"/> --><!-- 반환형이xyz.itwill07.aop.Student인 모든 메소드-->
			<!-- <aop:before method="beforeLog" pointcut="execution(* get*(..))"/> --><!-- get으로 시작하는 메소드 -->
			<!-- <aop:before method="beforeLog" pointcut="execution(* *(int)) or execution(int *(..))"/> --><!-- 매개변수가 int 거나 반환형이 int인 경우 -->

			<!-- [within] 함수를 이용하여 타겟메소드를 지정하는 방법 : 광범위한 타겟 메소드 지정하고 싶을 때 이용 -->
			<!-- => Spring Bean으로 등록된 클래스(핵심관심모듈)의 모든 메소드를 타겟메소드로 지정 -->
			<!-- 형식)within(패키지.클래스명) -->
			<!-- => 클래스 대신 인터페이스 사용 불가능 -->

			<!-- <aop:before method="beforeLog" pointcut="within(xyz.itwill07.aop.StudentDAOImpl)"/> -->
			<!-- <aop:before method="beforeLog" pointcut="within(xyz.itwill07.aop.StudentServiceImpl)"/> -->
<!--🧡[pointcut] aop:pointcut - 어떤 클래스의 어떤 메소드에 널을까?-->
			<!-- pointcut : 핵심관심모듈의 메소드 중 횡단관심모듈의 메소드가 삽입된 타겟
			메소드를 지정하기 위한 엘리먼트 -->
			<!-- => 자주 사용되는 PointCut 표현식을 저장하여 타겟메소드에 대한 정보 제공 : mybatis의 resultMap과 비슷한 기능
			<!-- => [aspect 엘리먼트 선언 전]에 작성하거나 [aspect 엘리먼트의 하위 엘리먼트]로 작성 -->
			<!-- => [aspect 엘리먼트의 하위 엘리먼트]로 작성하면 그 내부에서만 이용 가능 -->
			<!-- expression 속성 : 타겟메소드를 지정하기 위한 PointCut 표현식을 속성값으로 설정 -->
			<!-- id 속성 : PointCut 표현식을 구분하기 위한 식별자를 속성값으로 설정 -->
			<aop:pointcut expression="execution(* xyz.itwill07..StudentDAO.*(..))" id="studentDAOPointCut"/>
			<aop:pointcut expression="execution(* xyz.itwill07..StudentService.*(..))" id="studentServicePointCut"/>
			<!-- pointcut-ref 속성 : pointcut 엘리먼트의 식별자를 속성값으로 설정 -->
			<!-- <aop:before method="beforeLog" pointcut-ref="studentDAOPointCut"/> -->
			<aop:before method="beforeLog" pointcut-ref="studentServicePointCut"/>
<!--🖤[JoinPoint] aop:after - 핵심관심코드 실행 후 예외 발생과 상관없이 무조건-->
			<!-- after : 핵심관심코드 실행 후 예외 발생과 상관없이 무조건 횡단관심코드를 삽입
			하여 실행되도록 설정하기 위한 엘리먼트 -->
			<aop:after method="afterLog" pointcut-ref="studentServicePointCut"/>
<!--🖤[JoinPoint] aop:after-returning - 핵심관심코드가 정상적으로 실행된 후-->
			<!-- after-returning : 핵심관심코드가 정상적으로 실행된 후 횡단관심코드를 삽입하여
			실행되도록 설정하기 위한 엘리먼트 -->
			<aop:after-returning method="afterReturningLog" pointcut-ref="studentServicePointCut"/>
<!--🖤[JoinPoint] aop:after-throwing - 핵심관심코드 실행시 예외가 발생된 후-->
			<!-- after-throwing : 핵심관심코드 실행시 예외가 발생된 후 횡단관심코드를 삽입하여
			실행되도록 설정하기 위한 엘리먼트 -->
			<aop:after-throwing method="afterThrowingLog" pointcut-ref="studentServicePointCut"/>
<!--🖤[JoinPoint] aop:around - 핵심관심코드 실행 전과 후-->
			<!-- around : 핵심관심코드 실행 전과 후에 횡단관심코드를 삽입하여 실행되도록 설정하기
			위한 엘리먼트 -->
			<aop:around method="aroundLog" pointcut-ref="studentServicePointCut"/>
		</aop:aspect>
	</aop:config>
</beans>

06. 실행프로그램

StudentAopApp
package xyz.itwill07.aop;

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

public class StudentAopApp {
	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("07-1_aop.xml");
		StudentService service = context.getBean("studentService",StudentService.class);
		System.out.println("======================================================");
		service.addStudent(null);
		System.out.println("======================================================");
		service.getStudent(0);
		System.out.println("======================================================");
		service.getstudentList();
		System.out.println("======================================================");
		((ClassPathXmlApplicationContext)context).close();
	}
}
반응형