프 록 시 모드 의 자바 동적 프 록 시 실현 방법
package com.yixi.proxy;
public interface UserService {
public int save() ;
public void update(int id);
}
실현 클래스:UserService Impl.java
package com.yixi.proxy;
public class UserServiceImpl implements UserService {
@Override
public int save() {
System.out.println("user save....");
return 1;
}
@Override
public void update(int id) {
System.out.println("update a user " + id);
}
}
그리고 성급 하 게 자신 이 원 하 는 Invocation Handler 를 적 었 습 니 다.이 기능 은 간단 한 것 은 방법 이 실 행 된 시작 시간 과 종료 시간 을 기록 하 는 것 입 니 다.TimeInvocation Handler.java
package com.yixi.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class TimeInvocationHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("startTime : " +System.currentTimeMillis());
Object obj = method.invoke(proxy, args);
System.out.println("endTime : " +System.currentTimeMillis());
return obj;
}
}
의 모든 준비 작업 을 기록 하 는 것 입 니 다.다 됐 으 니까 테스트 시작 해 야 지!Test.java
package com.yixi.proxy;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args) { 9 TimeInvocationHandler timeHandler = new TimeInvocationHandler();
UserService u = (UserService) Proxy.newProxyInstance(UserServiceImpl.class.getClassLoader(), UserServiceImpl.class.getInterfaces(), timeHandler);
u.update(2);
u.save();
}
}
는 즐겁게 Run 을 했 지만,당신 의 체면 을 세 워 주지 않 았 습 니 다.결 과 는 화면 에 가득 찬 이상 이 었 습 니 다.
startTime : 1352877835040
startTime : 1352877835040
startTime : 1352877835040
Exception in thread "main" java.lang.reflect.UndeclaredThrowableException
at $Proxy0.update(Unknown Source)
at com.yixi.proxy.Test.main(Test.java:11)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.yixi.proxy.TimeInvocationHandler.invoke(TimeInvocationHandler.java:12)
... 2 more
com.yixi.proxy.TimeInvocation Handler.invoke(TimeInvocation Handler.java:12)는 TimeInvocation Handle 의 12 줄 에 있 는 문 제 를 명확 하 게 알려 주 었 습 니 다.즉,
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("startTime : " +System.currentTimeMillis());
Object obj = method.invoke(proxy, args);
System.out.println("endTime : " +System.currentTimeMillis());
return obj;
}
방법 으로 볼 때 틀린 것 이 없 었 습 니 다!invoke()라 는 방법 에 method.invoke(Object,Object[])가 원 하 는 모든 인 자 를 제공 한 것 같 기 때문에 우 리 는 당연히 그것 을 사용 해 야 합 니 다.그렇게 생각한다 면 JDK 의 함정 에 빠 질 것 입 니 다.먼저 정확 한 쓰 기 를 보 세 요.어떤 학생 들 이 뒤의 것 을 볼 기분 이 나 지 않도록 정확 한 해법 을 주 십시오.TimeInvocation Handler.java
package com.yixi.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class TimeInvocationHandler implements InvocationHandler {
private Object o;
public TimeInvocationHandler(Object o){
this.o = o;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("startTime : " +System.currentTimeMillis());
Object obj = method.invoke(o, args);
System.out.println("endTime : " +System.currentTimeMillis());
return obj;
}
}
를 수정 하고 Test.java
package com.yixi.proxy;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args) {
TimeInvocationHandler timeHandler = new TimeInvocationHandler(new UserServiceImpl());
UserService u = (UserService) Proxy.newProxyInstance(UserServiceImpl.class.getClassLoader(), UserServiceImpl.class.getInterfaces(), timeHandler);
u.update(2);
u.save();
}
}
를 수정 하 는 것 은 현재 정확 한 출력 결과 입 니 다.
startTime : 1352879531334
update a user 2
endTime : 1352879531334
startTime : 1352879531334
user save....
endTime : 1352879531335
코드 가 적 으 려 면 익명 류 를 직접 쓸 수 있 습 니 다.package com.yixi.proxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class Test { public static void main(String[] args) { final UserServiceImpl usi = new UserServiceImpl(); UserService u = (UserService) Proxy.newProxyInstance( usi.getClass().getClassLoader(), usi.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("startTime : " +System.currentTimeMillis()); Object obj = method.invoke(usi, args); System.out.println("endTime : " +System.currentTimeMillis()); return obj; } }); u.update(2); u.save(); }}method.invoke(target,args);첫 번 째 인 자 는 대상 에 들 어 가 는 것 입 니 다.그러면 invocation Handler 의 Invoke 방법 은 Object proxy 인 자 를 왜 원 하 십 니까?그냥 내 려 다 봐!가장 중요 한 invoke 라 는 방법 에 대해 서 는 JDK 가 어떻게 말 하 는 지 살 펴 보 겠 습 니 다.
invoke
Object invoke(Object proxy,
Method method,
Object[] args)
throws Throwable 。 , 。
:
proxy -
method - Method 。Method , 。
args - , , null。 ( java.lang.Integer java.lang.Boolean) 。
proxy-그 위 에서 호출 하 는 방법의 프 록 시 인 스 턴 스?이 말 이 무슨 뜻 이 죠?대리method 는 대리 방법 입 니까?그럼 제 가 프 록 시 를 수행 하 는 method 는 Object obj=method.invoke(proxy,args)가 아 닙 니 다.그렇습니까?당시 에 나 도 모퉁이 를 돌 지 않 았 다.토론 군 에 가서 구 글 에 가도 영감 을 찾 지 못 했다.생각해 보 니 이것 이 소스 코드 를 보 는 것 이 좋 겠 다.아마도 뭔 가 를 볼 수 있 을 것 이다!Proxy 류 의 소스 코드 를 열 어 보 니 어떤 구조 방법 이 있 습 니까?
protected InvocationHandler h;
protected Proxy(InvocationHandler h) {
this.h = h;
}
Invocation Handler 를 Proxy 의 구조 방법의 매개 변수 로...그럼 Invocation Handler 는 무엇 을 해 야 합 니까?Invocation Handler 의 invoke()방법 과 무슨 연관 이 있 습 니까?제 가 제일 먼저 생각 한 것 은 Proxy 내부 에서 다음 문 구 를 호출 하 는 것 입 니 다.
h.invoke(this,methodName,args);
invoke 방법 을 사용 해 야 해당 하 는 method 방법 을 실행 할 수 있 기 때 문 입 니 다.이것 부터 살 펴 보 겠 습 니 다.여기 서 약간 느낌 이 있 는 것 같 습 니 다.u.update(2)시 à Proxy 는 handler.invoke(proxy Class,update,2)à 즉 proxy Class.update(2)를 호출 합 니 다.u.save();시 à Proxy 는 handler.invoke(proxyClass,save,null)à 를 호출 합 니 다.즉,proxyClass.save()를 호출 합 니 다.
Test.java 가 이렇게 바 뀌 었 을 때:
public class Test {
public static void main(String[] args) {
final UserServiceImpl usi = new UserServiceImpl();
UserService u = (UserService) Proxy.newProxyInstance(
usi.getClass().getClassLoader(),
usi.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return null;
}
});
u.update(2);
u.save();
}
}
이때 익명 류 의 방법 이 null 로 되 돌아 오 는 것 을 주의 하 십시오.실행 해 보면
Exception in thread "main" java.lang.NullPointerException
at $Proxy0.save(Unknown Source)
at com.yixi.proxy.Test.main(Test.java:17)
17 줄 에 빈 포인터 가 있 습 니 다.바로 여기 u.save()방법 이 null 인 요소 가 있 습 니 다.u 가 비어 있 습 니까?아 닙 니 다.u 가 null 이 라면 u.update(2)는 거기에 빈 포인터 이상 을 알 립 니 다.17 줄 의 주석 을 떨 어 뜨 린 후에 이상 이 없 으 면 u.update()가 정상적으로 실 행 될 수 있 습 니 다.그럼 이 건 도대체 왜 일 까?사실은 이것 이 바로 invoke 방법 이 null 로 돌아 가 는 이유 입 니 다.UserService 류 의 두 가지 방법 을 주의 하 십시오.
public interface UserService {
public int save() ;
public void update(int id);
}
Save()방법 은 int 형 으로 돌아 가 고 update 방법 은 void 형 으로 돌아 갑 니 다.위의 추측 에 따 르 면 handler.invoke()는 proxyClass.update(2)를 실현 하 는 것 으로 추정 된다.의,invoke 방법 중의 return 방법 은 해당 하 는 프 록 시 방법의 반환 값 입 니 다.따라서 invoke 방법 이 null 로 돌아 갈 때 프 록 시 update 방법 은 반환 값 이 null 인 것 을 받 았 습 니 다.원래 void 로 돌아 가기 때문에 이상 을 보고 하지 않 았 습 니 다.프 록 시 save 는 int 형의 수 치 를 되 돌려 야 합 니 다.JVM 은 null 을 int 형 으로 바 꿀 수 없어 서 이상 을 신 고 했 습 니 다.이렇게 해석 하면 설명 이 통 하고 앞의 추측 도 상대 적 으로 증명 할 수 있 습 니 다.InvocationHandler 에서 invoke 방법 에서 첫 번 째 매개 변수 proxy 는 프 록 시 클래스 가 자신의 InvocationHandler 대상 에 게 호출 방법 을 인용 할 때 프 록 시 대상 proxyClass 의 인용 을 전송 하여 proxyClass 가 완성 해 야 할 업 무 를 완성 할 수 있 도록 하 는 것 같 습 니 다.문채 가 안 돼!능력 에 한계 가 있다!지적 해 주 셨 으 면 좋 겠 는데...
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Is Eclipse IDE dying?In 2014 the Eclipse IDE is the leading development environment for Java with a market share of approximately 65%. but ac...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.