바닥코딩

코드로 익혀보는 spring 기초3( AOP) 본문

Spring Framework/스프링 기초

코드로 익혀보는 spring 기초3( AOP)

개발공부개발공부 2020. 2. 18. 00:18

AOP( Aspect Oriented Programing)

 직역하자면 관점 지향 프로그래밍이다 프로그래밍을 하다보면 공통적인 기능이 많이 발생한다 자바나 C# 등 객체지향 프로그래밍을 해본 사람들이라면 이러한 공통기능을 적용하기 위해 상속이라는 개념을 사용하는 것을 알 것입니다. 그렇지만 자바를 공부해본 사람들은 알듯이 자바는 다중 상속이 불가능 합니다.

 따라서 이러한 모듈의 기능을 상속받아 공통 기능을 부여하기에는 한계가 존재한다 따라서 Spring에서는 DI가 모듈의 결합도를 낮춰주는 역할을 한다면 AOP는 애플리케이션 전체에 걸쳐 사용되는 기능을 재사용하도록 해주는 기능을 제공합니다 정리하자면 

 1. 핵심기능과 공통기능을 분리 시킨다 

 2. 공통 기능을 필요로 하는 핵심 기능들에서 다시 사용한다 

AOP에서 사용하는 용어

1.Pointcut : 어느 부분(where)에 횡단 관심 모듈을 삽입 할 것인지 정의합니다. 자바 프로그래밍은 매서드의 호출로 진행이 되기 떄  문에 메서드의 횡단 관심 모듈을 삽입하니다

2.Joinpoint : 언제(when)언제 횡단 관심 모듈을 삽입할지를 정의합니다

  • 메서드 실행전(before)
  • 메서드 실행 후 (after)
  • 변환된 후(AfterReturning)
  • 예외가 던져지는 시점(AfterThrowing) 
  • 메서드 실행 전, 후(around)

※pointcut이 메서드이기 때문에 pointcut을 기준으로 joinpoint가 결정 된다 

3.advice : 핵심 관심 모듈에 삽일 될 횡단 관심 모듈 자체(What)

4.Aspect : 공통기능을 의미

5.Weaving : Advicd를 핵심 기능에 적용 하는 행위

6.proxy : 프록시는 대행인 이라는 뜻을 가지고 있다 프록시 서버는 클라이언트가 다른 네트워크 서비스에 간접적으로 접속할 수 있게  해주는 컴퓨터 시스템을 의미하지만  spring에서는 이렇게 생각하기 보다는 aop를 구현해주는 방법이라고 생각하는 것이 편할겁니다  

      프록시를에게 요청 -> 프록시에서 공통기능 수행 -> 프록시가 핵심기능으로  이동 -> 핵심기능 로직 수행 -> 프록시로 돌아와 나머지 공통부분 수행 -> 종료

    ※ 프록시에만 공통기능을 보내주면 로직을 알아서 대행해준다 

AOP를 사용하는 방법

 xml에서 aop활용하기 

1. src/main/java 폴더 내 com.javalec.ex 패키지를 만들어 준다 

2. Student, Worker 클래스를 만들 것이다 이 두개는 위 프록시에서 설명한 target 즉 핵심기능을 수행하게 되는데, 이 두분엔는 공통적으로 사용되는 공통 기능이 있으며 이 부분을 aop를 통해 다른 관점에서 바라본느 프로그램을 작성할 것입니다. Student 클래스와 Worker 클래스 내용은 아래와 같습니다.

package com.javalec.ex;

public class Student {
	private String name;
	private int age;
	private int gradeNum;
	private int classNum;
	
	public String getName() {
		return name;
	}
	public int getAge() {
		return age;
	}
	public int getGradeNum() {
		return gradeNum;
	}
	public int getClassNum() {
		return classNum;
	}
	public void setName(String name) {
		this.name = name;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public void setGradeNum(int gradeNum) {
		this.gradeNum = gradeNum;
	}
	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());
	}


}
package com.javalec.ex;

public class Worker {

	private String name;
	private int age;
	private String job;
	public String getName() {
		return name;
	}
	public int getAge() {
		return age;
	}
	public String getJob() {
		return job;
	}
	public void setName(String name) {
		this.name = name;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public void setJob(String job) {
		this.job = job;
	}
	public void getWorkerInfo() {
		System.out.println("이름 :" + getName());
		System.out.println("나이 :" + getAge());
		System.out.println("직업 :" + getJob());
		
	}
	
	
}

3. 해당 class의 변수 내용을 bean을 이용해 주입한다

	<bean id="student" class="com.javalec.ex.Student">
		<property name="name" value="홍길동"></property>
		<property name="age" value="10"></property>
		<property name="gradeNum" value="3"></property>
		<property name="classNum" value="5"></property>
	</bean>
	<bean id="worker" class="com.javalec.ex.Worker">
		<property name="name" value="홍길순"></property>
		<property name="age" value="35"></property>
		<property name="job" value="개발자"></property>
	</bean>

4. 공통기능을 작성한다 해당 프로젝트에서는 log에 관련된 공통기능을 구현 하려고 한다 매서드가 시작 되었을때의 시간과 종료 되었을 떄의 시간을 입력받아 수행시간을 출력해주는 문장을 작성한다.

LogAOP

package com.javalec.ex;

import org.aspectj.lang.ProceedingJoinPoint;

public class LogAop {

	public Object loggerAop(ProceedingJoinPoint joinpoint) throws Throwable{
		String singnatureStr = joinpoint.getSignature().toShortString();
		long st = System.currentTimeMillis();
		try {
			Object obj = joinpoint.proceed();
			return obj;
		} 
		finally {
			long et = System.currentTimeMillis();
			System.out.println(singnatureStr + "is finished");
			System.out.println(singnatureStr + "경과시간" +(et-st));
			
		}
		
	}
}

 

5. aop를 추가 한다

aop를 추가 할 때는 이전 포스트 내용의 context를 namespace에 추가해주는 것처럼 namespace에서 aop체크박스를 체크 해준다

위에 설명하였던 aspect 나 around pointcut 과 같은 부분의 설정을 직접 타이핑 하여 쓸 수도 있지만 namespace에서더웃 쉽게 작성할 수 있다 이것을 통해 aopconfig를 아래와 같이 작성해준다 

<aop:config>
		<aop:aspect id="logger" ref="logAop">
			<aop:pointcut expression="witnin(com.javalec.ex.*)"
				id="publicM" />
			<aop:around method="loggerAop" pointcut-ref="publicM" />
		</aop:aspect>
	</aop:config>

6. 해당 aop를 테스트할 main 클래스를 만든다

package com.javalec.ex;

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

public class MainClass {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		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();	
	}

}

 

해당 코드를 실행하면 다른 핵심에서 aop 하나를 통해 공통기능을 수행하는 동작을 확인 할 수 있습니다.