博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java静态代理和动态代理分析
阅读量:7045 次
发布时间:2019-06-28

本文共 6367 字,大约阅读时间需要 21 分钟。

一直想分享一些技术,为多变的技术带来一些分享,以后会慢慢的带来一些自己学过的技术,和自己的一些心得,最近想分享effect java,设计模式,并发编程,一些java集合源码和并发包源码,jvm,mybatis源码,nio,nio2,netty,grpc,和一些数据结构算法,mysql,git

今天就先来分析静态代理和动态代理

一、静态代理模式

        假设有个这样的场景,想对一个Source类进行加强,比如在不改变Source类的基础,执行Source类的method()方法执行前后打印一些日记,实现步骤

  • 首先有个接口

    public interface Sourceable {    void method();}复制代码

  • 再者实现接口的Source类

    public class Source implements Sourceable {    @Override    public void method() {        System.out.println("the original method");    }}复制代码

  • 然后再有个代理类,同样也实现Sourceable接口

    public class Proxy implements Sourceable {    private Sourceable source;    public Proxy(Source source) {        this.source = source;    }    @Override    public void method() {        before();        source.method();        after();    }        private void before() {        System.out.println("method() run begin");    }    private void after() {        System.out.println("method() run end");    }}复制代码

  • 最后测试下

    public class ProxyTest {    public static void main(String[] args) {        Source source = new Source();        Proxy proxy = new Proxy(source);        proxy.method();    }}复制代码

  • 结果

    method() run beginthe original methodmethod() run end复制代码

二、动态代理模式

          我们经常在使用mybatis的时候mapper只是个接口,调用接口方法就能执行如下

IUserMapper userMapper = session.getMapper(IUserMapper.class);//获取接口,已经是代理接口 userMapper.getById(1);//调用mybatis内部的MapperProxy类的invoke复制代码

我们先来看下核心的Proxy.newProxyInstance(arg1,arg2,arg3)方法

(ServiceInterface) Proxy.newProxyInstance(ServiceInterface.class.getClassLoader(), serviceInterface.getClass().getInterfaces(), InvocationHandler);复制代码

第一个参数arg1是接口的classloader,就是为了加载动态生成的代理类,arg2是接口,为了生成的代理类实现此接口,拥有实现此接口的方法,最后一个参数arg3,InvocationHandler,目的是生成的代理类对象,执行方法时,调用此内部的invoke()方法

接下来我们开始实现它,有两种情况,一种是接口有实现类,我们在内部直接用反射进行调用实现类方法,第二种就是mybatis实现方式,只有接口没有实现类,我们先实现由实现类的方式

  • 首先有个ServiceInterface接口

    public interface ServiceInterface {    void println();}复制代码

  • 再者有个接口实现类

    public class ServiceInterfaceImpl implements ServiceInterface {    @Override    public void println() {        System.out.println("ServiceInterfaceImpl");    }}复制代码

  • 接下来看下重要的handler,invoke有三个参数第一个动态生成的代理类,第二个参数是要执行的方法,第三个参数是方法参数

public class MyInvocationHandler implements java.lang.reflect.InvocationHandler {    private Object target;    public MyInvocationHandler(Object target) {        this.target = target;    }    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        System.out.println("2222");        method.invoke(target, args);        System.out.println("3333");        return null;    }}复制代码

  • 最后测试

    public class ProxyTest {    public static void main(String[] args) {        ServiceInterface serviceInterface = new ServiceInterfaceImpl();        InvocationHandler InvocationHandler = new MyInvocationHandler(serviceInterface);        ServiceInterface proxy = (ServiceInterface) Proxy.newProxyInstance(ServiceInterface.class.getClassLoader(), serviceInterface.getClass().getInterfaces(), InvocationHandler);        proxy.println();    }}复制代码

我们再来看下第二种方式只有接口没有实现类

  • 同样首先有个接口

    public interface ServiceInterface {    void println();}复制代码

  • 再者

