framework/spring AOP(관점지향)

[springAOP] 1. AOP의 개요 | OOP vs AOP

jeri 2024. 7. 30. 10:46
반응형

01. AOP의 개요

절차지향

  • 대형 프로그램만들 시 매우 많은 함수들을 사용하므로 점점 관리하기가 어려워져서,
  • 함수를 통해 명령들을 모아 모듈화 하여 이용했음 (ex. C언어)
  • 단점: 함수는 자료형이 아니므로 배포가 불가능함

객체지향(OOP)

  • 함수(메소드)뿐만 아니라 필요한 변수(필드)까지 모두 모듈화하여 사용함
  • 이를 클래스라 부름 : 클래스 자료형 = 필드 + 메소드 (ex. C++언어가 나옴)
  • 또한 모듈화된 자료형으로 만들었기 때문에 배포 가능
  • 원하는 기능들을 가져가다가 손쉽게 이용 가능
  • 그러나 너무 강력한 모듈화..
  • 프로그램 만들 시 공통된 코드들(ex. 보안코드)이 반복되어 나오는데, 자바는 파일들을 가져다 삽입하는 기술이 없음
  • JSP에서 제공해준 include(JSP에서 만든 기술 중 하나) 액션 태그는 자바가 아님..!!!
  • 객체지향프로그래밍은 모든 기능을 하나의 객체가 모두 다 가지고 있어야함
  • 즉, 클래스마다 필요한 코드들이 같다면 중복해서 사용해야함
  • 중복된 코드를 최소화할 수 있도록 다른 클래스를 만들어 관계를 맺어 가져다 씀
  • 그러나 코드가 중복된다고 관계를 맺는 건 좋지 않음
  • 관계란 상속관계 - is A 과 포함관계 - has A처럼 객체간의 관계가 있어야 하는데,
  • 코드의 중복성을 회피하고자 다른 클래스를 만들어 억지로 관계를 맺어버린다면 코드가 지저분해지고, 생산성 떨어지고, 객체간의 결합도가 높으면 재활용성 떨어지고, 유지보수의 효율성이 떨어짐
  • 이를 해결하고자 AOP(관점지향프로그래밍)가 나옴

관점지향(AOP)

  • 관계를 맺지 않아도 프로그램이 실행될 때 AOP기능을 제공해주는 프로그램이 각각의 클래스에서 필요한 기능만 가져다가 합쳐서 프로그램에서 실행될 수 있도록 만들어줌
  • 기능은 핵심관심코드와 횡단관심코드로나뉨

 

 

 

02. OOP vs AOP

1) OOP

🖤OopOne 클래스
  • 억지로 관계 맺은 OopOne - OopLogger
package xyz.itwill06.oop;

//OOP 단점 : 모듈화가 너무 강력하여 핵심관심코드와 횡단관심코드를 분리하여 프로그램을 작성이 어려움
// => 코드의 중복성이 높아 프로그램에 생산성 및 유지보수의 효율성 감소
public class OopOne {

	/*
	//메소드가 사용할 명령들 중 중복명령은 [private]로 만들어 가져다 사용 - 유지보수의 효율성 증가
	private void beforelog() {
		System.out.println("*** 메소드의 명령(핵심관심코드)이 실행되기 전에 기록될 내용 ***"); //횡단관심코드
	}
	*/

	//메소드가 사용할 중복명령을 클래스로 만들어 사용(모든 클래스가 사용) - 유지보수의 효율성 증가 & OOP의 개념 위반
	//=> 그러나!!! 코드의 중복을 피하기 위해 관계도 없는 횡단관심과 핵심관심을
	//억지로 관계를 맺어(포함관계 OopOne - logger) 사용하는 것은
	//OOP의 추상화와 캡슐화의 개념을 위반함
	private OopLogger logger=new OopLogger();

