어느 덧 추석이 다가오네요!
코로나19로 인해 가족이 모이는 것도
다소 조심스러운 부분이 있는데요
아무튼 학습을 진행하겠습니다
프로그램을 만들다 보면
공통적인 기능이 많이 발생하게 됩니다
자바에서 이러한 공통 기능을
모든 모듈(Module)에 적용하기 위해
상속을 이용하지만 몇 가지 한계가 있습니다
우선 자바에서 다중 상속이 불가하다는 점입니다
또 기능 구현 부분에 핵심 기능 코드와
공통 기능 코드가 섞여 있어 효율성이 떨어집니다
그래서 AOP 등판!
AOP는 공통 기능을 핵심 기능과 분리하고
공통 기능 중에서 핵심 기능에
적용하고자 하는 부분에 적용합니다
아래는 AOP의 용어를 정리한 것입니다
용어 | 설명 |
Aspect | - 공통 기능 |
Advice | - Aspect의 기능 자체 <aop:before> : 메소드 실행 전에 advice실행 <aop:after-returning> : 정상적으로 메소드 실행 후에 advice실행 <aop:after-throwing> : 메소드 실행중 exception 발생시 advice실행 <aop:after> : 메소드 실행중 exception 이 발생하여도 advice실행 <aop:around> : 메서드 실행 전/후 및 exception 발생시 advice실행 |
Jointpoint | - Advice를 적용해야 되는 부분(method) |
Pointcut | - Jointpoint의 부분으로 실제로 Advice가 적용된 부분 |
Weaving | - Advice를 핵심 기능에 적용 하는 행위 |
스프링에서는 아래의 그림과 같이
proxy를 이용해서 AOP를 구현하는데요
XML 스키마 혹은 @Aspect 어노테이션 기반 방식이 있습니다
우선 두 방식 모두 pom.xml 파일에
아래의 코드를 추가해야합니다~
<!-- AOP -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
아래의 코드는 XML 스키마 기반
AOP 구현 방식입니다
1. applicationCTX.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="com.example.demo.LogAop" />
<aop:config>
<aop:aspect id="logger" ref="logAop">
<aop:pointcut id="publicM" expression="within(com.example.demo.*)" />
<aop:around pointcut-ref="publicM" method="loggerAop" />
</aop:aspect>
</aop:config>
<bean id="student" class="com.example.demo.Student" >
<property name="name" value="GuruSa" />
<property name="age" value="10" />
<property name="gradeNum" value="3" />
<property name="classNum" value="5" />
</bean>
<bean id="worker" class="com.example.demo.Worker" >
<property name="name" value="BuruSa" />
<property name="age" value="35" />
<property name="job" value="developer" />
</bean>
</beans>
2. Student.java
package com.example.demo;
public class Student {
private String name;
private int age;
private int gradeNum;
private int classNum;
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;
}
public void getStudentInfo() {
System.out.println("이름 : " + getName());
System.out.println("나이 : " + getAge());
System.out.println("학년 : " + getGradeNum());
System.out.println("반 : " + getClassNum());
}
}
3. Worker.java
package com.example.demo;
public class Worker {
private String name;
private int age;
private String job;
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;
}
public void getWorkerInfo() {
System.out.println("이름 : " + getName());
System.out.println("나이 : " + getAge());
System.out.println("직업 : " + getJob());
}
}
4. LogAop.java
package com.example.demo;
import org.aspectj.lang.ProceedingJoinPoint;
public class LogAop {
public Object loggerAop(ProceedingJoinPoint joinpoint) throws Throwable {
String signatureStr = joinpoint.getSignature().toShortString();
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));
}
}
}
5. MainClass.java
package com.example.demo;
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:applicationCTX.xml");
Student student = ctx.getBean("student", Student.class);
student.getStudentInfo();
Worker worker = ctx.getBean("worker", Worker.class);
worker.getWorkerInfo();
ctx.close();
}
}
다음은 @Aspect 어노테이션을 이용한 방식으로
LogAop 클래스와 applicationCTX.xml을 수정합니다
1. applicationCTX.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="com.example.demo.LogAop" />
<bean id="student" class="com.example.demo.Student" >
<property name="name" value="GuruSa" />
<property name="age" value="10" />
<property name="gradeNum" value="3" />
<property name="classNum" value="5" />
</bean>
<bean id="worker" class="com.example.demo.Worker" >
<property name="name" value="BuruSa" />
<property name="age" value="35" />
<property name="job" value="developer" />
</bean>
</beans>
2. LogAop.java
package com.example.demo;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
@Aspect
public class LogAop {
@Pointcut("within(com.example.demo.*)")
private void pointcutMethod() {
}
@Around("pointcutMethod()")
public Object loggerAop(ProceedingJoinPoint joinpoint) throws Throwable {
String signatureStr = joinpoint.getSignature().toShortString();
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(com.example.demo.*)")
public void beforAdvice() {
System.out.println("beforAdvice()");
}
}
위의 코드를 실행해보시면
Student 클래스의 getStudentInfo()와
Worker 클래스의 getWorkerInfo()가
호출되었을 때 동작하는 것을 볼 수 있습니다
이것으로 학습을 마치겠습니다
그럼 이만-_-
'Java' 카테고리의 다른 글
[Java] 스프링(Spring) 폼(Form) 데이터와 Validator 검증 (0) | 2020.09.29 |
---|---|
[Java] 스프링(Spring) MVC(Model-View-Controller) (0) | 2020.09.28 |
[Java] 스프링(Spring) 컨테이너(Container)와 빈(Bean)의 생명 주기(Life Cycle) 및 범위(Scope) (0) | 2020.09.24 |
[Java] 스프링(Spring) DI(Dependency Injection)과 IOC 컨테이너(Container) (0) | 2020.09.23 |
[Java] 스프링(Spring) 환경 세팅하기 (0) | 2020.09.23 |