이 기사는 Huawei Cloud 커뮤니티 " Spring Master's Road 18 - XML 구성의 관점에서 Spring AOP 이해 ", 저자: Zhuan Yeyang__에서 공유되었습니다.
1. Spring AOP와 동적 프록시
1.1 Spring AOP와 동적 프록시의 관계
Spring AOP
동적 프록시를 기본 메커니즘으로 사용하여 측면 지향 프로그래밍을 구현합니다. 이 메커니즘을 사용하면 Spring
런타임 시 프록시 개체를 동적으로 생성할 수 있습니다. 이러한 프록시 개체는 대상 개체의 메서드를 호출하기 전후에 추가 동작(예: 보안 검사, 트랜잭션 관리, 로깅 등)을 삽입하기 위해 대상 개체(예: 비즈니스 구성 요소)를 래핑합니다. .
-
JDK 동적 프록시 : 대상 객체가 하나 이상의 인터페이스를 구현할 때
Spring AOP
기본적으로 사용되는 동적 프록시입니다JDK
.JDK
동적 프록시는 리플렉션 메커니즘을 사용하여 인터페이스에 대한 프록시 객체를 생성합니다. 이 프록시 객체는 대상 인터페이스 메서드에 대한 모든 호출을 가로챕니다. -
CGLIB 프록시 : 대상 객체가 인터페이스를 구현하지 않는 경우 라이브러리를
Spring AOP
사용하여CGLIB
대상 클래스의 하위 클래스를 생성합니다.CGLIB
( )는 런타임 시 클래스를 확장하고 하위 클래스의 메서드를 재정의하여 메서드 차단을 구현하는Code Generation Library
강력한 고성능 코드 생성 라이브러리입니다 .Java
어떤 프록시 메서드를 사용하든 원래 비즈니스 논리 코드를 변경하지 않고 측면에서 정의한 알림을 통해 메서드 실행의 다양한 단계에서 추가 동작을 삽입하는 것이 목적입니다.
1.2 AOP 기본 용어
Aspect : Aspect는 여러 클래스(로깅, 트랜잭션 관리 등)에 걸쳐 관심사를 모듈화하는 구조입니다. 관점은 여러 유형의 조언( )과 해당 조언이 실행되는 위치와 시기를 정의하는 Advice
하나 이상의 포인트컷( )을 포함할 수 있습니다.Pointcut
조인 포인트(Join Point) : 조인 포인트는 프로그램 실행 중 특정 위치를 나타내며 Spring AOP
이러한 위치를 메서드 호출로 제한합니다. 간단히 말해서, Join Point는 Aspect Advisory를 삽입할 수 있는 지점입니다.
Advice : Advice는 연결점에서 애스펙트가 수행할 작업을 정의합니다. 알림 유형에 따라 이러한 작업은 메서드 호출 전, 후, 결과 반환 후 또는 예외가 발생했을 때 수행될 수 있습니다. 알림 유형은 다음과 같습니다.
- 사전 알림(
Before advice
): 메소드가 실행되기 전에 실행됩니다. - 사후 알림(
After advice
): 결과와 관계없이 메소드가 실행된 후에 실행됩니다. - 반환 후 알림(
After-returning advice
): 메서드가 성공적으로 실행된 후에 실행됩니다. - 사후 예외 알림(
After-throwing advice
): 메서드가 예외를 발생한 후에 실행됩니다. - 서라운드 조언(
Around advice
): 메소드 실행 전후에 실행되어 메소드 호출에 대한 완전한 제어를 제공합니다.
Pointcut(Pointcut) : Pointcut 표현식은 메소드 이름, 액세스 수정자 및 알림이 실행될 때 트리거되어야 하는 메소드를 결정하는 기타 조건을 통해 연결 지점을 일치시킬 수 있는 표현식입니다.
Target Object : 하나 이상의 측면에서 알림을 받는 개체입니다. 프록시 객체라고도 합니다.
AOP 프록시 : AOP
측면 계약(어드바이스와 포인트컷으로 정의됨)을 구현하기 위해 프레임워크에서 생성된 개체입니다. 에서 프록시는 동적 프록시 또는 프록시일 Spring AOP
수 있습니다 .AOP
JDK
CGLIB
소개 : 소개를 사용하면 기존 클래스에 새 메서드나 속성을 추가할 수 있습니다. 이는 Introduction interfaces
하나 이상의 추가 인터페이스( )를 정의하여 달성 되며 AOP
프레임워크는 이러한 인터페이스를 구현하는 대상 개체에 대한 프록시를 생성합니다.
여전히 추상적이라고 느껴진다면, 영화제작의 또 다른 예를 들어 비유해보자.
측면
누군가가 영화를 촬영하고 있는데 영화의 특수 효과(예: 폭발, 특수 조명 효과)가 응용 프로그램에서 처리해야 하는 교차 문제(예: 로깅 또는 트랜잭션 관리)와 같다고 상상해 보세요. 이러한 특수 효과는 특정 장면뿐만 아니라 영화의 다양한 장면에서 나타납니다. Python 에서 AOP
이러한 "효과"는 측면이며 실제 장면(또는 코드)을 변경하지 않고도 프로그램의 여러 부분에 적용될 수 있습니다.
조인포인트
영화의 비유를 이어가면 폭발이 일어나는 순간 등 각 장면의 특정 순간이 연결점으로 볼 수 있다. 프로그래밍에서 이는 일반적으로 메서드 호출에 해당합니다.
조언
알림은 "이 장면이 시작되기 전에 폭발 효과를 추가하세요", "장면이 끝난 후 연기 소멸 효과를 보여주세요"와 같이 감독이 특수 효과 팀에게 보내는 구체적인 지시와 같습니다. 이 지침은 영화의 특정 순간에 특정 효과를 추가해야 하는 특수 효과 팀을 알려줍니다. 에서 AOP
이러한 "명령"은 조인 포인트(특정 코드 실행 순간) 전후 또는 주변에서 측면(특수 효과)이 실행되어야 함을 지정하는 알림입니다.
포인트컷
통지문이 특수효과팀에 대한 감독의 지시라면, 컷팅포인트는 '밤새 로케이션 장면' 등 지시사항에 포함된 구체적인 조건이다. 포인트컷은 알림(효과 지침)을 받아야 하는 연결 지점(예: 특정 메서드 호출)을 정의합니다.
대상 객체
대상 개체는 특수 효과를 추가해야 하는 장면입니다. 프로그래밍 비유에서 이는 측면 논리(예: 로깅이 필요한 클래스)의 영향을 받는 개체입니다.
AOP 프록시
AOP
프록시는 특수 효과 팀에서 제공하는 장면의 제어 가능한 가상 복사본과 같습니다. 이 사본은 관객에게 원본 장면과 동일하게 보이지만 실제로는 감독이 필요할 때 자동으로 특수 효과를 추가합니다. 프로그래밍에서 프록시는 AOP
프레임워크에 의해 자동으로 생성된 개체로, 대상 개체를 래핑하고 알림(특수 효과 지침)이 올바른 시간에 실행되도록 합니다.
소개
소개는 원본 대본에는 존재하지 않는 새로운 캐릭터나 장면을 영화에 추가하는 것과 같습니다. 에서 AOP
소개를 사용하면 기존 클래스에 새로운 메서드나 속성을 추가할 수 있습니다. 이는 원본 스크립트를 변경하지 않고 영화의 내용을 확장하는 것과 같습니다.
2. XML 구성을 통해 Spring AOP 구현
Spring
풍부한 AOP
지원을 제공하며 구성을 통해 XML
Aspect, 알림( advice
) 및 포인트컷( pointcuts
)을 정의할 수 있습니다. 이를 통해 소스 코드를 수정하지 않고도 추가 동작(예: 로깅, 트랜잭션 관리 등)을 추가할 수 있습니다.
구현 단계:
-
Spring 종속성 추가 : 프로젝트에 프레임워크 및 관련 종속성을
pom.xml
추가합니다 .Spring
AOP
-
비즈니스 인터페이스 및 구현 클래스 정의 : 간단한 서비스 클래스와 같은 비즈니스 논리 인터페이스 및 해당 구현을 만듭니다.
-
측면 클래스 정의 : 사전, 사후 및 랩 어라운드 알림을 정의하는 측면 클래스를 만듭니다.
-
구성 XML :
applicationContext.xml
측면, 비즈니스bean
및AOP
관련 태그를 XML로 구성합니다.
2.1 Spring 의존성 추가
pom.xml
파일 에 다음 종속성을 추가합니다.
<종속성> <의존성> <groupId>org.springframework</groupId> <artifactId>스프링 컨텍스트</artifactId> <버전>5.3.10</버전> </종속성> <의존성> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <버전>5.3.10</버전> </종속성> <의존성> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <버전>1.9.6</버전> </종속성> </종속성>
2.2 비즈니스 인터페이스 및 구현 클래스 정의
먼저 비즈니스 로직 인터페이스 MyService
와 그 구현을 정의합니다 MyServiceImpl
.
MyService.java:
패키지 com.example.demo.aop; 공개 인터페이스 MyService { 문자열 PerformAction(문자열 입력)에서 예외가 발생합니다. }
MyServiceImpl.java:
패키지 com.example.demo.aop; 공개 클래스 MyServiceImpl은 MyService를 구현합니다. @우세하다 public String PerformAction(String action)이 예외를 발생시킵니다. System.out.println("MyService에서 작업 수행: " + action); if ("throw".equals(action)) { throw new Exception("MyService의 예외"); } return "수행된 작업: " + 작업; } }
2.3 측면 클래스 정의
다음으로 메소드 가 실행되기 전에 실행되는 MyAspect
사전 조언( advice
) 을 포함할 측면 클래스를 정의합니다 .MyService
performAction
MyAspect.java:
패키지 com.example.demo.aop; import org.aspectj.lang.ProceedingJoinPoint; 공개 클래스 MyAspect { // 사전 알림 공개 무효 beforeAdvice() { System.out.println("조언이 실행되기 전!"); } // 게시 알림 공개 무효 afterAdvice() { System.out.println("조언이 실행된 후!"); } // 반납 후 알림 공개 무효 afterReturningAdvice(Object retVal) { System.out.println("어드바이스를 반환한 후 실행 중입니다! 반환 값: " + retVal); } // 예외 발생 후 알림 공공 무효 afterThrowingAdvice(Throwable ex) { System.out.println("조언을 던진 후 실행 중입니다! 예외: " + ex.getMessage()); } //서라운드 알림 public Object aroundAdvice(ProceedingJoinPoint JoinPoint)는 Throwable {를 발생시킵니다. System.out.println("주변 조언: 메소드 실행 전"); 개체 결과 = null; 노력하다 { 결과 = JoinPoint.proceed(); } 마지막으로 { System.out.println("주변 조언: 메소드 실행 후"); } 결과 반환; } }
2.4 구성 XML
Spring
마지막으로 구성 파일 에서 applicationContext.xml
위와 관련된 내용을 bean
구성 해야 합니다 .AOP
applicationContext.xml:
<?xml version="1.0" 인코딩="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-인스턴스" 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.xsd"> <!-- 위는 XML 파일의 헤더 선언으로 파일의 버전과 인코딩 유형을 정의하고 Spring Bean과 AOP의 네임스페이스를 소개합니다. 이러한 네임스페이스를 통해 XML에서 <bean> 및 <aop:*> 태그를 사용할 수 있습니다. --> <!-- 빈 정의 --> <bean id="myService" class="com.example.demo.aop.MyServiceImpl"/> <bean id="myAspect" class="com.example.demo.aop.MyAspect"/> <!-- AOP 구성--> <aop:구성> <!-- 측면과 알림 정의 --> <aop:aspect id="myAspectRef" ref="myAspect"> <!-- 포인트컷을 정의하고 메소드가 실행될 때 트리거되어야 하는 알림을 지정합니다 --> <aop:pointcut id="serviceOperation" 표현="execution(* com.example.demo.aop.MyService.performAction(..))"/> <!-- 사전 알림 적용, 메소드 실행 전 작업 지정 --> <aop:before method="beforeAdvice" pointcut-ref="serviceOperation"/> <!-- 사후 알림 적용, 메서드 실행 후 작업 지정, 메서드 실행 성공 여부 또는 예외 발생 여부 --> <aop:after method="afterAdvice" pointcut-ref="serviceOperation"/> <!-- 애플리케이션 반환 후 알림, 지정된 메서드 이후의 작업이 성공적으로 실행되어 반환됨 --> <aop:after-returning method="afterReturningAdvice" pointcut-ref="serviceOperation" return="retVal"/> <!-- 애플리케이션 예외 이후 알림, 지정된 메서드 이후의 작업에서 예외가 발생함 --> <aop:after-throwing method="afterThrowingAdvice" pointcut-ref="serviceOperation" throw="ex"/> <!-- 메소드 실행 전후에 완전한 제어를 제공하기 위해 주변 알림을 적용합니다 --> <aop:around method="aroundAdvice" pointcut-ref="serviceOperation"/> </aop:측면> </aop:구성> </beans>
myService : 이것은 비즈니스 로직이며 클래스의 인스턴스를 bean
가리킵니다 .MyServiceImpl
myAspect : 이것은 클래스의 인스턴스를 bean
가리키는 관점입니다.MyAspect
<aop:config>
: 이것은 AOP
구성의 루트 요소입니다. AOP
측면 정의, 포인트컷 및 알림 방법을 포함한 모든 구성은 이 요소 내에 정의되어야 합니다.
Aspect : <aop:aspect>
요소를 통해 정의되며 일련의 조언( advice
)과 하나 이상의 포인트컷( pointcut
)을 포함합니다. 이 요소는 측면 클래스(알림 로직을 포함하는 클래스)를 특정 작업(대상 개체를 향상시키는 방법 및 시기)과 연결합니다.
Pointcut : <aop:pointcut>
요소 정의를 통해 pointcut은 실행 시 알림을 트리거할 메서드를 정확하게 제어해야 하는 경우 pointcut을 정의해야 합니다. 포인트컷 표현식은 메소드 이름, 매개변수 유형, 주석 등으로 메소드를 매우 정확하게 지정할 수 있습니다. expression
이는 포인트컷의 표현식을 정의하고 포인트컷의 일치 규칙을 지정합니다. 여기서 표현은 execution(* com.example.demo.aop.MyService.performAction(..))
포인트컷이 MyService
인터페이스의 메소드 실행과 일치 performAction
하고 포인트컷이 Join Point
알림이 적용되는 연결 지점(예: 메소드 호출)을 지정하는 데 사용된다는 것을 의미합니다.
표현식 구문 분석 정보execution(* com.example.demo.aop.MyService.performAction(..))
실행 : 가장 일반적으로 사용되는 포인트컷 함수로, 메서드 실행의 연결 지점을 일치시키는 데 사용됩니다.
*: 메소드의 반환 유형이 임의임을 나타냅니다.
com.example.demo.aop.MyService.performAction : 인터페이스 이름과 메소드 이름의 전체 경로를 지정합니다.
(…) : 메소드 매개변수가 임의적이며 메소드에 있는 매개변수 수에 관계없이 일치함을 나타냅니다.
-
조인포인트(Join Point) : 조인포인트는 메소드 호출 등 프로그램 실행 중 특정 지점을 말한다. 조인 포인트는 명시적인 조인 포인트 집합, 즉 인터페이스 메서드의 모든 호출을 지정하는 포인트컷을 정의하는 pointcut( ) 표현식으로
Pointcut
식별되고 일치됩니다 . 이 예에서 인터페이스 메서드 호출은 잠재적인 연결 지점입니다. 메소드가 호출될 때 마다 조인 포인트에 도달합니다 . 이 연결 지점은 애플리케이션에 타이밍이 통보되는 곳입니다.execution(* com.example.demo.aop.MyService.performAction(..))
MyService
performAction
MyService
performAction
performAction
-
Advice
AOP
: 특정 시간에 액션을 수행하여 메소드의 실행력을 향상시키는 액션 입니다 .method
속성은 위에 정의된 포인트컷을 참조하여 포인트컷이 일치할 때 실행되어야 하는 관점의 메서드 이름을 지정합니다pointcut-ref
. 예를 들어beforeAdvice
대상 메서드가 실행되기performAction
전에 호출되는 메서드 는 다음과 같습니다. 즉,MyService.performAction(..)
메소드가 호출될 때마다beforeAdvice
해당 메소드가 먼저 실행됩니다.
한 문장으로 요약하면: Spring AOP
특정 방법을 향상시키기 위한 시기(연결 지점)와 방법(알림)을 지정하는 측면에서 규칙(컷 포인트)을 정의함으로써 원래 비즈니스 로직을 수정하지 않고도 코드의 모듈화 및 관심사 분리가 달성됩니다. .
이러한 방식으로 Spring AOP
원래 비즈니스 논리 코드를 수정하지 않고도 특정 메서드 실행 전후 또는 실행 전후에 삽입할 사용자 지정 논리를 정의할 수 있습니다. 이는 특히 애플리케이션의 여러 부분(예: 로깅, 트랜잭션 관리 등)에 걸쳐 있는 교차 관심사의 경우 관심사 분리를 달성하기 위한 강력한 메커니즘입니다.
<aop:config>
다음으로 설정 하면 참고하세요.
<aop:config 프록시-대상-클래스="true"> <!--다른 구성은 변경되지 않습니다--> </aop:구성>
이를 설정하면 대상 개체가 인터페이스를 구현하더라도 프록시가 기본적으로 사용됩니다 proxy-target-class="true"
. 기본적으로 속성을 설정할 필요가 없으며, 설정한 경우 동적 프록시가 사용됩니다 .Spring AOP
CGLIB
proxy-target-class
false
JDK
주요 프로그램:
DemoApplication.java:
패키지 com.example.demo; import com.example.demo.aop.MyService; org.springframework.context.support.ClassPathXmlApplicationContext 가져오기; 공개 클래스 DemoApplication { 공개 정적 무효 메인(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); MyService myService = (MyService) context.getBean("myService"); 노력하다 { System.out.println(myService.performAction("normal")); } 잡기(예외 e) { e.printStackTrace(); } System.out.println("======================="); 노력하다 { System.out.println(myService.performAction("throw")); } 잡기(예외 e) { System.out.println("메인에서 예외 발생: " + e.getMessage()); } context.close(); } }
작업 결과:
AOP
동적 프록시 기술과 이러한 개념을 결합하면 Spring AOP
애플리케이션에 방해가 되지 않는 방식으로 교차 관심사에 대한 지원이 제공될 수 있으므로 개발자는 이러한 관심사를 모듈화하고 비즈니스 논리 구성 요소를 집중적이고 단순하게 유지할 수 있습니다.
동적 프록시에 관심이 있다면 다시 디버깅할 수 있습니다. 여기서 동적 프록시 는 디버깅이 다음과 같이 구현되어 있기 JDK
때문입니다 .public class MyServiceImpl implements MyService
여기서 볼 수 있는 주요 클래스와 인터페이스에 대해 간략하게 이야기해보겠습니다.
ProxyFactorySpring AOP
: 프록시 객체를 생성하는 데 사용되는 팩토리 클래스 입니다 . 대상 개체가 인터페이스를 구현하는지 여부에 따라 JDK
동적 프록시 또는 프록시를 사용할지 결정할 수 있습니다 CGLIB
.
AopProxy : 이 인터페이스는 프록시 객체를 얻기 위한 메서드를 정의합니다. 여기에는 JdkDynamicAopProxy
( JDK
동적 프록시의 경우) 및 CglibAopProxy
( CGLIB
프록시의 경우) 라는 두 가지 주요 구현이 있습니다 .
JdkDynamicAopProxy : AopProxy
인터페이스를 구현하고 JDK
동적 프록시 기술을 사용하여 프록시를 생성합니다. 인터페이스를 구현 InvocationHandler
하고 프록시 객체에 대한 모든 메서드 호출을 가로챕니다.
CglibAopProxyAopProxy
: 인터페이스 도 구현 하지만 CGLIB
라이브러리를 사용하여 프록시 개체를 만듭니다. 인터페이스를 구현하지 않는 클래스의 경우 Spring
이 메서드를 선택하여 프록시를 생성합니다.
Spring AOP
소스 코드를 심층적으로 이해하려면 이 두 클래스의 구현을 JdkDynamicAopProxy
직접 볼 수 있습니다. CglibAopProxy
이는 이 기사의 초점이 아니며 간단히 언급하면 다음과 같습니다.
예를 들어 JdkDynamicAopProxy
다음에서 동적 프록시 구현을 참조하세요.
-
JdkDynamicAopProxy
클래스는 동적 프록싱의 핵심InvocationHandler
인 인터페이스를 구현합니다.JDK
해당invoke
메서드에는 통화를 가로채야 하는지 여부를 결정하는 논리가 있으며 해당 알림은 통화 전후에 적용됩니다. -
프록시를 생성하는 프로세스는 주로 구성 에 따라 인스턴스를 반환하는 메서드를
ProxyFactory
호출하여 수행됩니다 .createAopProxy()
JdkDynamicAopProxy
CglibAopProxy
-
프록시 사용: 클라이언트 코드는
ProxyFactory
프록시 객체를 획득하고 이 프록시 객체를 통해 대상 메서드를 호출합니다. 프록시 개체는JdkDynamicAopProxy
또는 내부적으로CglibAopProxy
이러한 호출을 가로채고AOP
구성에 따라 알림을 수행합니다.ProxyFactory
프록시 객체를 얻는 프로세스Spring
는 일반적으로 구성 및 사용에서 암시적으로 수행되며, 특히Spring
컨테이너 관리를 사용할 때 더욱 그렇습니다AOP
. 이 프로세스에서는 개발자가ProxyFactory
클래스를 직접 호출할 필요가 없습니다.Spring
구성에 측면이 정의 되고bean
측면이 적용되면Spring
컨테이너는 에이전트 생성 및 알림 적용 프로세스를 자동으로 처리합니다. 이는Spring
후처리기와 네임스페이스 지원을 통해 달성되며AOP
개발자는 일반적으로 측면과 조언을 선언적으로 구성하기만 하면 됩니다.
CGLIB
상담원 2
을 보고 싶다면 여기 방법이 있어요
세 번째 방법은 구현된 인터페이스를 1
제거한 다음 기본 프로그램과 표현식 사이의 해당 위치를 변경하는 것입니다 . 세 번째 방법은 이를 달성하기 위해 구성 파일에서 레이블의 속성을 명시적으로 설정하는 것입니다. 다음과 같이:MyServiceImpl
MyService
expression
MyServiceImpl
2
Spring
<aop:config>
proxy-target-class="true"
<aop:config 프록시-대상-클래스="true"> <!--다른 구성은 변경되지 않습니다--> </aop:구성>
디버깅은 다음과 같습니다.
원클릭 삼중접속을 환영합니다~
궁금하신 점은 메시지를 남겨주시면 함께 토론하고 배워보도록 하겠습니다.
RustDesk는 만연한 사기로 국내 서비스 Taobao(taobao.com)를 중단하고 웹 버전 최적화 작업을 재개했으며 Apple은 M4 칩을 출시했으며 고등학생들은 성인식으로 자신의 오픈 소스 프로그래밍 언어를 만들었습니다. 네티즌들은 다음과 같이 논평했습니다. 변호인인 Yunfeng은 Alibaba에서 사임했으며 향후 Windows 플랫폼의 Visual Studio Code 1.89를 독립 게임 프로그래머를 위한 대상인 Huawei에 의해 공식적으로 발표되었습니다. Yu Chengdong의 직업 조정은 "FFmpeg Pillar of Shame"에 포함되었습니다. ” 15년 전, 오늘 그는 우리에게 감사해야 합니다. Tencent QQ Video가 이전의 수치심을 복수한다고요? 화중과기대학교 오픈소스 미러 스테이션이 외부 네트워크 접속에 공식적으로 개방되었습니다.