JDK动态代理和CGLIB动态代理案例

动态代理

特点

字节码随用随创建,随用随加载

作用

不修改源码的基础上对方法增强

分类

基于接口的动态代理和基于子类的动态代理。
基于接口的动态代理涉及的类:Proxy。提供者JDK官方,也就是我们常说的JDK动态代理。
基于子类的动态代理第三方cglib库

JDK动态代理

使用Proxy类中的newProxyInstance方法创建代理对象,并且要求被代理对象最少实现一个接口,如果没有实现接口则没有办法使用。

newProxyInstance方法的参数:

ClassLoader

类加载器:它是用于加载代理对象字节码的。和被代理对象使用相同的类加载器。固定写法。

Class[]

字节码数组:它是用于让代理对象和被代理对象有相同方法。固定写法。

InvocationHandler

用于提供增强的代码:它是让我们写如何代理。我们一般都是些一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。此接口的实现类都是谁用谁写。

案例

以生产厂家卖东西为例,现在不需要厂家直接卖,而是通过一个代理对象,可以理解为现实生活中的经销商,他们来给我们提供销售服务。
首先定义一个接口,有两个方法,一个是销售方法,也就是拿到钱给货的方法,还有一个就是售后服务方法。我们只以销售方法为例来编写。

public interface IProducer {

    public void saleProduct(float money);

    public void afterService(float money);
}

然后定义一个生产商需要实现这个接口。

public class Producer implements IProducer{

    public void saleProduct(float money){
        System.out.println("拿到钱销售" +money);
    }

    public void afterService(float money){
        System.out.println("提供售后服务,并拿到钱"+money);
    }
}

最后我们可以模拟一个客户端进行客户消费,我们从代理对象那里买到商品。当然代理需要实现一些操作。一般代理商肯定会赚差价哈哈。我们可以理解为这是一个方法的增强逻辑,通过动态代理实现。

public class Client {
    public static void main(String[] args) {
        final Producer p = new Producer();
        IProducer proxyInstance = (IProducer) Proxy.newProxyInstance(p.getClass().getClassLoader(),
                p.getClass().getInterfaces(), new InvocationHandler() {
                    /**
                     * 作用:执行被代理对象的任何接口方法都会经过该方法
                     * 方法参数的含义
                     * @param proxy   代理对象的引用
                     * @param method  当前执行的方法
                     * @param args    当前执行方法所需的参数
                     * @return 和被代理对象方法有相同的返回值
                     * @throws Throwable
                     */
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        /*
                        增强代码
                         */
                        Object returnvalue=null;
                        float money =(Float)args[0];
                        // 这里只对销售方法进行增强,也就是代理商进行销售的时候从中截取20%的资金。
                        if ("saleProduct".equals(method.getName())){
                            returnvalue=method.invoke(p,money*0.8f);
                        }
                        return returnvalue;
                    }
                });
                //代理对象调用方法
        proxyInstance.saleProduct(100000f);
    }

}

程序运行输出结果如下:

拿到钱销售80000.0

cglib动态代理

涉及的类

Enhancer类 ,使用Enhancer类中的create方法进行创建

create方法参数

Class

字节码:用于指定被代理对象的字节码

Callback

用于提供增强的代码:它是让我们写如何代理。一般都是该接口的实现类,通常情况下使用匿名内部类,但不是必须的,此接口的实现类都是谁用谁写。
我们一般写的都是该接口的子接口的实现类:MethodInterceptor

========================

此时不要求被代理对象实现接口,但是要求被代理对象不是最终类,也就是说不能是final修饰,具体的底层原理目前还不太清楚。先把案例给出来。后期原理再慢慢补充。

案例

前提我们需要第三方库,因为我用的是maven创建的工程,直接导一个坐标就可以了。

<dependencies>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2</version>
        </dependency>
</dependencies>

只需要这么一个坐标就可以了。
同样模拟上述卖货的操作,只是此时我们创建的类不需要实现接口。
只需要有这么一个Producer类。

public class Producer {

    public void saleProduct(float money){
        System.out.println("拿到钱销售" +money);
    }

    public void afterService(float money){
        System.out.println("提供售后服务,并拿到钱"+money);
    }
}

客户端模拟销售操作。

public class Client {
    public static void main(String[] args) {
        final Producer p = new Producer();


        Producer cglibporducer = (Producer) Enhancer.create(p.getClass(), new MethodInterceptor() {

            /**
             *执行此代理对象的任何方法都会经过该方法
             * @param proxy  代理对象的引用
             * @param method 当前执行的方法
             * @param args 当前执行方法所需的参数
             * 以上三个参数和基于接口中的动态代理中invoke方法参数是一样的
             * @param methodProxy 当前执行方法的代理对象
             * @return
             * @throws Throwable
             */
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                /*
                        增强代码
                         */
                Object returnvalue = null;
                // 获取执行方法的参数
                float money = (Float) args[0];
                // 判断是否为销售
                if ("saleProduct".equals(method.getName())) {
                    returnvalue = method.invoke(p, money * 0.8f);
                }
                return returnvalue;
            }
        });
        cglibporducer.saleProduct(1000);
    }
}

执行输出结果如下:

拿到钱销售800.0

这样我们就通过两种方式实现了动态代理。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值