신규 블로그를 만들었습니다!

2020년 이후부터는 아래 블로그에서 활동합니다.

댓글로 질문 주셔도 확인하기 어려울 수 있습니다.

>> https://bluemiv.tistory.com/

AOP

Aspect Oriented Programing

관점 지향 프로그래밍

 

프로그래밍을 하다보면, 공통적인 기능이 많이 발생한다.

이러한 공통기능을 모든 모듈에 적용하기 위한 방법으로 상속을 이용한다.

상속도 좋은 방법이지만, JAVA에서는 다중 상속이 불가능하다.

 

이러한 모듈을 상속받아 공통 기능을 부여하기에는 한계가 있다.

그리고, 기능 구현부분에서

핵심코드와 공통기능코드가 섞여있어서

보기에도 불편하고, 효율성이 떨어진다.

 

이러한 이유로 AOP가 등장했다.

AOP방법은 핵심 기능과 공통 기능을 분리 시켜놓고,

공통 기능을 필요로 하는 핵심 기능들에서 사용하는 방식이다.

(핵심기능은 변화하지만, 공통기능은 다시 적용이 가능하다.)

 

즉, AOP는 핵심기능과 공통기능을 분리시킨다는 부분을 주의깊게 보자

 

 

 

주요용어

Aspect : 공통기능

Advice : Aspect의 기능 자체

Jointpoint : Advice를 적용해야 되는 부분(ex : 필드, 메소드 / 스프링에서는 메소드만 해당)

Pointcut : Jointpoint의 부분으로 실제로 Advice가 적용된 부분

Weaving : Advice를 핵심기능에 적용하는 행위

 

스프링에서 AOP 구현방법 :  proxy를 이용한다.

 

client(호출부) -> proxy -> Target(핵심기능)

 

  • step1. client가 프록시한테 요청해서 공통기능을 실행
  • stpe2. 프록시가 다시 Target으로 가서 핵심기능을 실행
  • step3. 다시 공통기능을 실행하기 위해, 프록시로 와서 공통기능 실행

(프록시가 중간에서 '대행' 역할을 한다.)

 

 

 

스프링에서 AOP 구현방식

  • 방법1. XML 스키마 기반의 AOP구현

  • 방법2. @Aspect 어노테이션 기반의 AOP 구현

 

방법 1. XML기반의 AOP구현

<설정할 부분>

  • 의존설정(pom.xml)

<!-- AOP -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.7.4</version>        
</dependency>​
 
 
  • 공통기능의 클래스 제작 - Advice 역할 클래스

// proxy
public class LogAop {
 
    // 경과시간 체크하는 공통기능 메소드
    public Object loggerAop(ProceedingJoinPoint joinPoint) throws Throwable {
        // 
    }
}
​
자세한 코드는 글의 아래에서  다룬다.
 
 
  • XML설정 파일에 Aspect 설정

<bean id="logAop" class="com.edu.ex.LogAop"></bean>
<aop:config>
    <aop:aspect id="logger" ref="logAop">
        <aop:pointcut expression="within(com.edu.ex.*)" id="publicMethod"/>
        <aop:around pointcut-ref="publicMethod" method="loggerAop"/>
    </aop:aspect>
</aop:config>
​

 

 

 

코드를 통해 알아보기

Main.java

package com.edu.ex;
 
import org.springframework.context.support.GenericXmlApplicationContext;
 
public class Main {
 
    public static void main(String[] args) throws Exception {
        GenericXmlApplicationContext ctx = new GenericXmlApplicationContext("classpath:applicationCTX.xml");
 
        Student student = ctx.getBean("student", Student.class);
        student.getInfo();
 
        Worker worker = ctx.getBean("worker", Worker.class);
        worker.getInfo();
 
        ctx.close();
    }
}
 ​

단순한 Main함수

 

Student.java

package com.edu.ex;
 
public class Student {
 
    private String name;
    private int age;
 
    // get set method
    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;
    }
 
    // constructor
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
 
    public Student() {
 
    }
 
    public void getInfo() {
        System.out.println(">> name : " + name);
        System.out.println(">> age : " + age);
    }
 
}​

 

단순한 VO,

정보를 확인할 getInfo() 출력함수를 만들었다.

 

Worker.java

package com.edu.ex;
 
public class Worker {
 
    private String name;
    private int age;
    private String job;
 
    // constructor
    public Worker(String name, int age, String job) {
        this.name = name;
        this.age = age;
        this.job = job;
    }
 
    public Worker() {
    }
 
    // get set method
    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 getInfo() {
        System.out.println(">> name : " + name);
        System.out.println(">> age : " + age);
        System.out.println(">> job : " + job);
    }
 
}​

단순한 VO,

정보를 확인할 getInfo() 출력함수를 만들었다.

 

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.springframework.samples</groupId>
  <artifactId>exam02</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  
  <properties>
 
        <!--

            생략        

        -->    
 
    </properties>
    
    <dependencies>
 
        <!--

            생략        

        -->    
        
        <!-- AOP -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.7.4</version>        
        </dependency>
 
    </dependencies>    
</project>​

마지막에 'aspectj' dependency를 추가 한다.

 

메이븐 디펜던시에 라이브러리가 추가된것을 확인할 수 있다.

 
 

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.edu.ex.LogAop"></bean>
    <aop:config>
        <aop:aspect id="logger" ref="logAop">
            <aop:pointcut expression="within(com.edu.ex.*)" id="publicMethod"/>
            <aop:around pointcut-ref="publicMethod" method="loggerAop"/>
        </aop:aspect>
    </aop:config>
 
    <bean id="student" class="com.edu.ex.Student">
        <property name="name">
            <value>hongku_student</value>        
        </property>
        <property name="age">
            <value>26</value>        
        </property>
    </bean>
    
    <bean id="worker" class="com.edu.ex.Worker">
        <property name="name">
            <value>hongku_worker</value>        
        </property>
        <property name="age">
            <value>36</value>        
        </property>
        <property name="job">
            <value>developer</value>        
        </property>
    </bean>
</beans>​

namespace에 aop를 추가 한다.

 

LogAop.java

package com.edu.ex;
 
import org.aspectj.lang.ProceedingJoinPoint;
 
// proxy
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));
        }
    }
}​

공통기능(시간체크하는 기능)이 2번 호출 된다.

공통기능 실행 -> 핵심기능 실행 -> 공통기능 실행

 

 

▲ 결과 화면

시작 시간을 체크 (공통기능 1회 실행)

핵심기능 실행 (getInfo() 메소드)

끝나는 시간을 체크 (공통기능 2회 실행)

 

 

 

AOP 태그의 종류

  • <aop:before> : 메소드 실행전에 advice 실행

  • <aop:after-returning> : 정상적으로 메소드 실행 후에 advice 실행

  • <aop:after-throwing> : 메소드 실행둘 exception 발생시 advice 실행

  • <aop:after> : 메소드 실행중 exception이 발생해도 advice 실행

  • <aop:around> : 메소드 실행 전/후 및 exception 발생시 advice 실행

 
 
 

 

※ 이 글은 Seoul Wiz - '실전 Spring 강좌'를 요약하여 작성하였습니다.

>> 유튜브 - SeoulWiz

 

 

  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기