Java

[Java] 스프링(Spring) AOP(Aspect-Oriented Programming)

구루싸 2020. 9. 24. 14:54
반응형
SMALL

어느 덧 추석이 다가오네요!

코로나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()가

호출되었을 때 동작하는 것을 볼 수 있습니다

이것으로 학습을 마치겠습니다

그럼 이만-_-

반응형
LIST