动态代理-jdk

一、什么是代理?

代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。

二、静态代理

  • 使用组合方式实现静态代理;
interface Movie {
    void play();
}
public class RealMovie implements Movie {
    @Override
    public void play() {
        System.out.println("看电影。。。。。");
    }
}
public class MovieProxy implements Movie {
    private Movie movie;

    public MovieProxy(Movie movie) {
        this.movie = movie;
    }

    @Override
    public void play() {
        System.out.println("看电影前先买票。。。。");
        movie.play();
    }
}

public class MovieTest {
    public static void main(String[] args) {
        Movie proxy = new MovieProxy(new RealMovie());
        proxy.play();
        /**
         * 看电影前先买票。。。。
         * 看电影。。。。。
         */
    }
}

三、动态代理使用案例(jdk方式)

public interface WorkInterface {
    void toWork();
    void toWork2();
}

public class Engineer implements WorkInterface{
    @Override
    public void toWork() {
        System.out.println("工程师开始工作了。。。。。。。。。");
    }

    @Override
    public void toWork2() {
        System.out.println("工程师开始工作了2222。。。。。。。。。");
    }
}

public class WorkInvocationHandle implements InvocationHandler {
    private Object obj;
    public WorkInvocationHandle(Object obj) {
        this.obj = obj;
    }
    /**
     *
     * proxy:代表动态代理对象
     * method:代表正在执行的方法
     * args:代表调用目标方法时传入的实参
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("进入代理,执行增强方法");
        Object invoke = method.invoke(obj, args);//执行被代理的方法
        return invoke;  //返回结果
    }
}
public class JkdProxy {
    public static void main(String[] args) {
   		//开启动态代理的文件输出
   		// 代理class的生成路径是在idea的工作空间下的 com\sun\proxy 目录中
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
        //创建代理类
        WorkInterface proxy = (WorkInterface) Proxy.newProxyInstance(JkdProxy.class.getClassLoader(), Engineer.class.getInterfaces(), new WorkInvocationHandle(new Engineer()));
        proxy.toWork();
        proxy.toWork2();
        /**
         * 进入代理,执行增强方法
         * 工程师开始工作了。。。。。。。。。
         */
    }
}

Proxy.newProxyInstance方法我们需要注意的参数:
第一个参数ClassLoader loader:类的加载器,传入我们自定义类的加载器
第二个参数Class<?>[] interfaces 注意很重要 这个参数是传入一个接口数组
第三个参数 h:类型是InvocationHandler,传入InvocationHandler接口的子类

在调用过程中特别注意:

Class<?> cl = getProxyClass0(loader, intfs);

调用了getProxyClass0方法, 该方法 需要传入两个参数 一个是类加载器,一个是接口数组
在方法getProxyClass0 中 会创建出一个类$Proxy0 ,并且创建出这个内部类的引用返回
我通过生出的内部类文件,反编译出源码可以看下:

package com.sun.proxy;

import com.ganyz.demo.jdkproxy.WorkInterface;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements WorkInterface {
    private static Method m1;
    private static Method m4;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy0(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 void toWork2() throws  {
        try {
            super.h.invoke(this, m4, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    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 toWork() 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"));
            m4 = Class.forName("com.ganyz.demo.jdkproxy.WorkInterface").getMethod("toWork2");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.ganyz.demo.jdkproxy.WorkInterface").getMethod("toWork");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}


  • 注意:我们可以发现这个生成的类继承了proxy 并且实现了我自己定义的那个接口,我们可以设置System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true") 在磁盘上写代理类;

四、代理源码解析

https://www.nhooo.com/note/qagnkd.html
https://my.oschina.net/u/4613350/blog/4810435

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值