728x90
AOP
AOP(Aspect-Oriented Programming)는 프로그래밍 패러다임 중 하나로, 주로 관점 지향 프로그래밍이라고도 불립니다. AOP는 코드에서 흩어진 관심사(concern)를 모듈화하고 중복을 제거하여 코드의 가독성과 유지보수성을 향상시키는데 도움을 줍니다.
관심 분리
관심 분리(Concern Separation)는 소프트웨어 엔지니어링에서 중요한 원칙 중 하나로, 횡단 관심과 핵심 관심을 분리하는 것을 의미합니다.
Controller 메서드
- ( 개발자용 ) 로그
- 권한 확인 : 보안, 인증, 허가, ...
- 비즈니스 메서드( CRUD, 핵심 로직, 핵심 관심, ...)
- 트랜잭션, 보안 관제 로그, ...
1, 2, 4 : 공통 로직, 횡단 관심
3 : 핵심 관심, 핵심 로직, 비즈니스 메서드, CRUD
AOP 용어
- Advice (어드바이스)
- Advice는 횡단 관심사를 나타내는 것으로, 애플리케이션의 여러 지점에서 실행되는 코드입니다. Advice는 주로 메서드 실행 전, 후, 예외 발생 시 등과 같이 특정한 시점에서 동작합니다. 예를 들어, 로깅, 보안, 트랜잭션 관리 등이 Advice의 예시입니다.
- Pointcut (포인트컷)
- Pointcut은 핵심 관심사로서 적용할 메서드를 선택하는 방법을 나타냅니다. Pointcut은 특정한 메서드 패턴 또는 이름을 정의하여 어떤 메서드가 Advice를 받아야 하는지를 결정합니다. CRUD(Create, Read, Update, Delete) 메서드와 같이 특정한 메서드 그룹에 Advice를 적용할 수 있습니다.
- Aspect (애스팩트)
- Aspect는 Pointcut과 Advice의 결합입니다. 즉, 어떤 Pointcut에서 어떤 Advice를 실행할 것인지를 정의한 것을 의미합니다. Aspect는 횡단 관심사와 핵심 관심사를 결합하여 특정한 시점에 Advice를 적용합니다.
- Weaving (위빙)
- Weaving은 Aspect에 정의된 Advice가 핵심 관심사(비즈니스 메서드)에 적용되는 과정을 나타냅니다. 스프링은 위빙을 통해 Aspect의 Advice를 코드에 주입하고, 이를 실행할 때마다 해당 Advice가 실행됩니다. 스프링은 런타임에 위빙을 수행하며, 이것이 AOP의 핵심 원리 중 하나입니다.
- Join Point (조인 포인트)
- Join Point는 Pointcut이 선택한 대상 메서드들 중에서 Advice가 실행될 때의 실제 실행 지점을 나타냅니다. 예를 들어, 메서드 호출 시점이나 예외 발생 시점이 Join Point입니다. 핵심 관심사의 실행 시점을 나타냅니다.
실습
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/maven-v4_0_0.xsd">
...
<!-- AOP -->
<!-- AspectJ -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.8</version>
</dependency>
...
</project>
pom.xml
pom.xml에서 AOP사용을 위한 의존성을 추가합니다.
<?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:context="http://www.springframework.org/schema/context"
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/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
<context:component-scan base-package="com.spring.biz" />
</beans>
applicationContext.xml
applicationContext.xml의 namespaces에서 AOP를 추가합니다. applicationContext.xml에 추가하는 이유는 Controller의 로직과 소통할 확률이 높기 때문이며 불러내는 시점이 사용자 요청 직후이기 때문입니다. 또한 AOP 설정이 완료되는 시점이 클라이언트로 부터 HTTP 요청을 받는 시점보다 먼저여야 하기 때문에 루트 컨테이너로 등록된 applicationContext.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:context="http://www.springframework.org/schema/context"
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/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
<context:component-scan base-package="com.spring.biz" />
<!-- <bean id="LogAdvice" class="com.spring.biz.common.LogAdvice" /> -->
<!-- <bean id="LogAdvice2" class="com.spring.biz.common.LogAdvice2" /> -->
<!-- <bean id="aroundAdvice" class="com.spring.biz.common.AroundAdvice" /> -->
<!-- <bean id="afterReturningAdvice" class="com.spring.biz.common.AfterReturningAdvice" /> -->
<!-- <bean id="advice" class="com.spring.biz.common.AfterThrowingAdvice" /> -->
<bean id="advice" class="com.spring.biz.common.AroundAdvice" />
<aop:config>
<!-- <aop:pointcut expression="execution(OUTPUT FUNCNAME(INPUT))" id="" /> -->
<aop:pointcut expression="execution(* com.spring.biz..*Impl.*(..))" id="aPointcut" />
<aop:pointcut expression="execution(* com.spring.biz..*Impl.select*(..))" id="bPointcut" />
<!-- <aop:aspect ref="LogAdvice2"> -->
<!-- <aop:aspect ref="aroundAdvice"> -->
<aop:aspect ref="advice">
<!-- <aop:before method="printLog2" pointcut-ref="aPointcut" /> -->
<!-- <aop:after method="printLog2" pointcut-ref="bPointcut" /> -->
<!-- <aop:around method="aroundPrintLog" pointcut-ref="bPointcut" /> -->
<!-- <aop:after-returning method="afterReturningPrintLog" pointcut-ref="bPointcut" returning="returnObj" /> -->
<!-- <aop:after-throwing method="afterThrowingPrintLog" pointcut-ref="aPointcut" throwing="exceptObj" /> -->
<aop:around method="aroundPrintLog" pointcut-ref="aPointcut" />
</aop:aspect>
</aop:config>
</beans>
applicationContext.xml
GitHub
https://github.com/Qkrwnsgus0522/Spring
728x90