Spring 사용자 정의 주석 이 유효 하지 않 은 원인 분석 및 해결 방법
배경:
프로젝트 에 서 는 spring AOP 를 기반 으로 자바 캐 시 주 해 를 실 현 했 습 니 다.그러나 최근 한 가지 상황 이 발생 했다. 캐 시가 효력 이 발생 하지 않 았 고 대량의 요청 이 db 층 에 뚫 려 서 db 의 압력 이 너무 크다.지금 우 리 는 구체 적 인 코드 상황 을 살 펴 보 자.
interface A {
int method1(..);
int method2(..);
... ...
}
class AImpl implements A {
@Override
@CacheMM(second=600) // @CacheMM
public int method1(..) {
... ...
method2(..);
... ...
}
@Override
@CacheMM(second=600)
public int method2(..) {
... ...
}
}
위의 코드 와 같이 method 1 을 호출 할 때 method 2 주석 이 유효 하지 않 음 을 발견 합 니 다.
분석:
왜 그 럴 까요?서 두 르 지 마라, 우 리 는 이 문 제 를 가지 고 주해 의 실현 류 를 보 러 갔다.(여 기 는 캐 시 주해 의 실현 코드 를 붙 이지 않 습 니 다) 제 사용자 정의 주 해 는 extends AbstractBean Factory PointcutAdvisor 류 를 직접 확장 한 다음 에 getPointcut () 과 getAdvice () 를 실현 합 니 다.(사실 여 기 는 op 서 라운드 알림 을 직접 사용 할 수 있 습 니 다. 원리 가 많 지 않 습 니 다. 저 는 소스 코드 를 익히 기 위해 이렇게 썼 습 니 다)
그 다음 에 우 리 는 계속 분석 을 해 보 았 습 니 다. 우 리 는 spring op 을 바탕 으로 하 는 주 해 를 알 고 있 습 니 다. spring 에서 op 이 실현 되면 용 기 는 이러한 대리 류 를 주입 합 니 다. 이곳 의 대리 류 는 op 동적 대리 가 생 성 하 는 대리 류 입 니 다.Spring op 의 동적 대 리 는 두 가지 가 있 습 니 다. 하 나 는 jdk 의 동적 대리 이 고 하 나 는 CGLIB 를 바탕 으로 합 니 다.이 두 가지 차 이 는 더 이상 말 하지 않 겠 습 니 다. 만약 당신 의 업무 유형 이 인터페이스 에 기반 하여 이 루어 진다 면 jdk 동적 대 리 를 사용 하 십시오. 그렇지 않 으 면 CGLIB 동적 대 리 를 사용 합 니 다.내 가 여기 서 사용 하 는 것 은 인터페이스 실현 이기 때문에 우 리 는 생각 을 따라 jdk 동적 대리 의 구체 적 인 실현 을 살 펴 보 자.
위의 업무 코드 류 를 나 는 이미 붙 였 다.프 록 시 대상 (proxy) 을 만 들 고 두 단계 로 나 누 어야 합 니 다.
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class AProxy implements InvocationHandler
{
private Object target;
/**
* , .
* @param target
* @return */
public Object bind(Object target)
{
this.target = target;
// , .
Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(), //
target.getClass().getInterfaces(), // ,
this);// ,this , InvocationHandler invoke
return proxy;
}
/**
* , AProxy , 。
* @param proxy
* @param method
* @param args
* @return 。
* @throws Throwable */
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
System.err.println(" ");
Object obj = method.invoke(target, args);// AImpl .
System.err.println(" ");
return obj;
}
}
코드 에 서 는 Object obj = method. invoke (target, args) 가 실제 대상 을 반사 적 으로 스케줄 링 하 는 방법 이 중요 합 니 다.우 리 는 사실 op 이 대리 대상 을 통 해 추가 적 인 조작 을 실현 하지만 진정한 방법 으로 호출 하 는 것 은 실제 대상 을 반사 적 으로 호출 하 는 것 임 을 알 고 있다.이때 우 리 는 문 제 를 돌 이 켜 보 았 다. 우리 AImpl 에는 두 가지 방법 이 있 는데 그 중에서 method 2 는 method 1 내부 에서 호출 된 것 이다.method 1 을 호출 할 때 spring 내 부 는 에이전트 류 AProxy 류 의 invoke 를 호출 합 니 다. 이 때 실제 대상 방법 돈 을 실행 하여 method 1 의 추가 작업 을 수행 합 니 다.그리고 반 사 를 통 해 대응 하 는 AImpl 류 에 들 어가 method 1 방법 을 호출 합 니 다.이 때 는 프 록 시 대상 에서 작 동 하지 않 습 니 다. method 2 의 호출 은 method 1 내부 에서 호출 되 었 기 때문에 여기 서 실제 method 2 를 호출 하 는 것 은 실제 대상 이지 프 록 시 대상 이 아 닙 니 다.따라서 method 2 의 캐 시 주석 이 유효 하지 않 습 니 다.
해결:
자, 이제 문제 의 원인 을 알 게 된 후에 (동적 대리 의 구덩이 야, 내부 호출 이 대리 류 를 가지 지 않 기 때문에 실 현 된 부가 작업 은 반드시 실행 되 지 않 을 것 이다) 우 리 는 목적 성 있 게 해결 할 것 이다.우 리 는 지금 이것 이 실제 실 행 된 것 이 대리 류 가 아니 기 때문에 발생 한 것 이라는 것 을 알 고 있다. 그러면 우리 가 해결 하 는 방향 은 method 2 의 대리 류 를 호출 시 키 면 된다.(이렇게 간단 하 다)
AProxy 류 는 spring 용기 에서 얻 을 수 있 습 니 다.다음은 수 정 된 해결 방안 입 니 다.
method1(..) {
... ...
// , , ,
if(null != AopContext.currentProxy()){
AopContext.currentProxy().method2();
}else{
method2();
}
}
이곳 의 AopContext. currentProxy () 가 받 은 것 은 실제 대리 대상 입 니 다. 이렇게 하면 대리 대상 을 통 해 method 2 를 호출 하 는 데 문제 가 없 을 것 입 니 다.
또 하나의 해결 방법 은 동적 프 록 시 를 사용 하지 않 고 aspectJ 를 사용 하여 짜 는 것 이다. aspectJ 는 프 록 시 방식 이 아니 라 소스 클래스 에 바이트 코드 를 직접 삽입 하 는 것 이다.
여기 서 AspectJ 컴 파일 시 짜 기 (Compile Time Weaving, CTW) 를 참고 할 수 있 습 니 다.
이렇게 바 꾸 는 것 이 비교적 크기 때문에, 현재 나 는 여전히 첫 번 째 방안 을 채택 하여 문 제 를 해결 하 였 다.이로써 문 제 는 해결 되 었 다.
요약:
Spring op 동적 에이전트 의 실현 원 리 를 결합 하여 두 가지 동적 대 리 를 제공 합 니 다: JDK 대리 와 CGLIB 대리
JDK 에이 전 트 는 인 터 페 이 스 를 실현 한 클래스 만 생 성 할 수 있 을 뿐 클래스 를 대상 으로 할 수 없습니다.CGLIB 는 클래스 에 대해 대 리 를 수행 하 는 것 으로 지 정 된 클래스 에 하위 클래스 를 생 성하 고 덮어 쓰 는 방법 이 며, 계승 이기 때문에 final 로 클래스 나 방법 을 수식 할 수 없다.그래서 이런 종류 나 방법 은 final 로 밝 히 지 않 는 게 좋 을 것 같 아 요.
더 상세 한 설명 은 이 박문 에서 어떤 방법 으로 Spring AOP 업 무 를 실시 할 수 없 는 지 참고 할 수 있다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.