jdk动态代理的示例

概述

要学习动态代理,首先要了解一下什么是“代理”,其实也可能称为代理模式。就是当你无法操作某一个java对象的时候,又想调用对象内部的方法的话,此时就需要用到一个“代理对象”来帮你调用你想调用的对象的方法。
其实代理的话,又分静态代理和动态代理。静态代理很简单,实现同一个接口然后调用方法即可。而动态代理不需要实现同一个接口,可以直接运用java的反射模式来获取class类,获取method类,根据字节码来调用你想调用的方法。对于代理模式更详细可以看一下我之前写的文章:Java反射怎么用,反射的原理及简单使用实例.

静态代理

静态代理的话,首先先看如下关系图。
如果我们想在Store.sell()调用前在控制台中打印一段日志,此时就可以使用一个ProxyStore代理类,去代理调用Store.sell()方法,在调用前打印日志(当然这简单的场景不只是代理能实现,还有很多方式可以实现)
在这里插入图片描述
此时可以看一下实际代码是怎么写的
首先先创建接口IStore

public interface IStore() {
    public void sell();
}

其次创建两个子类

public class Store() implements IStore {
    public void sell() {
        system.out.println("sell....");
    }
}
public class ProxyStore() implements Istore {
    private Store store;
    
    public ProxyStore (Store store) {
        this.store = store
    }

    public void sell() {
        System.out.println("proxyStore sell...");
        store.sell();
    }

}

实际调用的代码为

public class TestProxy() {
    
    @Test
    public void testProxy() {
        IStore store = new ProxyStore(new Store());
        store.sell();
    }
    
}

此时这一顿操作,就能不直接调用Store对象,也能调用到Store对象的sell方法,并且在sell方法之前增加了打印日志。

痛点

然后又有一个场景,除了sell方法,也需要在buy方法,以及close方法中增加同一段日志,那这个时候如果又像刚才静态代理实现的话,就需要给sell/buy/close都要代理,此时就需要重复写三段代码,并且比较繁琐,所以此时其实可以使用动态代理来实现当前功能。

jdk动态代理

对于java的动态代理实现的话,目前有两种方式,一种是基于jdk实现的动态代理,一种是基于第三方工具cglib实现的动态代理,先说一下基于jdk的实现方式。
基于jdk使用动态代理的话,不像静态代理那样,代理类需要实现接口IStore接口。代理类是需要实现特定的接口的,最主要涉及到的两个类为
在这里插入图片描述
Proxy、InvocationHandler(接口),使用这两个java.lang.reflect包下的类,实现动态代理。
此篇文章只是简单介绍如何创建及使用动态代理,并不会跟源码进行深层的逻辑(再下一篇文章中会介绍到jdk动态代理的源码跟踪及实现原理)
首先我们使用动态代理的话,需要有以下步骤

1、创建继承InvocationHandler接口的对象,重写invoke方法
2、调用Proxy.newProxyInstance()创建代理对象
3、代理对象调用方法即可
// 创建继承InvocationHandler接口的对象
public class ProxyStore implements InvocationHandler() {
    // 此Object为反射调用方法的class对象
    private Object object;
    
    public ProxyStore(Object iStore) {
        this.object = object
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable() {
        System.out.println("proxy running.....");
        /**
            1、method是从class中获取到的method对象
            2、method.invoke()就是反射调用的方法,object为当前调用此方法的类
            3、return/args这些就没啥好说的了
        */
        return method.invoke(object, args);
    }

}
// 看一下调用流程
public void TestJDkProxy() {
    
    // 通过动态代理,调用ChinaStore的sell/buy方法
    public static void main(String[] args) {
        // 1、创建ChinaStore对象
        ChinaStore chinaStore = new ChinaStore();
        // 2、需要创建上方我们新建的handler类(传递的object为chinaStore)
        InvocationHandler proxyHandler = new ProxyStore(chinaStore);
        // 3、通过Proxy.newProxyInstance()创建代理类
        // 解释一下这里做的事情
        // 首先传递第一个参数为,我们需要调用的对象的classLoader第二个参数为我们需要调用的对象的子类,此时Proxy是会找到对象以及对象的子类,将所有方法都找出来。然后存储到代理对象村
        // 然后传递handler,handler重写了invoke方法,相当于一个回调函数,之后代理对象调用的所有方法实际上都是再invoke中使用反射调用方法。
        IStore store = (IStore) Proxy.newProxyInstance(chinaStore.getClass().getClassLoader, chinaStore.getClass().getInterfaces(), proxyHandler)
        // 4、调用方法,此时要注意,这里不是真的直接调用store.sell方法,sotre是一个代理对象,此时是会先进入到invoke中,在invoke中调用method.invoke()来调用sell方法
        store.sell();
    }

}

所以综合来看,使用动态代理的方式其实挺简单的,最主要就是跟着上面的步骤走就行。
虽然到了这里,还不知道动态代理的实现原理是怎样的,但是没关系,后续的文章会说,并且会说一下cglib的实现

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值