Spring 복습 AOP에 대해서...

충찌·2022년 1월 8일
0

Spring-remind

목록 보기
3/4
post-thumbnail

AOP

AOP(Aspect Oriented Programming, 관점 지향 프로그램)
: 핵심관심사(Core Concerns)에 대한 관점과 횡단관심사(Cross-cutting Concerns)에 대한 관점들로 프로그램을 분해해 객체지향방식에서 추구하는 모듈을 효과적으로 지원하도록 하는 프로그래밍 기법

AOP의 특징

  1. 모듈화
    : 횡단 관심사를 포괄적이고 체계적으로 모듈화
  2. 캡슐화
    : 횡단 관심사는 Aspect라는 새로운 단위로 캡슐화하여 모듈화가 이루어짐
  3. 단순화
    : 핵심 모듈은 더 이상 횡단 관심사의 모듈을 직접 포함하지 않으며 횡단관심사의 모든 복잡성은 Aspect로 분리

AOP의 개념도 및 주요 요소

1.AOP의 개념도
핵심과 횡단의 분리를 이루고, AOP가 핵심 관심 모듈의 코드를 직접 건드리지 않고 필요한 기능을 작동하는 데는 weaving 또는 cross-cutting 작업 필요

2.AOP의 주요 요소

스프링에서 AOP 구현 방법

-- proxy를 이용

Spring AOP Advice 종류

before과 after을 통합하는 aroud가 많이 쓰임

AOP 구현 예시(1)

Around advice, xml
핵심관심사 : Student, Worker
횡단관심사 : LogAop

<Student.java>
package och06_aop1;

public class Student {
	private String name;
	private int age;
	private int gradeNum;
	private int classNum;
	
	public void getStudentInfo() {
		System.out.println("이름 :"+getName());
		System.out.println("나이 :"+getAge());
		System.out.println("학년 :"+getGradeNum());
		System.out.println("반 :"+getClassNum());
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public int getGradeNum() {
		return gradeNum;
	}

	public void setGradeNum(int gradeNum) {
		this.gradeNum = gradeNum;
	}

	public int getClassNum() {
		return classNum;
	}

	public void setClassNum(int classNum) {
		this.classNum = classNum;
	}
	
}



<Worker.java>
package och06_aop1;

public class Worker {
	private String name;
	private int age;
	private String job;
	
	public void getWorkerInfo() {
		System.out.println("이름 :"+getName());
		System.out.println("나이 :"+getAge());
		System.out.println("직업 :"+getJob());
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getJob() {
		return job;
	}

	public void setJob(String job) {
		this.job = job;
	}
}



<LogAop.java>
package och06_aop1;

import org.aspectj.lang.ProceedingJoinPoint;

public class LogAop {
	//Around Advice에서 사용할 공통기능 메서드는, 대부분 파라미터로 전달받은 ProceedingJoinPoint의 proceed() 메서드만 호출
	//Proxy
	public Object loggerAop(ProceedingJoinPoint joinpoint) throws Throwable{ //핵심관심사와 횡단관심사의 결합 위치를 정해주는 거가 조인포인트 
		String signatureStr = joinpoint.getSignature().toString();
		
		//핵심관심사의 수행 메소드
		System.out.println(signatureStr +" is start.");
		long st = System.currentTimeMillis();
		
		try {
			//핵심관심사 수행
			Object obj = joinpoint.proceed();
			return obj;
		}finally {
			long et = System.currentTimeMillis();
			System.out.println(signatureStr+ " is finished.");
			System.out.println(signatureStr +" 경과시간: "+(et-st));
		}
		
	}
}


<MainClass.java>
package och06_aop1;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

public class MainClass {
	public static void main(String[] args) {
		AbstractApplicationContext ctx = new GenericXmlApplicationContext("classpath:applicationCTX1.xml");
		
		Student student = ctx.getBean("student", Student.class);
		student.getStudentInfo();
		
		Worker worker = ctx.getBean("worker", Worker.class);
		worker.getWorkerInfo();
		ctx.close();
	}

}


<applicationCTX1.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-3.2.xsd">


	<bean id="logAop" class="och06_aop1.LogAop"/>
	
	<aop:config>
		<aop:aspect id="logger1" ref="logAop">
			<aop:pointcut id="pub1" expression="within(och06_aop1.S*)"/>
			<aop:around pointcut-ref="pub1" method="loggerAop"/>
		</aop:aspect>
	</aop:config>
	
