AOP는 Aspect-Oriented Programming의 약자이고, 이를 번역하면 관점 지향 프로그램이 된다.
스프링 DI가 의존성(new)에 대한 주입이라면 스프링 AOP는 로직(code) 주입이라고 할 수 있다.
핵심 관심사 : 모듈별로 다르게 나타나는 부분
코드 = 핵심 관심사 + 횡단 관심사
객체 지향에서 로직(코드)이 있는 곳은 당연히 메서드의 안쪽이다. 메서드에서 코드를 주입할 수 있는 곳
총 5군데다.
package aop002;
public interface Person {
void runSomething();
}
package aop002;
public class Boy implements Person {
public void runSomething() {
System.out.println("컴퓨터로 게임을 한다.");
}
}
package aop002;
public class Girl implements Person{
public void runSomething() {
System.out.println("요리를 한다.");
}
}
package aop002;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class MyAspect {
@Before("execution(*runSomething())")
public void before(JoinPoint joinPoint) {
System.out.println("얼굴 인식 확인: 문을 개방하라");
//System.out.println("열쇠로 문을 열고 집에 들어간다.");
}
}
package aop002;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Start {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("aop002/aop002.xml");
Person romeo = context.getBean("boy", Person.class);
Person juliet = context.getBean("girl", Person.class);
romeo.runSomething();
juliet.runSomething();
}
}
<?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
https://www.springframework.org/schema/aop/spring-aop.xsd">
<aop:aspectj-autoproxy />
<bean id="myAspect" class="aop002.MyAspect" />
<bean id="boy" class="aop002.Boy" />
<bean id="girl" class="aop002.Girl" />
</beans>
이 이외에도 빌드 도구에 AOP에 대한 의존성 주입하기
👨🏻💻 스프링 AOP 요약
스프링 AOP는 인터페이스(interface) 기반이다.
스프링 AOP는 프록시(proxy) 기반이다.
스프링 AOP는 런타임(runtime) 기반이다.
[접근제한자패턴] 리턴타입패턴 [패키지&클래스패턴.]메서드이름패턴(파라미터패턴)[throws 예외패턴]
[ ] 은 생략 가능을 의미
package aop002;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class MyAspect {
**@Before**("execution(*runSomething())")
**public void before(JoinPoint joinPoint) {
System.out.println("얼굴 인식 확인: 문을 개방하라");
}**
}
// Pointcut이 시작되기 전(@Before)에 before() 메서드를 실행
AOP에서 Aspect는 여러 개의 Advice와 여러 개의 Pointcut의 결합체를 의미
Aspect = Advice들 + Pointcut들
Advice는 [언제(When), 무엇을(What)]를 의미, Pointcut은 [어디에(Where)]를 의미
→ 결국 Aspect는 When + Where + What(언제, 어디서, 무엇을)이 된다.
// POJO & XML 기반 - 스프링 프레임워크에 종속되지 않음
package aop003;
import org.aspectj.lang.JoinPoint;
public class MyAspect {
public void before(JoinPoint joinPoint) {
System.out.println("얼굴 인식 확인: 문을 개방하라");
//System.out.println("열쇠로 문을 열고 집에 들어간다.");
}
}
<?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
https://www.springframework.org/schema/aop/spring-aop.xsd">
<aop:aspectj-autoproxy />
<bean id="myAspect" class="aop003.MyAspect" />
<bean id="boy" class="aop003.Boy" />
<bean id="girl" class="aop003.Girl" />
<aop:config>
<aop:aspect ref="myAspect">
<aop:before method="before" pointcut="execution(* runSomething())" />
</aop:aspect>
</aop:config>
</beans>
package aop004;
import org.aspectj.lang.JoinPoint;
public class MyAspect {
public void before(JoinPoint joinPoint) {
System.out.println("얼굴 인식 확인: 문을 개방하라");
}
public void lockDoor(JoinPoint joinPoint) {
System.out.println("주인님 나갔다: 어이 문 잠가!!!");
}
}
<?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
https://www.springframework.org/schema/aop/spring-aop.xsd">
<aop:aspectj-autoproxy />
<bean id="myAspect" class="aop004.MyAspect" />
<bean id="boy" class="aop004.Boy" />
<bean id="girl" class="aop004.Girl" />
<aop:config>
<aop:aspect ref="myAspect">
<aop:before method="before" pointcut="execution(* runSomething())" />
<aop:after method="lockDoor" pointcut="execution(* runSomething())" />
</aop:aspect>
</aop:config>
</beans>
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
https://www.springframework.org/schema/aop/spring-aop.xsd">
<aop:aspectj-autoproxy />
<bean id="myAspect" class="aop004.MyAspect" />
<bean id="boy" class="aop004.Boy" />
<bean id="girl" class="aop004.Girl" />
<aop:config>
<aop:pointcut id="iampc" expression="execution(* runSomething())"/>
<aop:aspect ref="myAspect">
<aop:before method="before" pointcut-ref="iampc" />
<aop:after method="lockDoor" pointcut-ref="iampc" />
</aop:aspect>
</aop:config>
</beans>
package aop005;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Before;
public class MyAspect {
@Before("execution(* runSomething()")
public void before(JoinPoint joinPoint) {
System.out.println("얼굴 인식 확인: 문을 개방하라");
}
@After("execution(* runSomething())")
public void lockDoor(JoinPoint joinPoint) {
System.out.println("주인님 나갔다: 어이 문 잠가!!!");
}
}
<?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
https://www.springframework.org/schema/aop/spring-aop.xsd">
<aop:aspectj-autoproxy />
<bean id="myAspect" class="aop005.MyAspect" />
<bean id="boy" class="aop005.Boy" />
<bean id="girl" class="aop005.Girl" />
</beans>
어노테이션 기반 리펙토링 후
package aop006;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class MyAspect {
@Pointcut("execution(* runSomething())")
private void iampc() {
//여긴 무엇을 작성해도 의미가 없어요.
}
@Before("iampc()")
public void before(JoinPoint joinPoint) {
System.out.println("얼굴 인식 확인: 문을 개방하라");
}
@After("iampc()")
public void lockDoor(JoinPoint joinPoint) {
System.out.println("주인님 나갔다: 어이 문 잠가!!!");
}
}