[Spring 7-3] AOP 기술 및 용어 설명-2

임승현·2023년 2월 16일

Spring

목록 보기
20/46

src/main/java 폴더에 xyz.itwill07.aop 패키지 생성

🌈클래스 생성

📃Student.java

※ xyz.itwill07.aop 패키지에 Student.java 클래스 생성

package xyz.itwill07.aop;
//
import lombok.Data;
//
@Data//Setter,Getter를 이걸로 만듬
public class Student {
	private int num;
	private String name;
}

🌈DAO 인터페이스 생성

📃StudentDAO.java

※ xyz.itwill07.aop 패키지에 StudentDAO.java 인터페이스 생성

package xyz.itwill07.aop;
//
import java.util.List;
//
public interface StudentDAO {
	//메소드 생성
	int insertStudent(Student student);
	Student selectStudent(int num);
	List<Student> selectStudentList();
}

🌈Impl 클래스 생성(핵심관심모듈)

📃StudentDAOImpl.java

※ xyz.itwill07.aop 패키지에 StudentDAOImpl.java 클래스 생성

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() {
		// TODO Auto-generated method stub
		return null;
	}
}

🌈Service 인터페이스 생성

📃StudentService.java

※ xyz.itwill07.aop 패키지에 StudentService.java 인터페이스 생성

package xyz.itwill07.aop;
//
import java.util.List;
//
public interface StudentService {
	//메소드 생성
	void addStudent(Student student);
	Student getStudent(int num);
	List<Student> getStudentList();
}

🌈Impl 클래스 생성

📃StudentServiceImpl.java

※ xyz.itwill07.aop 패키지에 StudentServiceImpl.java 클래스 생성

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() 메소드 호출 ***");
		throw new RuntimeException();//인위적 예외 발생
		//return studentDAO.selectStudentList();
	}
}

🌈프로그램 생성

📃StudentAopApp.java

※ xyz.itwill07.aop 패키지에 StudentAopApp.java 클래스 생성

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();
	}
}

🌈환경설정파일 생성

Namespaces 추가(aop)

📃07-1_aop.xml

