Java动态代理——Sping(5)

8 篇文章 0 订阅
6 篇文章 0 订阅
1 特点:字节码随用随创建,随用随加载
2 作用:不修改源码的基础上对方法增强
3 分类:
  • 基于接口的动态代理
  • 基于子类的动态代理
3.1 基于接口的动态代理:
  • 涉及的类:Proxy
  • 提供者:JDK官方
3.1.2 如何创建代理对象:

使用Proxy类中的newProxyInstance方法

3.1.3 创建代理对象的要求:

被代理类最少实现一个接口,如果没有则不能使用(此细节最重要)

3.1.4 newProxyInstance方法的参数:

(1) ClassLoader:类加载器 ,它是用于加载代理对象字节码的。和被代理对象使用相同的类加载器。固定写法。
(2) Class[]:字节码数组,它是用于让代理对象和被代理对象有相同方法。固定写法。
(3) InvocationHandler:用于提供增强的代码,它是让我们写如何代理。我们一般都是些一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的(此接口的实现类都是谁用谁写)。
详情可以查看类中的描述

3.1.5 分销和直销

(1) 直销:
用户直接从厂家购买商品,并由厂家提供售后,省去中间环节
(2) 分销:
在电商出现之前,我们大部分都是从分销商手中购买商品,并且通过分销商给我们提供售后服务
两种方式各有利弊,需要具体行业具体分析,再次不在赘述。
下面我们通过一个分销的方式来说明动态代理的实现方式
在这里插入图片描述
这里的经销商就起到一个代理的作用:


/**
 * 对生产商提供的要求
 */
public interface IProducer {
    /**
     * 生产商需要具有销售的功能
     * @param money
     */
    public void saleProduct(float money);
    /**
     * 需要提供售后支持功能
     * @param money
     */
    public void afterService(float money);
}


/**
 * 一个生产者
 */
public class ProducerImpl  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类型
        final ProducerImpl producer = new ProducerImpl();
        IProducer proxyProducer = (IProducer) Proxy.newProxyInstance(producer.getClass().getClassLoader(),
                producer.getClass().getInterfaces(),
                new InvocationHandler() {
                    /**
                     * 执行被代理对象的代理接口方法,都会经过该方法
                     * @param proxy 代理对象的引用(一般不用)
                     * @param method 当前执行的方法
                     * @param args 当前执行方法的返回参数
                     * @return 和当前被代理方法有相同的返回值
                     * @throws Throwable
                     */
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //定义object类型接收
                        Object returnValue = null;
                        //1. 获取方法执行的参数
                        Float money = (float) args[0];
                        //2. 判断当前方法是不是销售
                        if ("saleProduct".equals(method.getName())) {
                            returnValue = method.invoke(producer, money);
                        }
                        return returnValue;
                    }
                });
        proxyProducer.saleProduct(10000f);
    }

我们没有对ProductImpl做任何的操作就完成了商品的销售,那这种方式就是动态代理接口的实现方式,那如果我们把 IProducer proxyProducer = (IProducer) Proxy.newProxyInstance();换成 ProducerImpl proxyProducer = (ProducerImpl) Proxy.newProxyInstance 还可以实现动态搭理么,答案是否定的,如果我们一定要通过这种方式那又如何实现呢

3.2 基于子类的动态代理:
3.2.1 首先我们需要添加依赖

CGLib (Code Generation Library) 是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。CGLib 比 Java 的 java.lang.reflect.Proxy 类更强的在于它不仅可以接管接口类的方法,还可以接管普通类的方法。
CGLib 的底层是Java字节码操作框架 —— ASM。

<!--底层为字节码框架asm,不仅可以代理接口而且还可以代理普通类-->
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.1_3</version>
        </dependency>

这里我们可以看到asm的jar包已经为我们导入进来了
在这里插入图片描述

3.2.1 基于子类的动态代理:
  • 涉及的类:Enhancer
  • 提供者:第三方cglib
3.2.2 如何创建代理对象:

使用Enhancer类中的create方法

3.2.3 创建代理对象的要求:

被代理类不能是最终类

3.2.4 create方法的参数:

(1) Class:指定一个类的字节码 它是用于指定被代理对象的字节码,要想搭理谁就写谁的xx.class。固定写法。
(2) callback:用于提供增强的代码它是让我们写如何代理。我们一般都是些一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。我们一般写的都是该接口子接口实现:MethodInterceptor

代码实现`

/**
 * 一个生产者
 */
public class Producer{

    /**
     * 销售
     * @param money
     */
    public void saleProduct(float money){
        System.out.println("销售产品,并拿到钱:"+money);
    }

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


public class Client {

    public static void main(String[] args) {
        final Producer producer = new Producer();
        Producer cglibProducer = (Producer)Enhancer.create(Producer.class, new MethodInterceptor() {

            /**
             * 执行被代理对象的任何方法都可以经过该方法
             * @param o
             * @param method
             * @param objects
             * 以上三个参数和基于接口的代理方法参数是一样的
             * @param methodProxy:当前执行方法的代理对象
             * @return
             * @throws Throwable
             */
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                //定义一个Object类型的对象
                Object returnValue = null ;
                //接收参数
                Float money = (Float) objects[0];
                if("saleProduct".equals(method.getName())){
                  returnValue = method.invoke(producer,money*0.8f);
                }
                return returnValue;
            }
        });
        cglibProducer.saleProduct(10000f);

    }
}

以上两种代理都可以对我们已有的方法进行增强,添加我们需要的内容
那这个动态代理我们可以用在什么呢

  • 全站中文乱码的问题
  • 连接池中close(),不能真正的关闭,可以使用方法增强实现真正的关闭
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值