美文网首页
Java 代理模式

Java 代理模式

作者: 索性流年 | 来源:发表于2021-02-08 08:54 被阅读0次

文集地址

一句话总计代理模式

  • 让别人帮你做事,便是代理模式

什么是代理模式?

*为其他对象生成一个代理,以控制这个对象的访问

为什么使用代理模式?

  • 中介隔离:在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到承上启下的作用,其特征是代理类和委托类实现相同的接口。

  • 开闭原则,增加功能代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额外的功能来扩展委托类的功能,这样做我们只需要修改代理类而不需要再修改委托类,符合代码设计的开闭原则。代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后对返回结果的处理等。代理类本身并不真正实现服务,而是同过调用委托类的相关方法,来提供特定的服务。真正的业务功能还是由委托类来实现,但是可以在业务功能执行的前后加入一些公共的服务。例如我们想给项目加入缓存、日志这些功能,我们就可以使用代理类来完成,而没必要打开已经封装好的委托类。

代理模式实现原理

  • 代理模式主要包含三个角色,即抽象主题角色(Subject)、委托类角色(被代理角色,Proxied)以及代理类角色(Proxy)

生么是静态代理?

  • 静态代理是由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。

  • 总结: 自己手写代理类就是静态代理。

静态代理的缺点?

  • 如若项目中被代理类过多,那么就会生成很多代理类,代码会非常冗余

动态代理

  • 动态代理是在实现阶段不用关心代理类,而在运行阶段才指定哪一个对象,动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成。

代理模式两种创建方式

  • 继承、实现

静态代理与动态代理区别

  • 静态代理是程序员手动创建的代理,而动态代理则是由系统在运行时自动创建的代理。

JDK动态代理与CGLIB代理区别

  • JDK实现动态代理,被代理类必须实现接口,底层是采用反射机制执行
  • CGLIB实现动态代,采用继承代理实现类的方式,底层是采用ASM(字节码)生成子类

JDK动态代理实现原理

  • 拼接java 源码
  • 编译为 class 文件
  • 使用类加载器将class 文件读取到程序中
  • JDK的动态代理,走拦截回调,通过实现接口生成动态代理类,使用反射技术执行目标方法

CGLIB代理实现原理

  • 通过ASM字节码技术生成class 文件
  • 使用类加载器将class 文件读取到程序中
  • 采用FastClass 机制调用目标方法
  • CGLIB 动态代理采用集成的方式生成代理类,底层通过ASM 字节码技术实现
  • FastClass 会将我们目标对象下所有的方法生成对应索引标记,直接根据索引标记调用目标方法

应用案例

  • 小朋友要吃糖,他只能自己去找糖,撕开糖纸,在把糖吃进嘴里,这时候小朋友就会想,要是能有人帮我把糖拿过来,撕开糖纸,把糖塞进我嘴里多好。
    这就是代理模式,让别人把你做事

实现案例

  • 被代理对象
/**
 * 被代理对象
 *
 * @author ext.liuyan10
 * @date 2021/2/5 14:34
 */
public class User {
    public void test() {
        System.out.println("小朋友:糖真甜");
    }
}

静态代理

  • 代理对象 UserProxy
/**
 * 代理对象
 *
 * @author ext.liuyan10
 * @date 2021/2/5 13:38
 */
public class UserProxy implements UserApi {
    private User user;

    public UserProxy(User user) {
        this.user = user;
    }

    @Override
    public void test() {
        System.out.println("将糖找来");
        System.out.println("撕开糖纸,喂给小朋友");
        user.test();
    }
}

  • 调用代理对象 TestApp
/**
 * @author liunian
 * @date 2021/2/5 13:42
 */
public class TestApp {

    public static void main(String[] args) {
        User user = new User();
        UserProxy userProxy = new UserProxy(user);
        userProxy.test();
    }
}

动态代理

CGLIB动态代理

  • 对被代理对象无要求,可以是接口,也可以是具体类

  • 引入依赖

  <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.2.10</version>
  </dependency>
  • 生成代理对象(可多次调用生成不同代理对象)
/**
 * 生成动态代理对象
 *
 * @author liunian
 * @date 2021/2/5 14:35
 */
