【Java】jdk1.8 Java代理模式,Jdk动态代理讲解(非常详细,附带class文件)

这篇具有很好参考价值的文章主要介绍了【Java】jdk1.8 Java代理模式,Jdk动态代理讲解(非常详细,附带class文件)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【Java】jdk1.8 Java代理模式,Jdk动态代理讲解(非常详细,附带class文件),java,代理模式,开发语言

  📝个人主页:哈__

期待您的关注 

【Java】jdk1.8 Java代理模式,Jdk动态代理讲解(非常详细,附带class文件),java,代理模式,开发语言

一、什么是代理模式

想要学代理模式,我们就要先弄清一个概念“什么是代理”?

在我们的现实生活中,你或许不少听过关于代理的名词,如:代理商。那什么又叫做代理商?让我一个词来形容就是中间商。

举个例子,在你买二手房的时候,你一般不会直接和业主去交谈,你或许会找一家二手房出租出售企业来寻找房源,你看上哪个房子后,由这位中间商来沟通房源的业主完成购买流程。这就是一个代理的例子。

再举个例子,在青青草原上举办了一场选美大赛,在喜羊羊的劝导下,美羊羊参加了这场比赛。当然结果对于美羊羊来说是十分完美的,美羊羊以158票的优势超越第二名的红太狼位居榜首。从此美羊羊成为了青青草原的大明星。

红太狼自然是不服,于是灰太狼和红太狼商量了一个计划,他们想要请美羊羊来参加一场由他们举办的模特比赛,美羊羊在接收到邀请后非常开心,直接就同意了他们的邀请。但这时作为经纪人的喜羊羊就不同意了,这明显是请君入瓮啊,于是喜羊羊就代替美羊羊推掉了他们的邀请。

如果没有喜羊羊,美羊羊去了之后的后果可想而知,这时就体现出了喜羊羊的重要性了。

【Java】jdk1.8 Java代理模式,Jdk动态代理讲解(非常详细,附带class文件),java,代理模式,开发语言 

二、Java中的静态代理 

 1.创建我们的美羊羊同意邀请的service层。go()方法也叫做目标方法。

public interface YangService {
    void go();
}


public class YangServiceImpl implements YangService {
    @Override
    public void go() {
        System.out.println("美羊羊想要同意邀请");
    }
}

2.创建一个喜羊羊检查意图和拒绝他们的邀请的类(喜羊羊可能是多个人的经纪人,所以把他的功能单独抽取)。这些方法我也会称作增强方法。

public class DaoTransaction{
    public  void beforeCheck(){
        System.out.println("喜羊羊检查灰太狼的意图");
    }
    public  void afterCheck(){
        System.out.println("喜羊羊拒绝他们的邀请");
    }


}

3.我们创建一个代理类,这个类就相当于灰太狼和红太狼直接向喜羊羊发出了邀请,美羊羊太火,他们无法直接接触到美羊羊。这里要实现美羊羊功能的接口,因为喜羊羊要对美羊羊的一切行动做出处理。看下边的代码,美羊羊在同意之前要经过喜羊羊的检查,同意之后还要被喜羊羊拒绝。

public class XiYyProxy implements YangService {
    DaoTransaction daoTransaction = new DaoTransaction();
    YangServiceImpl yangService = new YangServiceImpl();
    @Override
    public void go() {
        daoTransaction.beforeCheck();
        yangService.go();
        daoTransaction.afterCheck();
    }
}

4.主程序。

public static void main(String[] args) {
        XiYyProxy xiYyProxy = new XiYyProxy();
        xiYyProxy.go();
    }

【Java】jdk1.8 Java代理模式,Jdk动态代理讲解(非常详细,附带class文件),java,代理模式,开发语言

三、Jdk动态代理 

我们上边写的是静态代理,你可以看到,我们的代码只能让喜羊羊作为美羊羊一个人的经纪人,静态代理有着这么几个特点。

  1. 目标角色固定
  2. 在应用程序执行前就得到目标角色
  3. 代理对象会增强目标对象的行为
  4. 有可能存在多个代理 引起"类爆炸"(缺点)

如果灰太狼邀请的不是美羊羊,那我们的代码就毫无用处了,所以我们使用动态代理来实现功能。

我们创建这样的一个service,我们上边写的是YangService,为了区分我们创建一个YangTwoService,这里我弄得不太规范,重在让大家理解。

public interface YangTwoService {
    void go();
}

public class YangTwoServiceImpl implements YangTwoService {
    @Override
    public void go() {
        System.out.println("沸羊羊同意参加健美比赛");
    }
}

那如果我们想要喜羊羊作为沸羊羊的经纪人拒绝掉这个比赛呢?还按照上边的代理方式吗?这就太费事费力了。我们这样想,我们把喜羊羊作为代理的过程抽取出来,到底要代理谁我们后期决定,只要传入一个参数确认是谁,这样我们的代码就简化很多了。

创建JdkProxyHandler。

