What is dynamic proxy
The core of dynamic proxy is the proxy mode, which is divided into static proxy and dynamic proxy in practice. As for the explanation of the proxy mode, Baidu Baike said:
Definition of proxy pattern: Provides a proxy for other objects to control access to that object. In some cases, an object is inappropriate or cannot directly reference another object, and a proxy object can act as an intermediary between the client and the target object.
Using the words of code to explain, in fact, is to define an interface, the subsequent objects A and B can implement the interface and implement its abstract method, but when accessing A and B, can not directly reference A and B objects, but directly call method through the interface reference.
Static agent
em… It’s still too cumbersome to use text, so let’s use static proxies. Show me the code!
Animal.kt
interface Animal {
fun run()
}
Copy the code
RabbitProxy.kt
class RabbitProxy : Animal{
override fun run() {
println("RabbitProxy run")
}
}
Copy the code
main()
fun main() {
var animal : Animal = RabbitProxy()
animal.run()
}
Copy the code
Running results:
RabbitProxy run
Process finished with exit code 0
Copy the code
A dynamic proxy
RabbitProxy is fixed at the time of writing, whereas dynamic proxies simply generate a rabbitProxy-like object at runtime.
Dynamic proxies can be implemented in Java using the following methods:
public static Object newProxyInstance(ClassLoader loader, Class<? >[] interfaces, InvocationHandler h)Copy the code
Before explaining this method, we can look at how to use it:
/ / create the object var myObject. = the Proxy newProxyInstance (Animal: : class. Java. This, arrayOf (Animal: : class. Java), object: InvocationHandler { override fun invoke(proxy: Any? , method: Method? , args: Array<out Any>?) : Any? { println("invoke ${method? .name}") return null } }); If (myObject is Animal){myobject.run ()}Copy the code
Running results:
invoke run
Process finished with exit code 0
Copy the code
Let’s analyze this a little bit:
- MyObject created by proxy.newProxyInstance ().
- MyObject calls run().
- The Invoke method of InvocationHandler is executed.
em… How is this process so familiar?
This is the same as the anonymous inner class we normally create!!
Var myObject = object: Animal {override fun run() {println("invoke run")}} if (myObject is Animal) {myObject.run()}Copy the code
So newProxyInstance() is not that complicated. It just creates an object dynamically and provides a callback method for us to override.
public static Object newProxyInstance(ClassLoader loader, Class<? >[] interfaces, InvocationHandler h)Copy the code
- ClassLoader: Since the class is loaded by ClassLoader, we need to pass in the ClassLoader.
- Class
[] : specify which interface we want to dynamically proxy, need to be declared here. - InvocationHandler: This is the callback that calls the method generated by the dynamic proxy, which is called here.
See here, it is estimated that we all have a certain understanding of dynamic proxy, but if used in peacetime project development, can have what use?
Emulate Retrofit practices
Below, we illustrate by simulating Retrofit.
Since annotations are covered below, if you don’t already know annotations, you can read this article from handwriting ButterKnife to mastering annotations and AnnotationProcessor.
To make a web request, first we need to know the link to the request and how to request it. We set this up with two annotations:
HttpUrl.kt
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
annotation class HttpUrl(val value: String)
Copy the code
HttpMethod.kt
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
annotation class HttpMethod (val value: String)
Copy the code
Httprequest.kt storage access interface:
interface HttpRequest {
@HttpMethod("GET")
@HttpUrl("https://www.baidu.com/login")
fun login(name: String, password: String) : UserInfo
}
Copy the code
The following is the key, which is to use the dynamic proxy to call login() and output the returned UserInfo.
UserInfo is actually just a simulated access interface success, return json entity:
UserInfo.kt
data class UserInfo(var name: String)
Copy the code
As for the callback part of the dynamic proxy, I mainly get the value of the annotation and the parameter value and output it. After all, once I get the value, how to build Okhttp for network requests is not the focus of this article.
MyRetrofit.kt
class MyRetrofit { companion object{ fun <T> create(interfaces: Class<T>): T {/ / returned directly generated object return Proxy. NewProxyInstance (Animal: : class. Java. This, arrayOf (HttpRequest: : class. Java), object : InvocationHandler { override fun invoke( proxy: Any, method: java.lang.reflect.Method, args: Array<out Any> ): Any? Var httpUrl = method.getannotation (httpUrl ::class.java) var httpMethod = Method.getannotation (HttpMethod::class.java) // Print the value of the annotation println("Url link: ${httpur.value}") println(" request method: ${httpmethod.value}") ${httpmethod.value}") {parameterTypes = method.parameterTypes; ${parameters[I].name} ${args[I]}") {return UserInfo(" not myopic cat ")}} as T}}Copy the code
It’s a bit long, but that’s the core:
HttpUrl = method.getannotation (httpUrl ::class.java) var httpMethod = Method.getannotation (HttpMethod::class.java) // Print the value of the annotation println("Url link: ${httpur.value}") println(" request method: ${httpmethod.value}") ${httpmethod.value}") {parameterTypes = method.parameterTypes; ${parameters[I].name} ${args[I]}")} return UserInfo(" not myopic cat ")Copy the code
All that remains is to make the call:
Var userInfo = myretrofit.create (HttpRequest::class.java).login(" not nearsighted cat ", "123456") ${userInfo.name}")Copy the code
Run:
Url: https://www.baidu.com/login request: GET parameter types: Java. Lang. String parameter value: not myopic cat parameter types: Java. Lang. String parameter value: 123456 login successful! Non-nearsighted cat Process finished with exit code 0Copy the code
Guess you like
- Make an App that never crashes
- Custom Gradle Plugin+ bytecode staking
- From handwritten ButterKnife to mastering annotations, AnnotationProcessor
- Here, I want you to write a performance check