	public void display1() {
		//횡단관심코드 : 프로그램 실행에 보조적인 기능을 제공하는 명령 (어떠한 기능을 구현하기 위해 반드시 필요한 명령)
		//=> 로그 처리(기록), 권한처리(인증), 트랜잭션처리(Commit&Rollback), 예외처리(try-catch)
		//System.out.println("*** 메소드의 명령(핵심관심코드)이 실행되기 전에 기록될 내용 ***");
		//beforelog();
		logger.beforelog(); //횡단관심코드

		//핵심관심코드 : 프로그램 실행에 핵심적인 기능을 제공하는 명령 (기능 구현과 별개의 명령)
		// => 데이타 처리 명령
		System.out.println("*** OopOne 클래스의 display1() 메소드 호출 ***"); //핵심관심코드
	}

	public void display2() {
		//System.out.println("*** 메소드의 명령(핵심관심코드)이 실행되기 전에 기록될 내용 ***");
		//beforelog();
		logger.beforelog();
		System.out.println("*** OopOne 클래스의 display2() 메소드 호출 ***");
	}

	public void display3() {
		//System.out.println("*** 메소드의 명령(핵심관심코드)이 실행되기 전에 기록될 내용 ***");
		//beforelog();
		logger.beforelog();
		System.out.println("*** OopOne 클래스의 display3() 메소드 호출 ***");
	}
}
🖤OopTwo 클래스
  • 억지로 관계 맺은 OopTwo - OopLogger
package xyz.itwill06.oop;

public class OopTwo {
	/*
	private void beforelog() {
		System.out.println("*** 메소드의 명령(핵심관심코드)이 실행되기 전에 기록될 내용 ***");
	}
	*/

	//억지로 포함관계를 맺음 (OopOne - logger) - 유지보수의 효율성 증가 & OOP의 개념 위반
	private OopLogger logger=new OopLogger();

	public void display1() {
		//System.out.println("*** 메소드의 명령(핵심관심코드)이 실행되기 전에 기록될 내용 ***");
		//beforelog();
		logger.beforelog();//횡단관심코드
		System.out.println("*** OopTwo 클래스의 display1() 메소드 호출 ***");//핵심관심코드
	}

	public void display2() {
		//System.out.println("*** 메소드의 명령(핵심관심코드)이 실행되기 전에 기록될 내용 ***");
		//beforelog();
		logger.beforelog();
		System.out.println("*** OopTwo 클래스의 display2() 메소드 호출 ***");
	}

	public void display3() {
		//System.out.println("*** 메소드의 명령(핵심관심코드)이 실행되기 전에 기록될 내용 ***");
		//beforelog();
		logger.beforelog();
		System.out.println("*** OopTwo 클래스의 display3() 메소드 호출 ***");
	}
}
🖤OopLogger 클래스
  • 억지로 관계 맺은 OopOne - OopLogger
  • 억지로 관계 맺은 OopTwo - OopLogger
package xyz.itwill06.oop;

public class OopLogger {
	public void beforelog() {
		System.out.println("*** 메소드의 명령(핵심관심코드)이 실행되기 전에 기록될 내용 ***"); //횡단관심코드
	}
}
🖤OopApp 실행프로그램
package xyz.itwill06.oop;

public class OopApp {
	public static void main(String[] args) {
		OopOne one = new OopOne();
		OopTwo two = new OopTwo();

		one.display1();
		one.display2();
		one.display3();

		two.display1();
		two.display2();
		two.display3();
	}
}

2) AOP

🖤핵심관심모듈 : (부모) Aop 인터페이스
package xyz.itwill06.oop;

public interface Aop {
	void display1();
	void display2();
	void display3();
}
🖤핵심관심모듈 : (자식) AopOne 클래스
  • 아무런 관계가 없는 AopOne - AopLogger
package xyz.itwill06.oop;

//핵심관심모듈 : 핵심관심코드만 이용하여 메소드를 작성한 클래스
public class AopOne implements Aop {