public class JdkProxyHandler implements InvocationHandler {
    //这是我们要代理的目标对象 到底是谁
    Object object;
    // 这是从喜羊羊那里抽取出来的方法
    DaoTransaction daoTransaction;
    public JdkProxyHandler(Object o,DaoTransaction daoTransaction){
        this.object = o;
        this.daoTransaction = daoTransaction;
    }
    @Override
    //proxy--代理类  method--目标方法   args--目标方法的参数
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object o = new Object();
        //我们只对go方法进行处理,喜羊羊不能管得太多
        if(method.getName().equals("go")){
            daoTransaction.beforeCheck();
            o = method.invoke(object,args);
            daoTransaction.afterCheck();
        }else{
            o = method.invoke(object,args);
        }
        return o;
    }
}

主方法。

public class Main {
    public static void main(String[] args) {
        DaoTransaction daoTransaction = new DaoTransaction();
        YangServiceImpl yangService = new YangServiceImpl();
        YangTwoServiceImpl yangTwoService = new YangTwoServiceImpl();
        JdkProxyHandler proxy1 = new JdkProxyHandler(yangService,daoTransaction);
        JdkProxyHandler proxy2 = new JdkProxyHandler(yangTwoService,daoTransaction);
        YangService proxyYang = (YangService) Proxy.newProxyInstance(yangService.getClass().getClassLoader(), yangService.getClass().getInterfaces(), proxy1);
        YangTwoService proxyYangTwo = (YangTwoService) Proxy.newProxyInstance(yangTwoService.getClass().getClassLoader(), yangTwoService.getClass().getInterfaces(), proxy2);
        proxyYang.go();
        proxyYangTwo.go();
    }
}

看不懂没关系,我接下来会将Jdk动态代理的过程。我先来解释一下上边的代码。

创建我们的Handler,在上边我们能够看到,我们的逻辑处理都是在这个对象里的,这个对象很重要,你到底是如何让喜羊羊去处理的,都是靠这个JdkProxyHandler类(自定义)实现。每只不同的羊都有自己的对象。

JdkProxyHandler proxy1 = new JdkProxyHandler(yangService,daoTransaction);

这行代码才是真正创建我们的代理对象,也就是相当于我们上边静态代理创建的XiYyProxy对象,我们调用美羊羊和沸羊羊的go方法,都通过这个proxyYang对象 。

 YangService proxyYang = (YangService) Proxy.newProxyInstance(yangService.getClass().getClassLoader(), yangService.getClass().getInterfaces(), proxy1);

 下边这行代码就是调用我们创建出来的代理对象来处理我们的逻辑。

proxyYang.go();

 【Java】jdk1.8 Java代理模式,Jdk动态代理讲解(非常详细,附带class文件),java,代理模式,开发语言

四、Jdk动态代理解析 

我们生成一下Jdk动态代理在编译后生成的class文件的反编译结果来查看一下。下边的代码就是为了生成我们的class文件的。

