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; }
📃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(); }
📃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; } }
📃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(); }
📃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>
📃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
<logger name="xyz.itwill07.aop"> <level value="info"/> </logger>