AOP(Aspect Oriented Programming, 관점 지향 프로그램)
: 핵심관심사(Core Concerns)에 대한 관점과 횡단관심사(Cross-cutting Concerns)에 대한 관점들로 프로그램을 분해해 객체지향방식에서 추구하는 모듈을 효과적으로 지원하도록 하는 프로그래밍 기법
1.AOP의 개념도
핵심과 횡단의 분리를 이루고, AOP가 핵심 관심 모듈의 코드를 직접 건드리지 않고 필요한 기능을 작동하는 데는 weaving 또는 cross-cutting 작업 필요
2.AOP의 주요 요소
-- proxy를 이용
before과 after을 통합하는 aroud가 많이 쓰임
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는 횡단관심사의 기능이 삽입되지 않아 결과가 핵심관심사에 구현된 기능만 나타났다.
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
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()
<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클래스를 참조한다.