※ src/main/resources 폴더에 07-1_aop.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"
	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으로 등록 -->
	<bean class="xyz.itwill07.aop.StudentDAOImpl" id="studentDAO"/>
	<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 -->
	<!-- Spring Bean Configuration File에서 Spring AOP 기능을 구현하고자 할 경우 AOP 네임스페이스를 추가하여 spring-aop.xsd 파일의 엘리먼트로 설정 -->
	<!-- ================================================================================ -->
	<!-- config : Spring AOP 관련 설정을 제공하기 위한 엘리먼트 -->
	<aop:config>
		<!-- aspect : 핵심관심코드에 횡단관심코드를 원하는 위치(Join Point)에 삽입되어 실행되도록 설정하기 위한 엘리먼트 -->
		<!-- → 횡단관심코드가 삽일될 위치(Join Point)를 하위 엘리먼트로 설정 -->
		<!-- → before, after, after-returning, after-throwing, around -->
		<!-- ref 속성 : 횡단관심모듈로 작성된 Advice 클래스의 Spring Bean의 식별자(beanName)를 속성값으로 설정 -->
		<aop:aspect ref="studentAdvice">
			<!-- before : 핵심관심코드 실행 전에 횡단관심코드를 삽입하여 실행되도록 설정하기 위한 엘리먼트 -->
			<!-- method 속성 : Advice 클래스의 메소드명(횡단관심코드가 작성된 메소드)을 속성값으로 설정 -->
			<!-- pointcut 속성 : 핵심관심 모듈의 메소드 중 횡단관심모듈의 메소드가 삽입될 타겟메소드를 지정하기 위한 PointCut 표현식을 속성값으로 설정 -->
			<!-- → execution 함수 또는 within 함수에 검색 패턴 문자와 연산자를 사용하여 타겟메소드 지정 -->
			<!-- → PointCut 표현식으로 사용 가능한 검색패턴문자 : ..(0개 이상), *(1개 이상), ?(0개 또는 1개) -->
			<!-- → PointCut 표현식으로 사용 가능한 연산자 : !(Not),&&(And),||(Or) -->
			<!--                                                                   -->
			<!-- execution 함수를 이용하여 타겟메소드를 지정하는 방법 -->
			<!-- → execution 함수에 메소드의 머릿부를 표현하여 타겟메소드 지정 -->
			<!-- 형식) execution([접근지정자] 반환형 [패키지.클래스.]메소드명(자료형,자료형,...) -->
			<!-- → 클래스 대신 인터페이스 사용 가능 - 인터페이스를 상속받은 모든 자식클래스 표현 -->
			<!-- → 반환형 또는 매개변수의 자료형이 클래스(인터페이스)인 경우 패키지를 포함하여 표현 -->
			<!-- <aop:before method="beforeLog" pointcut="execution(void addStudent(xyz.itwill07.aop.Student))"/> -->		
			<!-- <aop:before method="beforeLog" pointcut="execution(* *(..))"/> -->		
			<!-- <aop:before method="beforeLog" pointcut="execution(* xyz.itwill07.aop..*(..))"/> -->		
			<!-- <aop:before method="beforeLog" pointcut="execution(* xyz.itwill07.aop.StudentDAO.*(..))"/> -->
			<!-- <aop:before method="beforeLog" pointcut="execution(xyz.itwill07.aop.Student *(..))"/> -->
			<!-- <aop:before method="beforeLog" pointcut="execution(* get*(..))"/> -->
			<!-- <aop:before method="beforeLog" pointcut="execution(* *(int)) or execution(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 : 핵심관심모듈의 메소드 중 횡단관심모듈의 메소드가 삽입된 타겟
			메소드를 지정하기 위한 엘리먼트 -->
			<!-- → 자주 사용되는 PointCut 표현식을 저장하여 타겟메소드에 대한 정보 제공 -->
			<!-- → 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"/>
			<!--                                                                   -->
			<!-- after : 핵심관심코드 실행 후 예외 발생과 상관없이 무조건 횡단관심코드를 삽입 하여 실행되도록 설정하기 위한 엘리먼트 -->
			<aop:after method="afterLog" pointcut-ref="studentServicePointCut"/>
			<!--                                                                   -->
			<!-- after-returning : 핵심관심코드가 정상적으로 실행된 후 횡단관심코드를 삽입하여 실행되도록 설정하기 위한 엘리먼트 -->
			<aop:after-returning method="afterReturningLog" pointcut-ref="studentServicePointCut"/>
			<!--                                                                   -->
			<!-- after-throwing : 핵심관심코드 실행시 예외가 발생된 후 횡단관심코드를 삽입하여 실행되도록 설정하기 위한 엘리먼트 -->
			<aop:after-throwing method="afterThrowingLog" pointcut-ref="studentServicePointCut"/>
			<!--                                                                   -->
			<!-- around : 핵심관심코드 실행 전과 후에 횡단관심코드를 삽입하여 실행되도록 설정하기위한 엘리먼트 -->
			<aop:around method="aroundLog" pointcut-ref="studentServicePointCut"/>
		</aop:aspect>
	</aop:config>
</beans>

🌈Advice클래스 생성

📃StudentAdvice.java

※ xyz.itwill07.aop 패키지에 StudentAdvice.java 클래스 생성

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);
	//
	//타켓메소드의 명령 실행전에 삽입되어 실행될 명령을 작성한 메소드 - Before Advice 메소드
	//→ JoinPoint : 핵심관심코드를 기준으로 횡단관심코드가 삽입되어 동작될 위치를 표현
	//타켓메소드(Target Method) : 핵심관심모듈의 메소드 중 PointCut 표현식으로 지정된 메소드
	//→ PointCut 표현식 : 핵심관심모듈의 메소드 중 원하는 메소드만 지정하기 위한 언어
	public void beforeLog() {
		logger.info("[before]핵심관심코드 동작 전 삽입되어 실행될 횡단관심코드");
	}
	//
	//타겟메소드의 명령 실행후에 예외와 상관없이 무조건 삽입되어 실행될 명령을 작성한 메소드
	//→ After Advice 메소드
	public void afterLog() {
		logger.info("[after]핵심관심코드 동작 후 무조건 삽입되어 실행될 횡단관심코드");
	}
	//
	//타겟메소드의 명령이 정상적으로 실행된 후에 삽입되어 실행될 명령을 작성한 메소드
	//→ After Returning Advice 메소드
	public void afterReturningLog() {
		logger.info("[after-returning]핵심관심코드가 정삭적으로 동작된 후 삽입되어 실행될 횡단관심코드");
	}
	//
	//타겟메소드의 명령 실행시 예외가 발생된 경우에만 삽입되어 실행될 명령을 작성한 메소드
	//→ After Throwing Advice 메소드
	public void afterThrowingLog() {
		logger.info("[after-throwing]핵심관심코드 동작시 예외가 발생된 경우 삽입되어 실행될 횡단관심코드");
	}
	//
	//타겟메소드의 명령이 실행 전과 후에 삽입되어 실행될 명령을 작성한 메소드
	//→ Around Advice 메소드
	public void aroundLog(ProceedingJoinPoint joinPoint) throws Throwable {
		logger.info("[around]핵심관심코드 동작 전 삽입되어 실행될 횡단관심코드");
		joinPoint.proceed();//타겟메소드 호출 - 핵심관심코드 실행 
		logger.info("[around]핵심관심코드 동작 후 삽입되어 실행될 횡단관심코드");
	}
}

🌈메이븐 추가

📃pom.xml

<!-- AspectJ -->
<!-- → AspectJ로 생성된 결과물(핵심관심코드+횡단관심코드)을 실행하기 위한 라이브러리  -->
<dependency>
	<groupId>org.aspectj</groupId>
	<artifactId>aspectjrt</artifactId>
	<version>${org.aspectj-version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<!-- AspectJ를 사용하여 핵심관심코드와 횡단관심코드가 결합된 결과물을 생성하기 위한 라이브러리 -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>${org.aspectj-version}</version>
    <scope>runtime</scope>
</dependency>

🌈log4j.xml 추가

📃log4j.xml

<logger name="xyz.itwill07.aop">
	<level value="info"/>
</logger>

0개의 댓글