	<bean id="student" class="och06_aop1.Student">
		<property name="name" value="연개소문"/>
		<property name="age" value="50"/>
		<property name="gradeNum" value="3"/>
		<property name="classNum" value="5"/>
	</bean>
	<bean id="worker" class="och06_aop1.Worker">
		<property name="name" value="이순신"/>
		<property name="age" value="35"/>
		<property name="job" value="개발자"/>
	</bean>

</beans>


<결과>
void och06_aop1.Student.getStudentInfo() is start.
이름 :연개소문
나이 :50
학년 :3
반 :5
void och06_aop1.Student.getStudentInfo() is finished.
void och06_aop1.Student.getStudentInfo() 경과시간: 20
이름 :이순신
나이 :35
직업 :개발자

<aop:pointcut id="pub1" expression="within(och06_aop1.S*)"/>
pointcut에서 och06_aop1.S*로 해서 Worker는 횡단관심사의 기능이 삽입되지 않아 결과가 핵심관심사에 구현된 기능만 나타났다.

AOP구현 예시(2)

advice 종류 모두 사용, xml
aop2.buz패키지 : Student, Worker
aop2패키지 : LogAop, MainClass

<Student.java>
package aop2.buz;

public class Student {
	private String name;
	private int age;
	private int gradeNum;
	private int classNum;
	
	public Student() {
		System.out.println("Student 생성자");
	}
	
	public void getStudentInfo() {
		System.out.println("이름 :"+getName());
		System.out.println("나이 :"+getAge());
		System.out.println("학년 :"+getGradeNum());
		System.out.println("반 :"+getClassNum());
	
		//System.out.println(10/0);
		try {
			System.out.println(10/0);
		}catch(Exception e) {
			System.out.println("Student getStudentInfo +e.getMessage()->"+ e.getMessage());
		}
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public int getGradeNum() {
		return gradeNum;
	}

	public void setGradeNum(int gradeNum) {
		this.gradeNum = gradeNum;
	}

	public int getClassNum() {
		return classNum;
	}

	public void setClassNum(int classNum) {
		this.classNum = classNum;
	}
	
}



<Worker.java>
package aop2.buz;

public class Worker {
	private String name;
	private int age;
	private String job;
	
	public void getWorkerInfo() {
		System.out.println("이름 :"+getName());
		System.out.println("나이 :"+getAge());
		System.out.println("직업 :"+getJob());
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getJob() {
		return job;
	}

	public void setJob(String job) {
		this.job = job;
	}
}



<LogAop.java>
package aop2;

import org.aspectj.lang.ProceedingJoinPoint;

public class LogAop {
	//Around Advice에서 사용할 공통기능 메서드는, 대부분 파라미터로 전달받은 ProceedingJoinPoint의 proceed() 메서드만 호출
	//Proxy
	public Object loggerAop(ProceedingJoinPoint joinpoint) throws Throwable{ //핵심관심사와 횡단관심사의 결합 위치를 정해주는 거가 조인포인트 
		String signatureStr = joinpoint.getSignature().toString();
		
		//핵심관심사의 수행 메소드
		System.out.println(signatureStr +" is start."); //beforeAdvice랑 같은 때에 발생하므로 beforeAdvice대신 그냥 around로 써줌 
		long st = System.currentTimeMillis();
		
		try {
			//핵심관심사 수행
			Object obj = joinpoint.proceed();
			return obj;
		}finally {
			long et = System.currentTimeMillis();
			System.out.println(signatureStr+ " is finished.");
			System.out.println(signatureStr +" 경과시간: "+(et-st));
		}
		
	}
	
	public void beforeAdvice() {
		System.out.println("beforeAdvice()");
	}
	public void afterReturningAdvice() {//around에 다 포함함.
		System.out.println("afterReturningAdvice()");
	}
	public void afterThrowingAdvice() {
		System.out.println("afterThrowingAdvice()");
	}
	public void afterAdvice() {
		System.out.println("afterAdvice()");
	}
	
}



<MainClass.java>
package aop2;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

import aop2.buz.Student;
import aop2.buz.Worker;

public class MainClass {
	public static void main(String[] args) {
		AbstractApplicationContext ctx = new GenericXmlApplicationContext("classpath:applicationCTX2.xml");
		
		Student student = ctx.getBean("student", Student.class);
		student.getStudentInfo();
		
		Worker worker = ctx.getBean("worker", Worker.class);
		worker.getWorkerInfo();
		ctx.close();
	}
}



<applicationCTX2.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-3.2.xsd">


	<bean id="logAop" class="aop2.LogAop"/>
	
	<aop:config>
		<aop:aspect id="logger" ref="logAop">
			<aop:pointcut id="pub" expression="within(aop2.buz.*)"/>
			<aop:around pointcut-ref="pub" method="loggerAop"/>
		</aop:aspect>
		<aop:aspect id="logger" ref="logAop">
			<aop:pointcut id="pub1" expression="within(aop2.buz.*)"/>
			<aop:before pointcut-ref="pub1" method="beforeAdvice"/>
		</aop:aspect>
		<aop:aspect id="logger" ref="logAop">
			<aop:pointcut id="pub" expression="within(aop2.buz.*)"/>
			<aop:after-returning pointcut-ref="pub" method="afterReturningAdvice"/>
		</aop:aspect>
		<aop:aspect id="logger" ref="logAop">
			<aop:pointcut id="pub" expression="within(aop2.buz.*)"/>
			<aop:after-throwing pointcut-ref="pub" method="afterThrowingAdvice"/>
		</aop:aspect>
		<aop:aspect id="logger" ref="logAop">
			<aop:pointcut id="pub" expression="within(aop2.buz.*)"/>
			<aop:after pointcut-ref="pub" method="afterAdvice"/>
		</aop:aspect>
	</aop:config>

