代理背后的故事

154 阅读5分钟

「本文已参与好文召集令活动,点击查看:后端、大前端双赛道投稿,2万元奖池等你挑战!

代理模式是创建型模式的其中的一种;

框架中的实例:

**spring的AOP的代理模式

cglib的代理

JDK底层的代理模式**

1.动态代理

Java 中,实现动态代理有两种方式:1、JDK 动态代理:java.lang.reflect 包中的 Proxy 类和 InvocationHandler 接口提供了生成动态代理类的能力。2、Cglib 动态代理:Cglib (Code Generation Library )是一个第三方代码生成类库,运行时在内存中动态生成一个子类对象从而实现对目标对象功能的扩展。

代理的本质:

代理是对方法的增强;

对修改关闭,对扩展开放;

2.静态代理

2.1 静态代理的实现方式

继承实现两种方式

代理对象和被代理者需要有共同方法,

这种联系通常可以使用,

代理者和被代理者, 实现同一个接口sing()

代理者继承被代理者,就可以重写方法

举个例子,我们公司开年会,想请毛不易来唱歌,但是我们肯定直接接触不到毛不易,只能是联系他的经纪人,跟他确定事项,所以经纪人就是毛不易的代理对象,帮他打理事务,

3.1 公共接口方法

`package com.atlucas.creation.Proxy.com;

/**

  • @author luca

  • @create 2021-07-08 15:51

  • @description 对于当前唱作人的抽象方法唱歌

  • 问抽象类与接口的区别? */ public interface SingerAbstract {

    //唱歌 void sing();

} `

3.2 被代理者实现接口

毛不易实现自己的唱歌水平

package com.atlucas.creation.Proxy.com;

/**

  • @author luca

  • @create 2021-07-08 15:51

  • @description 唱作人毛不易 */ public class Starers implements SingerAbstract{

    public void sing() {

     System.out.println("毛不易带来消愁.......");
    

    } }

3.3 代理对象实现共同接口

经纪人agent开始跟毛不易商量事项

package com.atlucas.creation.Proxy.com;

/**

  • @author luca

  • @create 2021-07-08 15:57

  • @description 经纪人-->agent,对于当前唱作人的增强 */ public class Agent implements SingerAbstract {

    /**

    • 静态代理的角色,三个(当前方法功能的扩展,可以使用代理)
    • 抽象方法: sing
    • 被代理者: 毛不易
    • 代理对象: agent,经纪人
    • 代理对象,不能对被代理对象修改,只是在代理对象的基础上做扩展
    • 代理模式很符合软件的开闭原则:--对修改关闭,对扩展开放 */

    //毛不易 private Starers maobuyi;

    //利用构造器完成对被代理对象的加载 public Agent(Starers maobuyi) { this.maobuyi = maobuyi; }

    public void sing() { //sing,before()

     System.out.println("确定档期,活动事项,费用金额等");
    
     maobuyi.sing();
     //sing.after()
     System.out.println("结算尾款,确定成功,完成活动");
    

    }

}

3.4 代理对象被使用

主办方我们公司,联系经纪人

package com.atlucas.creation.Proxy.com;

/**

  • @author luca

  • @create 2021-07-08 16:07

  • @description 主办方的工作人员,需要联系经纪人,获取唱作人本身的档期,制定活动日期 */ public class Sponsor {

    public static void main(String[] args) {

     Starers starers=new Starers();
     //请毛不易唱歌
     Agent agent =new Agent(starers);
     agent.sing();
    

    } }

我们作为主办方,可以直接让明星唱歌, 这也是代理模式中静态代理的应用,

本质上, 代理,对于当前功能需要增强,不侵入原方法的情况下对功能进行增强

还有一种是, 父子类继承, 代理对象继承,并且扩展当前被代理者的接口, 做扩展,做增强

静态代理的痛点:

每个被代理者都需要一个代理对象,导致开发难度,代码的结构都会受到影响;

所以,我们可以使用动态代理,让代理的代码主动生成

4.动态代理

(1)JDK动态代理

JDK底层的动态代理Proxy

package proxy;

import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method;

public class Agent implements InvocationHandler {

//代理任何对象,其中object是被代理对象

private  Object object;

public Agent(Object object) {
    this.object = object;
}
//这个就是代理对象,JDK底层实现的动态代理的对象

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

    System.out.println("协商细节");
    Object invoke = method.invoke(object, args);// 被代理对象取调用自己的方法
    System.out.println(method.getName());    //获取调用方法的名称
    System.out.println("结算");
    return invoke;
}

}

package proxy;

import com.sun.org.apache.bcel.internal.generic.NEW;

import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;

public class JDKProxy {

public static void main(String[] args) {

    /**
     * JDK动态代理一个对象
     *   当前对象的类加载器,class.getclassLoad()
     *   接口的对象数组
     *   invoke的回调函数
     */

    Singer singer=new Singer();//代理毛不易

    //代理的返回的只能是代理接口的对象
    SingAbstract instance =(SingAbstract) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(),
            new Class[]{SingAbstract.class},
            new Agent(singer));


    instance.sing();  //实际调用的invoke的方法

}

}

package proxy;

public interface SingAbstract {

void sing();

}

package proxy;

public class Singer implements SingAbstract{

@Override
public void sing() {
    System.out.println("毛不易的消愁开始了");
}

}

(2)Cglib动态代理

其中对于cglib的代理,不需要直接有接口实现,不需要本质的接口实现就可以

代理模式的分类:

远程代理:就是将工作委托给远程对象(不同的服务器,或者不同的进程)来完成。常见的是用在web Service中。还有就是我们的RPC调用也可以理解为一种远程代理。

缓存代理:这个很好理解,就是通过存储来加速调用,比如Sping中的@Cacheable方法,缓存特定的参数获取到的结果,当下次相同参数调用该方法,直接从缓存中返回数据。

虚拟代理:这种代理主要是为方法增加功能,比如记录一些性能指标等,或进行延迟初始化

反射

反射是动态代理的一种实现方式