public class UserCglibInvocation implements MethodInterceptor {
    private Object target;

    public UserCglibInvocation(Object target) {
        this.target = target;
    }

    public Object getProxyInstance() {
        //工具类
        Enhancer en = new Enhancer();
        //设置父类
        en.setSuperclass(target.getClass());
        //设置回调函数
        en.setCallback(this);
        //创建子类代理对象
        return en.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("将糖找来");
        System.out.println("撕开糖纸,喂给小朋友");
        Object invoke = method.invoke(target);
        return invoke;
    }
}

  • 调用方法
/**
 * @author liunian
 * @date 2021/2/5 13:42
 */
public class TestApp {

    public static void main(String[] args) {
        User user = new User();
        UserCglibInvocation userInvocation = new UserCglibInvocation(user);
        User proxyInstance = (User) userInvocation.getProxyInstance();
        proxyInstance.test();
    }
}

JDK动态代理
  • 要求被代理对象是一个接口并且以被实现

  • 被代理对象 UserApi

/**
 * 被代理对象 
 *
 * @author liunian
 * @date 2021/2/5 13:39
 */
public interface UserApi {
    void test();
}
  • 被代理对象实现 UserImpl
/**
 * 被代理对象实现
 *
 * @author liunian
 * @date 2021/2/5 13:36
 */
public class UserImpl implements UserApi{
    @Override
    public void test() {
        System.out.println("小朋友:糖真甜");
    }
}
  • 生成代理对象(可多次调用生成不同代理对象)
/**
 * 生成代理对象
 *
 * @author ext.liuyan10
 * @date 2021/2/5 14:03
 */
public class UserInvocation implements InvocationHandler {

    Object target;

    public UserInvocation(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("将糖找来");
        System.out.println("撕开糖纸,喂给小朋友");
        Object invoke = method.invoke(target);
        return invoke;
    }
}

  • 调用方法
/**
 * @author liunian
 * @date 2021/2/5 13:42
 */
public class TestApp {
    public static void main(String[] args) {
        UserApi user = new UserImpl();
        UserInvocation userInvocation = new UserInvocation(user);
        UserApi userApi = (UserApi) Proxy.newProxyInstance(user.getClass().getClassLoader(), user.getClass().getInterfaces(), userInvocation);
        userApi.test();
    }
}
  • 调用结果
Connected to the target VM, address: '127.0.0.1:51870', transport: 'socket'
将糖找来
撕开糖纸,喂给小朋友
小朋友:糖真甜
Disconnected from the target VM, address: '127.0.0.1:51870', transport: 'socket'

Process finished with exit code 0

相关文章

  • java动态代理(JDK和cglib)(转载自http://ww

    java动态代理(JDK和cglib) JAVA的动态代理 代理模式 代理模式是常用的java设计模式,他的特征是...

  • Java代理模式之JDK动态代理

    了解什么是动态代理模式,可参考Java设计模式之代理模式 简介 JDK动态代理是java.lang.reflect...

  • java代理模式的那些事

    java代理模式-登场 什么是代理模式? 代理模式是java中的一种设计模式,它其实就是设置一个中间环节来代理你要...

  • java建造者模式

    其他设计模式java单例模式java建造者模式java策略模式java代理模式java观察者模式java适配器模式...

  • java单例模式

    其他设计模式java单例模式java建造者模式java策略模式java代理模式java观察者模式java适配器模式...

  • java外观模式

    其他设计模式java单例模式java建造者模式java策略模式java代理模式java观察者模式java适配器模式...

  • java适配器模式

    其他设计模式java单例模式java建造者模式java策略模式java代理模式java观察者模式java适配器模式...

  • java观察者模式

    其他设计模式java单例模式java建造者模式java策略模式java代理模式java观察者模式java适配器模式...

  • java代理模式

    其他设计模式java单例模式java建造者模式java策略模式java代理模式java观察者模式java适配器模式...

  • java策略模式

    其他设计模式java单例模式java建造者模式java策略模式java代理模式java观察者模式java适配器模式...

网友评论

      本文标题:Java 代理模式

      本文链接:https://www.haomeiwen.com/subject/ufkfzctx.html