public static void saveProxyClass(String path) throws IOException {
        byte[] $proxy1s = ProxyGenerator.generateProxyClass("$Proxy1", YangServiceImpl.class.getInterfaces());
        FileOutputStream out = null;
        try{
            out = new FileOutputStream(new File(path+"$Proxy1.class"));
            out.write($proxy1s);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(out == null){
                try {
                    out.flush();
                    out.close();
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
    }

在main方法中调用这个方法。注意:一定要修改saveProxyClass的路径,我直接生成到根目录下了!!!!!!

 public static void main(String[] args) throws IOException {
        DaoTransaction daoTransaction = new DaoTransaction();
        YangServiceImpl yangService = new YangServiceImpl();
        YangTwoServiceImpl yangTwoService = new YangTwoServiceImpl();
        JdkProxyHandler proxy1 = new JdkProxyHandler(yangService,daoTransaction);
        JdkProxyHandler proxy2 = new JdkProxyHandler(yangTwoService,daoTransaction);
        YangService proxyYang = (YangService) Proxy.newProxyInstance(yangService.getClass().getClassLoader(), yangService.getClass().getInterfaces(), proxy1);
        YangTwoService proxyYangTwo = (YangTwoService) Proxy.newProxyInstance(yangTwoService.getClass().getClassLoader(), yangTwoService.getClass().getInterfaces(), proxy2);
        proxyYang.go();
        proxyYangTwo.go();
        saveProxyClass("你的真实路径");
    }

【Java】jdk1.8 Java代理模式,Jdk动态代理讲解(非常详细,附带class文件),java,代理模式,开发语言

查看文件。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

import com.my.proxy.service.YangService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy1 extends Proxy implements YangService {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy1(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void go() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.my.proxy.service.YangService").getMethod("go");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

我们来分块讲解一下,先看下边的static静态块,这个块在类被加载的时候自动执行里边的代码。

我去,这不就是反射吗把我的YangServiceImpl类中继承的Object类中的方法都给我反射出来了,同时还把我的YangService接口中的方法go()也给我反射出来了。

static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.my.proxy.service.YangService").getMethod("go");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }

 在看看我们的go()方法调用。我去,这个super.h.invoke(this,m3,(Object[])null)是啥啊,我带你先弄清h是啥。

public final void go() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

我们往上看看这个代理类的构造函数。你明白了吗?h就是我们传给父类的InvocationHandler类型的对象,也就是我们上边自己创建的JdkProxyHandler类。

public $Proxy1(InvocationHandler var1) throws  {
        super(var1);
    }

那这个go方法还用点进去吗?我们上边的JdkProxyHandler已经写清楚了。

现在你是否了解了Jdk动态代理?它是通过反射实现的,将目标接口中的方法进行反射,然后我们的代理类拿到这些方法,每当我们执行目标接口中的方法的时候,都会通过我们的代理类进行反射调用,具体如何调用,就是通过我们创建的InvocationHandler类型的对象。

 

我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=32sln7v483acs文章来源地址https://www.toymoban.com/news/detail-851690.html

到了这里,关于【Java】jdk1.8 Java代理模式,Jdk动态代理讲解(非常详细,附带class文件)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 代理模式:静态代理+JDK/CGLIB 动态代理

    代理模式是一种比较好理解的设计模式。简单来说就是 我们使用代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。 代理模式的主要作用是扩展目标对象的功能,比如说在目标对象的某个方法

    2024年02月13日
    浏览(36)
  • 温故知新之:代理模式,静态代理和动态代理(JDK动态代理)

    代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。 静态代理 是一种代理模式的实现方式,它在编译期间就已经确定了代理对象,需要为每一个被代理对象创建一个代理类。静态代理的实现比较简单,但是每个被代理对象都需要创建

    2024年02月11日
    浏览(48)
  • 3_代理模式(动态代理JDK原生和CGLib)

    1.概念 代理模式(Proxy Pattern )是指 为其他对象提供一种代理,以控制对这个对象的访问 ,属于结构型模式。 在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。 使用代理模式主要有两个目的: 一是保护目标

    2024年01月17日
    浏览(41)
  • MAC(适用于M1,M2芯片)下载Java8(官方 ARM64 JDK1.8)安装、配置环境,支持动态切换JDK

    官方下载地址 https://www.oracle.com/cn/java/technologies/downloads/ 这个是官方新发布的适配了M1、M2芯片的ARM64版本的jdk8,再也不用去第三方下载了,也不用满世界的去找第三方jdk缺少的jar包了,而且更快更强!! 可以下载免安装版, 这样就可以配置多个版本的jdk了,配置如下 使配置

    2024年02月08日
    浏览(114)
  • Java——JDK动态代理

    动态代理(理解) 基于反射机制 举个例子,生活中一般在打官司的时候都会请代理律师,为什么要请律师呢?是因为开庭的时候大部人对于打官司没有经验,只会说出自己案件的陈述,并不会根据法律等争取自己权益的最大化,此时就可以请律师帮助自己不仅完成对案件的陈述

    2024年02月09日
    浏览(42)
  • java中的静态代理、jdk动态代理以及CGLIB 动态代理

    代理模式是一种比较好理解的设计模式。简单来说就是 我们使用代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能 那以下文章主要谈三种代理模式, 分别是静态代理,jdk的动态代理,cglib的动

    2024年02月11日
    浏览(43)
  • 【Java】JDK动态代理实现原理

    代理模式 代理模式一般包含三个角色: Subject :主题对象,一般是一个接口,定义一些业务相关的基本方法。 RealSubject :具体的主题对象实现类,它会实现Subject接口中的方法。 Proxy :代理对象,里面包含一个RealSubject的引用,外部会通过这个代理对象,来实现RealSubject中方

    2024年02月08日
    浏览(41)
  • Java代理之jdk动态代理+应用场景实战

    本文将先介绍jdk动态代理的基本用法,并对其原理和注意事项予以说明。之后将以两个最常见的应用场景为例,进行代码实操。这两个应用场景分别是 拦截器 和 声明性接口 ,它们在许多开发框架中广泛使用。比如在spring和mybatis中均使用了拦截器模式,在mybatis中还利用动态

    2023年04月10日
    浏览(43)
  • Linux安装jdk1.8(超详细)

    1.下载jdk tar.gz格式压缩包,放入linux的目录 2.解压压缩包 3.移动压缩包 /usr/local:用户级的程序目录,可以理解为C:/Progrem Files/。这里主要存放那些手动安装的软件。 /usr/local下没有名为jdk1.8的文件夹,则将jdk1.8.0_291移动到到/usr/local下并且更名为jdk1.8 4.修改配置文件 /etc/profil

    2024年02月13日
    浏览(61)
  • Liunx 安装JDK1.8详细教程

    创建文件夹,进入安装目录 在线下载 离线下载(官网下载链接) 配置JDK的环境变量,vim /etc/profile。添加下边的语句:(注意JAVA_HOME、JRE_HOME要对应JDK保存的位置): 使配置文件立即生效,source /etc/profile 查看环境变量是否配置成功:java -version。(出现版本号,说明配置成功了

    2024年02月08日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包