代理的作用

通过代理方式可以对目标方法进行扩展, 添加一些自定义的逻辑或返回特定的结果

静态代理

特点

  • 根据 Java API 代理机制规定, 被代理类必须要实现某个接口
  • 代理类也需要实现相同的接口
  • 代理类持有被代理类, 代理类里实现的方法通过调用持有的被代理类的对应方法实现

    示例

    ```kotlin /**
    • 接口 */ interface IHello { fun sayHello() }

/**

  • 被代理类 */ class HelloImp : IHello { override fun sayHello() {
    1. println(">>>>> helloImp: hello <<<<<")
    } }

/**

  • 代理类 */ class HelloProxy : IHello { private val hello = HelloImp() override fun sayHello() {
    1. hello.sayHello()
    } }

/**

  • 调用方式 */ val hello = HelloProxy() hello.sayHello() ```

    动态代理

    特点

  • 根据 Java API 代理机制规定, 被代理类必须要实现某个接口
  • 动态代理类需要实现 InvocationHandler
  • 关键点在于 InvocationHandler的 invoke方法

    应用场景

  • Retrofit API

  • Spring AOP

    InvocationHandler

    第一种方式

  • 通过构造方法传递被代理对象

  • 在 invoke 方法里 method.invoke(xxx, args)

    示例

    InvocationHandler实现类
    1. class ProxyHandlerImp(private val obj: Any) : InvocationHandler {
    2. override fun invoke(proxy: Any?, method: Method?, args: Array?): Any? {
    3. return method?.invoke(obj)
    4. }
    5. }

    调用方式

    1. val h: InvocationHandler = ProxyHandlerImp(HelloImp())
    2. val hProxy: IHello = Proxy.newProxyInstance(IHello::class.java.classLoader, arrayOf(IHello::class.java), h) as IHello
    3. hProxy.sayHello()

第一种方式优化

  • 通过工厂类和单例管理创建被代理类
  • 通过 method 里携带的接口类进行对比拿到对应的被代理类实例
  • 通过拿到的被代理实例 return method?.invoke(被代理实例)

第二种方式

直接在 invoke 方法里操作

  • 通过 method.getName 来区分方法
  • 通过对不同的方法返回不同的值

    示例

    InvocationHandler实现类
    1. class ProxyHandler2 : InvocationHandler {
    2. override fun invoke(proxy: Any?, method: Method?, args: Array?): Any? {
    3. return when(method?.name) {
    4. "sayHello" -> {
    5. println(" >>>>>> sayHello <<<<<<")
    6. }
    7. "sayBye" -> {
    8. println(" >>>>>> sayBye <<<<<<")
    9. }
    10. else -> {
    11. println(" >>>>>> empty <<<<<<")
    12. }
    13. }
    14. return null
    15. }
    16. }

    调用方式

    1. val h: InvocationHandler = ProxyHandlerImp()
    2. val hProxy: IHello = Proxy.newProxyInstance(IHello::class.java.classLoader, arrayOf(IHello::class.java), h) as IHello
    3. hProxy.sayHello()

    参考链接

    https://www.jianshu.com/p/9bcac608c714
    https://medium.com/hashtech/dynamic-proxy-in-java-56fbfa92c596
    https://www.jianshu.com/p/9e55174d4d27