English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
retrofit는 매우 높은 결합성을 가진 네트워크 요청 프레임워크입니다. 최근 연구 중에 매우 강력하고 실용적인 기술인 동적 대리자를 발견했습니다. 이 기사는 retrofit의 전제 지식으로서, 동적 대리자가 어떤 적용 시나리오가 있고, 동적 대리자는 무엇인지, 어떻게 사용하며, 그 제한성이 어디에 있는지에 대해 설명할 것입니다.
동적 대리의 적용 시나리오
1. AOP - 방향성 프로그래밍, 프로그램 결합 해소
간단히 말해, 특정 클래스의 내부 메서드에 대해 실행 전 후 일반적인 작업을 수행하고, 메서드 내에서 개별적인 작업을 수행하고자 할 때--동적 대리를 사용하면 업무량이 많을 때 코드량을 줄이고 유지보수성을 높일 수 있습니다.
2. 제3자 라이브러리의 일부 메서드를 정의하려고 합니다
제가 참조한 제3자 라이브러리의 일부 메서드가 제 요구사항을 충족하지 않으므로, 이 메서드를 다시 작성하거나 메서드 전후에 특정 작업을 추가하고 싶습니다--동적 대리를 사용하되, 이 메서드들이 제한적이라는 점을 주의하세요. 나중에 설명하겠습니다.
동적 대리는 무엇인가요
이 그림은 너무 추상적이므로, 우리는 일상의 예제에서 시작해 보겠습니다.
대房东(대리인)이 되어 많은 집을 임대하고, 임대인을 찾는 것이 어렵고 자신이 직접 처리하고 싶지 않으면 대리인을 고용하여 이를 관리하는 사람이 있습니다. 이 사람(대리인 또는 중개인)은 집을 임대할 때에 대해 중개 수수료를 부과합니다(집 임대에 대한 추가 작업). 임대인에게는 중개인이 주인이며, 대리인을 통해 일부 작업을 수행합니다.
위와 같이, 이는 대리의 예입니다. 그리고 왜 "동적"이라고 불리는지, "동적"이라는 두 글자가 어디에 반영되는지?
이렇게 생각해 보세요, 각 집에 대리인을 고용해 관리하면 새로운 집을 임대할 때마다 새로운 대리인을 고용해야 하므로 많은 대리인을 고용해야 하고, 높은 중개 비용이 발생합니다. 이는 일반적으로 "정적 대리"로 알려져 있습니다.
하지만 모든 집을 중개인에게 맡겨 다양한 집 간에 동적으로 역할을 바꿔 고객을 대신해 주는 경우가 있습니다. 이는 "동적 대리" 과정입니다. 동적 대리의 큰 특징은 컴파일 단계에서 대리 클래스가 실행 시에만 생성된다는 것입니다.
이제 일부 코드를 통해 확인해 보겠습니다
주택 임대의 작업
/** *의존 인터페이스 정의 **/ public interface RentHouse { void rent();//주택 임대 void charge(String str);//임대료 수수료 청구 }
사용자
public class HouseOwner implements RentHouse { public void rent() { System.out.println("I want to rent my house"); } public void charge(String str) { System.out.println("You get : ") + str + "RMB HouseCharge."); } }
중개업체
public class DynamicProxy implements InvocationHandler { // 이것은 우리가 대리할 실제 객체입니다. 즉, 사이쿼트. private Object subject; // 생성자, 대리할 실제 객체에 초기 값을 부여합니다. public DynamicProxy(Object subject) { this.subject = subject; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 실제 객체를 대리하기 전에 우리의 추가적인 작업을 추가할 수 있으며, 중개료를 받습니다. System.out.println("before "+method.getName()+" house"); System.out.println("Method:") + method.getName()); // 만약 메서드가 charge라면 중개료를 받습니다.100 원 중개료. if (method.getName().equals("charge")) { method.invoke(subject, args); System.out.println("I will get 100 RMB ProxyCharge."); } else { // 프로xor 객체가 실제 객체의 메서드를 호출할 때, 자동으로 프로xor 객체와 연결된 handler 객체의 invoke 메서드로 이동하여 호출됩니다. method.invoke(subject, args); } // 실제 객체를 대리한 후에도 우리의 추가적인 작업을 추가할 수 있습니다. System.out.println("after "+method.getName()+" house"); return null; } }
고객
public class Client { public static void main(String[] args) { // 우리가 대리할 실제 객체--사용자 HouseOwner houseOwner = new HouseOwner(); // 우리가 대리할 실제 객체는 그 객체를 넣고 마지막으로는 실제 객체를 통해 메서드를 호출합니다. InvocationHandler handler = new DynamicProxy(houseOwner); /* * Proxy의 newProxyInstance 메서드를 사용하여 우리의 프로xor 객체를 생성해보겠습니다. 그 세 가지 매개변수를 확인해보겠습니다. * 첫 번째 매개변수 handler.getClass().getClassLoader()는, 여기서는 handler 클래스의 ClassLoader 객체를 사용하여 프록시 객체를 로드합니다 * 두 번째 매개변수 realSubject.getClass().getInterfaces()는, 여기서는 프록시 객체에 제공하는 인터페이스는 실제 객체가 실행하는 인터페이스입니다. 이렇게 하면 실제 객체를 프록시로 대체할 수 있으며, 이 인터페이스의 메서드를 호출할 수 있습니다 * 세 번째 매개변수 handler는, 여기서는 이 프록시 객체를 위상의 InvocationHandler 객체에 연결했습니다 */ RentHouse rentHouse = (RentHouse) Proxy.newProxyInstance(handler.getClass().getClassLoader(), houseOwner .getClass().getInterfaces(), handler);//동적 프록시 클래스, 중개자 System.out.println(rentHouse.getClass().getName()); rentHouse.rent(); rentHouse.charge("10000"); } }
출력을 확인해 보겠습니다
com.sun.proxy.$Proxy0 before rent house 메서드:rent 저는 저의 집을 빌려주고 싶습니다 after rent house before charge house 메서드:charge 당신이 받는 것은 : 10000 RMB HouseCharge. I will get 100 RMB ProxyCharge. after charge house 프로세스가 종료되었습니다. 종료 코드 0
before rent house 및 after rent house가 출력되면, 메서드의前后에 작업을 추가할 수 있다는 것을 의미합니다. 또한, I will get 출력을 보면 100 RMB ProxyCharge. 중개자가 수취했습니다100 원의 중개 수수료는 우리가 작업을 추가할 수 있다는 것뿐만 아니라, 이 메서드를 대체하거나 그 실행을 직접 중단할 수 있다는 것을 의미합니다.
코드를 처음 보면 많은 의문이 있을 수 있습니다. 다음 내용을 통해 동적 프록시를 어떻게 사용하는지 확인해 보겠습니다.
동적 대리를 사용하는 방법
Java의 동적 대리 메커니즘에서 두 가지 중요한 클래스와 인터페이스가 있습니다. 하나는 InvocationHandler(인터페이스)와 다른 하나는 Proxy(Class)입니다. 이 두 클래스와 인터페이스는 동적 대리를 구현하기 위해 필요합니다.
모든 동적 대리 클래스는 InvocationHandler 인터페이스(코드의 중재자)를 구현해야 하며, 각 대리 클래스의 인스턴스는 handler와 연결됩니다. 대리 객체를 통해 메서드를 호출하면, 이 메서드 호출은 InvocationHandler 인터페이스의 invoke 메서드(메서드의 강화는 여기서 작성됩니다)를 통해 전달됩니다.
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
이 메서드는 총 세 가지 매개변수를 받습니다. 이 세 가지 매개변수는 무엇을 의미할까요?
Object invoke(Object proxy, Method method, Object[] args) throws Throwable //proxy: 대리하는 실제 객체를 의미합니다 //method: 호출할 실제 객체의 메서드를 나타내는 Method 객체를 의미합니다 //args: 호출할 실제 객체의 메서드에 전달할 매개변수를 의미합니다
이제 Proxy 클래스를 살펴보겠습니다
public static Object newProxyInstance(ClassLoader loader, Class<63;][] interfaces, InvocationHandler h) throws IllegalArgumentException
Proxy 클래스는 동적 대리 객체를 생성하기 위해 사용되는 클래스입니다. 많은 메서드를 제공하지만, 가장 많이 사용하는 메서드는 newProxyInstance입니다:
public static Object newProxyInstance(ClassLoader loader, Class<63;][] interfaces, InvocationHandler h) throws IllegalArgumentException
이 메서드의 역할은 동적 대리 객체를 얻는 것입니다. 세 가지 매개변수를 받습니다. 이 세 가지 매개변수가 나타내는 의미를 살펴보겠습니다
public static Object newProxyInstance(ClassLoader loader, Class<63;][] interfaces, InvocationHandler h) throws IllegalArgumentException //loader: 생성된 대리 객체를 로드할 ClassLoader 객체를 정의합니다 //interfaces: Interface 객체 배열, 제공할 대리 객체에 제공할 인터페이스 집합을 나타냅니다. 인터페이스 집합을 제공하면 대리 객체가 해당 인터페이스를 구현했다고 주장하고, 이렇게 하면 인터페이스 메서드를 호출할 수 있습니다(다형성) //h: InvocationHandler 객체, 이는 이 동적 대리 객체가 메서드를 호출할 때, 어떤 InvocationHandler 객체와 연결될 것인지를 나타냅니다.
이렇게 되면, 위에서 제공된 코드와 결합하여, 이동적 대리자의 사용 방법을 이해할 수 있습니다.
이동적 대리자의 제한성
이동적 대리자의 사용 방법에서, 실제로 강화될 수 있는 메서드는 인터페이스를 구현한 것이며(인터페이스를 구현하지 않은 public 메서드는 대리 클래스를 상속하여 사용할 수 있습니다), 코드에서 HouseOwner가 RentHouse를 상속했습니다. 하지만, private 메서드는 JDK의 이동적 대리자는 무력합니다!
위의 이동적 대리자는 JDK의 것이지만, java 프로젝트에는 유명한 CGLib도 있습니다. 그러나遗憾的是, CGLib은 android에서 사용할 수 없으며, android 가상 기계는 JVM과 차이가 있습니다.
결론
이동적 대리자의 사용场景은 이들만이 아닙니다. 내부 원리는 미래의 기사에서 소개할 것입니다. 하지만, 애플리케이션 클래스가 반영된 임시 대리자 클래스 생성 메커니즘은 성능에 영향을 미칠 것입니다. 이 문서는 retrofit 원리의 전신 기사로, 매우 자세하지 않습니다. 오류나 부족한 부분이 있으면, 지적해 주시기 바랍니다!
이것이 이 문서의 전체 내용입니다. 여러분의 학습에 도움이 되길 바라며, 많이 응원해 주시길 바랍니다.
고지사항: 이 문서의 내용은 인터넷에서 수집되었으며, 저작권자가 소유하고 있으며, 인터넷 사용자가 자발적으로 기여하고 업로드한 내용입니다. 이 사이트는 소유권을 가지지 않으며, 인공 편집 처리를 하지 않았으며, 관련 법적 책임을 부담하지 않습니다. 저작권 침해가 의심되는 내용을 발견하면, notice#w로 이메일을 보내 주시기 바랍니다.3codebox.com(댓글을 달 때는 #을 @으로 바꿔서 신고해 주시고, 관련 증거를 제공해 주시면, 실제로 확인되면, 이 사이트는 즉시 저작권 침해 내용을 제거할 것입니다。