	<bean id="student" class="aop2.buz.Student">
		<property name="name" value="김춘추"/>
		<property name="age" value="10"/>
		<property name="gradeNum" value="3"/>
		<property name="classNum" value="5"/>
	</bean>
	<bean id="worker" class="aop2.buz.Worker">
		<property name="name" value="김춘추"/>
		<property name="age" value="10"/>
		<property name="job" value="35"/>
	</bean>

</beans>



<결과>
Student 생성자
void aop2.buz.Student.getStudentInfo() is start.
beforeAdvice()
이름 :김춘추
나이 :10
학년 :3
반 :5
Student getStudentInfo +e.getMessage()->/ by zero
afterAdvice()
afterReturningAdvice()
void aop2.buz.Student.getStudentInfo() is finished.
void aop2.buz.Student.getStudentInfo() 경과시간: 21
void aop2.buz.Worker.getWorkerInfo() is start.
beforeAdvice()
이름 :김춘추
나이 :10
직업 :35
afterAdvice()
afterReturningAdvice()
void aop2.buz.Worker.getWorkerInfo() is finished.
void aop2.buz.Worker.getWorkerInfo() 경과시간: 15

AOP 구현 예시(3)

around, before, after advice, Annotation

<Student.java>
package aop3.buz;

public class Student {
	private String name;
	private int age;
	private int gradeNum;
	private int classNum;
	
	public void getStudentInfo() {
		System.out.println("이름 :"+getName());
		System.out.println("나이 :"+getAge());
		System.out.println("학년 :"+getGradeNum());
		System.out.println("반 :"+getClassNum());
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public int getGradeNum() {
		return gradeNum;
	}

	public void setGradeNum(int gradeNum) {
		this.gradeNum = gradeNum;
	}

	public int getClassNum() {
		return classNum;
	}

	public void setClassNum(int classNum) {
		this.classNum = classNum;
	}
	
}



<Worker.java>
package aop3.buz;

public class Worker {
	private String name;
	private int age;
	private String job;
	
	public void getWorkerInfo() {
		System.out.println("이름 :"+getName());
		System.out.println("나이 :"+getAge());
		System.out.println("직업 :"+getJob());
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getJob() {
		return job;
	}

	public void setJob(String job) {
		this.job = job;
	}
}



<LogAop.java>
package aop3;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class LogAop {
	@Pointcut("within(aop3.buz.*)") //aop3.buz패키지안에있는 모든 메소드
	private void pointcutMethod() {
		
	}
	@Around("pointcutMethod()")
	public Object loggerAop(ProceedingJoinPoint joinPoint) throws Throwable {
		String signatureStr = joinPoint.getSignature().toString();
		System.out.println(signatureStr+" is start.");
		long st = System.currentTimeMillis();
		
		try {
			Object obj = joinPoint.proceed();
			return obj;
		}finally {
			long et = System.currentTimeMillis();
			System.out.println(signatureStr+" is finished.");
			System.out.println(signatureStr +" 경과시간: "+(et-st));
		}
	}
	@Before("within(aop3.buz.*)")
	public void beforeAdvice() {
		System.out.println("@beforeAdvice()");
	}
	@After("within(aop3.buz.*)")
	public void afterAdvice() {
		System.out.println("@afterAdvice()");
	}
}



<MainClass.java>
package aop3;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

import aop3.buz.Student;

public class MainClass {

	public static void main(String[] args) {
		AbstractApplicationContext ctx = new GenericXmlApplicationContext("classpath:applicationCTX3.xml");
		
		Student student = ctx.getBean("student", Student.class);
		student.getStudentInfo();
		
		
		ctx.close();
	}

}



<applicationCTX3.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-3.2.xsd">

	<aop:aspectj-autoproxy/>
	<bean id="logAop" class="aop3.LogAop"/>

	<bean id="student" class="aop3.buz.Student">
		<property name="name" value="홍길동"/>
		<property name="age" value="10"/>
		<property name="gradeNum" value="3"/>
		<property name="classNum" value="5"/>
	</bean>

</beans>



<결과>
void aop3.buz.Student.getStudentInfo() is start.
@beforeAdvice()
이름 :홍길동
나이 :10
학년 :3
반 :5
void aop3.buz.Student.getStudentInfo() is finished.
void aop3.buz.Student.getStudentInfo() 경과시간: 20
@afterAdvice()

정리

  1. xml의 경우
<bean id="logAop" class="och06_aop1.LogAop"/>
	
<aop:config>
  <aop:aspect id="logger1" ref="logAop">
      <aop:pointcut id="pub1" expression="within(och06_aop1.*)"/>
      <aop:around pointcut-ref="pub1" method="loggerAop"/>
  </aop:aspect>
</aop:config>

--> loggerAop 메소드를 och06_aop1패키지 내에 있는 모든 핵심관심사에 끼어 넣을 거고 id는 logger1으로 하며 LogAop클래스를 참조한다.

  1. Annotation의 경우
profile
벨로그? 난 켈로그

0개의 댓글