	@Override
	public void display1() {
		System.out.println("*** AopOne 클래스의 display1() 메소드 호출 ***");
	}
	@Override
	public void display2() {
		System.out.println("*** AopOne 클래스의 display2() 메소드 호출 ***");
	}
	@Override
	public void display3() {
		System.out.println("*** AopOne 클래스의 display3() 메소드 호출 ***");
	}
}
🖤핵심관심모듈 : (자식) AopTwo 클래스
  • 아무런 관계가 없는 AopTwo - AopLogger
package xyz.itwill06.oop;

//핵심관심모듈
public class AopTwo implements Aop {

	@Override
	public void display1() {
		System.out.println("*** AopTwo 클래스의 display1() 메소드 호출 ***");
	}
	@Override
	public void display2() {
		System.out.println("*** AopTwo 클래스의 display2() 메소드 호출 ***");
	}
	@Override
	public void display3() {
		System.out.println("*** AopTwo 클래스의 display3() 메소드 호출 ***");
	}
}
🖤횡단관심모듈 : AopLogger 클래스 - Advice
  • 아무런 관계가 없는 AopOne - AopLogger
  • 아무런 관계가 없는 AopTwo - AopLogger
package xyz.itwill06.oop;

//횡단관심모듈 : 횡단관심코드만 이용하여 메소드를 작성한 클래스 - Advice 클래스
public class AopLogger {
	public void beforeLog() {
		System.out.println("*** 메소드의 명령(핵심관심코드)이 실행되기 전에 기록될 내용 ***");
	}
}
🖤동작 : AopProxy 클래스 - Aspect - (Spring에서는.. AspectJ 라이브러리가 Proxy 역할 해줌 )
  • 핵심관심모듈의 메소드에 횡단관심모듈의 메소드를 삽입하여 동작하는 기능을 제공하는 클래스 - Aspect (= 관점에 대한 결과물)
package xyz.itwill06.oop;

//Proxy 클래스 : 핵심관심모듈의 메소드에 횡단관심모듈의 메소드를 삽입하여 동작하는 기능을 제공
//하는 클래스 - Aspect
public class AopProxy implements Aop {
	//핵심관심모듈로 선언된 클래스의 객체를 저장하기 위한 필드
	// => 필드의 자료형을 인터페이스로 선언하여 모든 자식 클래스의 객체 저장 가능
	private Aop target;

	//횡단관심모듈로 선언된 클래스의 객체를 저장하기 위한 필드
	private AopLogger logger;

	//필드에 객체를 생성하여 저장하거나 매개변수로 객체를 전달받아 저장 - 의존성 주입(DI)
	//=>AOP는 만들어서 저장하고 target은 전달받아 저장할 것임
	public AopProxy(Aop target) {
		super();
		this.target = target;
		logger=new AopLogger();
	}

	//인터페이스의 추상메소드(PointCut)를 오버라이드 선언하여 핵심관심코드와 횡단관심코드를
	//결합(weaving)하여 실행되도록 작성 - Weaving
	// => 핵심관심모듈의 메소드 호출 전 또는 후에 횡단관심모듈의 메소드가 호출하여
	//실행되도록 설정 - 횡단관심 모듈의 메소드 삽입 위치 : JoinPoint
	@Override
	public void display1() {
		logger.beforeLog(); //횡단관심코드를 삽입해서 실행해주세요
		target.display1();  //핵심관심코드를 삽입해서 실행해주세요
	}

	@Override
	public void display2() {
		logger.beforeLog();
		target.display1();
	}

	@Override
	public void display3() {
		logger.beforeLog();
		target.display1();
	}
}
🖤AopApp 실행프로그램
package xyz.itwill06.oop;

public class AopApp {
	public static void main(String[] args) {
		AopProxy one = new AopProxy(new AopOne()); //매개변수를 통해 핵심관심코드의 객체 전달받아 결합시킴
		AopProxy two = new AopProxy(new AopTwo());

		one.display1();
		one.display2();
		one.display3();

		two.display1();
		two.display2();
		two.display3();
	}
}

반응형