public class MyInvocationHandler implements java.lang.reflect.InvocationHandler {    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        System.out.println("2222");        System.out.println("3333");        return null;    }}复制代码

  • 最后测试

    public class ProxyTest {    public static void main(String[] args) {        InvocationHandler InvocationHandler = new MyInvocationHandler();        ServiceInterface proxy = (ServiceInterface) Proxy.newProxyInstance(ServiceInterface.class.getClassLoader(), new Class[]{ServiceInterface.class}, InvocationHandler);        proxy.println();    }}复制代码

三、总结

        流程是调用Proxy.newProxyInstance()方法会动态生成实现传入的第二个参数的接口,然后第三个参数是handler,调用proxy.println(),其实动态类println()方法其实是调handler的invoke方法,我们接下来看下反编译后的动态类

// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.// Jad home page: http://www.kpdus.com/jad.html// Decompiler options: packimports(3) fieldsfirst package com.sun.proxy;import java.lang.reflect.*;import proxyStudy.ServiceInterface;public final class $Proxy0 extends Proxy    implements ServiceInterface{    private static Method m3;    private static Method m1;    private static Method m0;    private static Method m2;    public $Proxy0(InvocationHandler invocationhandler)    {        super(invocationhandler);    }    public final void println()    {        try        {            super.h.invoke(this, m3, null);            return;        }        catch(Error _ex) { }        catch(Throwable throwable)        {            throw new UndeclaredThrowableException(throwable);        }    }    public final boolean equals(Object obj)    {        try        {            return ((Boolean)super.h.invoke(this, m1, new Object[] {                obj            })).booleanValue();        }        catch(Error _ex) { }        catch(Throwable throwable)        {            throw new UndeclaredThrowableException(throwable);        }    }    public final int hashCode()    {        try        {            return ((Integer)super.h.invoke(this, m0, null)).intValue();        }        catch(Error _ex) { }        catch(Throwable throwable)        {            throw new UndeclaredThrowableException(throwable);        }    }    public final String toString()    {        try        {            return (String)super.h.invoke(this, m2, null);        }        catch(Error _ex) { }        catch(Throwable throwable)        {            throw new UndeclaredThrowableException(throwable);        }    }    static     {        try        {            m3 = Class.forName("proxyStudy.ServiceInterface").getMethod("println", new Class[0]);            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {                Class.forName("java.lang.Object")            });            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);        }        catch(NoSuchMethodException nosuchmethodexception)        {            throw new NoSuchMethodError(nosuchmethodexception.getMessage());        }        catch(ClassNotFoundException classnotfoundexception)        {            throw new NoClassDefFoundError(classnotfoundexception.getMessage());        }    }}复制代码

转载于:https://juejin.im/post/5bff9d17e51d45454b412116

你可能感兴趣的文章
Speed up your Internet browsing on Linux with a DNS Cache server
查看>>
我的失败与伟大 —— 合作伙伴的甄别
查看>>
APP运营中必须关注的7大数据指标
查看>>
kettle数据同步的五种方案
查看>>
如何用IE的开发人员工具选择Iframe里面的元素
查看>>
linux 常用命令(1) grep
查看>>
第三方开发的网贷系统安全如何保障
查看>>
Java千百问_05面向对象(006)_is-a,has-a,like-a是什么
查看>>
Android SDK r20.x更新时,没有Android API的问题
查看>>
PHPWind发布新产品架构图
查看>>
GitHub学习笔记
查看>>
RecyclerView+Cardview学习探索
查看>>
python 类 五 : 多重继承的MRO顺序
查看>>
Asp.net 数据库链接字符串 备份一下
查看>>
CentOS系统安装详细步骤
查看>>
我的友情链接
查看>>
我的友情链接
查看>>
Shell脚本之测试及条件表达式简述
查看>>
JavaScript函数详解(二)
查看>>
X9BYOD集群界面展示
查看>>