代理模式 1、静态代理 2、动态代理 jdk自带动态代理 3、Cglib代理

文章目录

来和大家聊聊代理模式

代理模式

代理模式:即通过代理对象访问目标对象,实现目标对象的方法。这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,实现对目标功能的扩展。

这涉及到一个编程思想:不要随意去修改别人已经写好的代码或者方法(有坑)。如果需要修改,可以通过代理模式实现。

代理模式 通常有三种实现写法:静态代理、动态代理、Cglib代理

代理模式的UML图

从UML图中,可以看出代理类与真正实现的类都是继承了抽象的主题类,这样的好处在于代理类可以与实际的类有相同的方法,可以保证客户端使用的透明性。

1、静态代理

我们先看针对上面UML实现的例子,再看静态代理的特点。

Subject接口的实现

java 复制代码
public interface Subject {
    void visit();
}

实现了Subject接口的两个类:

java 复制代码
public class RealSubject implements Subject {

    private String name = "byhieg";
    @Override
    public void visit() {
        System.out.println(name);
    }
}
public class ProxySubject implements Subject{

    private Subject subject;

    public ProxySubject(Subject subject) {
        this.subject = subject;
    }

    @Override
    public void visit() {
        subject.visit();
    }
}

具体调用如下:

java 复制代码
public class Client {

    public static void main(String[] args) {
        ProxySubject subject = new ProxySubject(new RealSubject());
        subject.visit();
    }
}

通过上面的代理代码,我们可以看出代理模式的特点,代理类接受一个Subject接口的对象,任何实现该接口的对象,都可以通过代理类进行代理,增加了通用性。但是也有缺点,每一个代理类都必须实现一遍委托类(也就是realsubject)的接口,如果接口增加方法,则代理类也必须跟着修改。其次,代理类每一个接口对象对应一个委托对象,如果委托对象非常多,则静态代理类就非常臃肿,难以胜任。

2、动态代理

动态代理有别于静态代理,是根据代理的对象,动态创建代理类。这样,就可以避免静态代理中代理类接口过多的问题。动态代理是实现方式,是通过反射来实现的,借助Java自带的java.lang.reflect.Proxy,通过固定的规则生成。

其步骤如下:

编写一个委托类的接口,即静态代理的(Subject接口)

实现一个真正的委托类,即静态代理的(RealSubject类)

创建一个动态代理类,实现InvocationHandler接口,并重写该invoke方法

在测试类中,生成动态代理的对象。
第一二步骤,和静态代理一样,不过说了。第三步,代码如下:

java 复制代码
public class DynamicProxy implements InvocationHandler {
    private Object object;
    public DynamicProxy(Object object) {
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = method.invoke(object, args);
        return result;
    }
}

第四步,创建动态代理的对象

java 复制代码
Subject realSubject = new RealSubject();
DynamicProxy proxy = new DynamicProxy(realSubject);
ClassLoader classLoader = realSubject.getClass().getClassLoader();
Subject subject = (Subject) Proxy.newProxyInstance(classLoader, new  Class[]{Subject.class}, proxy);
subject.visit();

创建动态代理的对象,需要借助Proxy.newProxyInstance。该方法的三个参数分别是:

java 复制代码
ClassLoader loader表示当前使用到的appClassloader。
Class<?>[] interfaces表示目标对象实现的一组接口。
InvocationHandler h表示当前的InvocationHandler实现实例对象。
jdk自带动态代理

java.lang.reflect.Proxy

  • 作用:动态生成代理类和对象

java.lang.reflect.InvocationHandler(处理器接口)

  • 可以通过invoke方法实现对真实角色的代理访问
  • 每次通过Proxy生成代理类对象时,都指定对对应的处理器对象

3、Cglib代理

要实现Cglib 代理,必须引入cglib.jar 包,由于Spring-core包中已经包含了cglib功能,且大部分Java项目均引入了spring 相关jar包,这边使用spring的cglib来讲解。(他俩实现方式都是一样的)

java 复制代码
public class CglibProxy implements MethodInterceptor {
    //目标对象
    private Object obj;
    public CglibProxy(Object obj){
        this.obj=obj;
    }
 
    //给目标对象创建一个代理对象
    public Object getProxyInstance(){
        //1.工具类
        Enhancer en = new Enhancer();
        //2.设置父类
        en.setSuperclass(obj.getClass());
        //3.设置回调函数
        en.setCallback(this);
        //4.创建子类(代理对象)
        return en.create();
    }
 
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("CglibProxy--------->");
        return method.invoke(obj,objects);
    }
}

说明:可以看出,Cglib代理模式实现不需要目标对象一定实现接口,故目标对象如果没有实现接口,可以使用cglib代理模式。其实Spring的代理模式也是这么实现的。

相关推荐
城管不管14 分钟前
重生——第十次面试之开源中国一面挂
java·linux·开发语言·算法·面试·职场和发展·开源
Java小白笔记18 分钟前
Windows系统免软件命令激活
java·网络·人工智能·windows·ai·ai编程
爱敲键盘的猴子27 分钟前
深入理解 Java HashMap
java·hashmap
霸道流氓气质27 分钟前
Java开发者AI编程常用MCP、Skills、Rules全景汇总
java·开发语言·ai编程
天涯醉青楼40 分钟前
Spring Boot 接口返回 Bean 时字段名“变形”的深度剖析与解决方案
java
步行cgn1 小时前
MyBatis 高级映射与延迟加载完全指南
java·tomcat·mybatis
thefool1122661 小时前
从中序与后序遍历序列构造二叉树
java
吴声子夜歌1 小时前
Java面试题——JVM(二)
java·开发语言·jvm
CRMEB1 小时前
商城大促活动策划全流程:从定目标到复盘四阶段
java·开发语言·人工智能·ai·开源·php
denglinqings1 小时前
Java开发从入门到精通所有课程
java·开发语言