Retrofit의 동적 에이전트
Retrofit
는 동적 에이전트를 통해 에이전트 대상을 생성하여 네트워크 요청의 발기자로 한다.오늘 동적 에이전트가 어떻게 작동하는지 한번 봅시다.아니면 어떻게 인터페이스처럼 보이는 대상에게 추상적인 방법을 사용하게 합니까?
코드부터 볼게요.
public static void main(String[] args) {
Factory factory = new Factory();
Bird bird = factory.create(Bird.class);
bird.fly();
}
interface Bird {
void fly();
}
이 코드는 하나의
Factory
실례 호출create
방법을 통해 하나의 인터페이스에 전송된 class
대상을 하나의 인터페이스의 실례로 되돌려주고 인터페이스에 있는 방법fly()
을 호출할 수 있다.우리의 정적 코드 중 이
Bird
인터페이스를 실현한 클래스는 하나도 없다. (전체 코드는 아래를 볼 수 있다.)그렇다면 이 상대는 도대체 어디서 온 걸까?전체 코드는 다음과 같다.
public class DynamicProxy {
interface Bird {
void fly();
}
public static void main(String[] args) {
Factory factory = new Factory();
Bird bird = factory.create(Bird.class);
bird.fly();
}
static class Factory implements InvocationHandler {
public T create(Class target) {
return (T) Proxy.newProxyInstance(target.getClassLoader(),
new Class[]{target},
this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("flying...");
return null;
}
}
}
호출
bird.fly()
할 때 출력 결과flying...
는 분명히 코드에 처음에 말한 것처럼 Bird
인터페이스를 실현한 하위 클래스가 존재하지 않았고 bird
는 실제 호출fly()
방법을 사용했다.유일한 가능성은 bird
이 인터페이스의 실례(또는 인터페이스를 실현하는 하위 클래스의 대상)이다.이곳은 보기에 좀 이상한 것 같다.물론 프로그래밍에는 마법이 없다. 여기에는
Java
의 동적 에이전트만 이용했고 Proxy.newProxyInstance()
방법을 통해 지정된 인터페이스를 실현한 하위 클래스를 생성하고 이 동적 생성 클래스의 실례 대상을 되돌려주었다.이 하위 클래스는 인터페이스에서 방법을 호출할 때 사실
InvocationHandler
의invoke()
방법을 호출한다.이 방법에는 대응하는 매개 변수의 리셋이 있어 이 매개 변수에 따라 적당한 차단/강화 등의 조작을 할 수 있다.주의해야 할 점은
JDK
가 제공한 동적 에이전트이다. 동적 생성의 하위 클래스는 Proxy
류에서 계승된 것이고 Java
는 다중 계승을 지원하지 않기 때문에 분명하다.동적 에이전트를 통해 되돌아오는 대상은 반드시 인터페이스 형식으로 수신된다. 확장된 것은 인터페이스와 인터페이스를 실현하는 하위 클래스만 있고 인터페이스를 실현하지 못한 일부 클래스는 확장할 수 없다.cglib
확장 클래스 지원)이것들을 알면
Retrofit
의 동적 대리가 대체로 어떤 논리인지 알 수 있다.다음 모조
Retrofit
는 방법에 대한 주석을 통해 네트워크 요청을 모의해 봅시다.인터페이스에서 방법에 대한 설명을 통해 요청한 매개 변수를 확인합니다.그리고 프록시 대상을 만들고 방법에서 온전한
Url
,https://github.com/search?q=java
네트워크를 요청하고 응답 헤더의 Status
필드를 출력합니다.public interface Bird {
@Protocol()
@Method()
@Path("search")
@Query("q=java")
@Url("github.com")
String fly();
}
public class Test {
public static void main(String[] args) {
Factory factory = new Factory();
Bird bird = factory.create(Bird.class);
String status = bird.fly();
System.out.println(status);// Status: 200 OK
}
}
부분 코드
public class Factory implements InvocationHandler {
OkHttpClient httpClient = new OkHttpClient();
public T create(Class target) {
return (T) Proxy.newProxyInstance(target.getClassLoader(),
new Class[]{target},
this);
}
public Object invoke(Object proxy, java.lang.reflect.Method method, Object[] args) throws Throwable {
String get = method.getAnnotation(Method.class).method();
String protocol = method.getAnnotation(Protocol.class).value();
String url = method.getAnnotation(Url.class).value();
String path = method.getAnnotation(Path.class).value();
String query = method.getAnnotation(Query.class).value();
String entire_url = protocol + "://" + url + "/" + path + "?" + query;
System.out.println(entire_url);
Request build = new Request.Builder().url(entire_url).get().build();
return httpClient.newCall(build).execute().headers().get("Status");
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Method {
String method() default "GET";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Url {
String value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Protocol {
String value() default "https";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Path {
String value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Query {
String value() default "";
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.