基于接口的动态代理和基于子类的动态代理

2019-11-27  本文已影响0人  吃伏冒有礼貌

代理的分析

举个例子,以前我们购买电脑的时候,我们直接找到厂家购买电脑,厂家也会对我购买的电脑进行售后,在那个时候,购买与售后都由厂家负责.


一开始我们和厂家有直接的联系

但是后来,生产厂家随着时间的发展和推移,各种销量和生产的提升,生产厂家发现既要生产,又要销售和售后压力很大


这个时候生产厂家运营成本主要为两个功能 1 生产 2销售和售后,l
那么作为生产厂家来说,不希望销售和售后给他带来很大的生产压力,代理商就因应而生
我们再购买电脑时就不能直接与厂家联系了,而是跟代理商联系

当电脑出现了质量问题,我们也是去找经销商.经销商再去找厂家帮我们维修.


不管是销售和售后,我们都不需要再直接与生产厂家保持联系了,生产厂家的压力也被缓解了
我们使用代理机制,可以实现对业务流程的增强,同时代理商和生产厂家之间也会些要求,比如找谁作为代理商,或者说代理商找什么样的生产厂家
代理分析
我们如何再程序中体现刚刚分析的

基于接口的动态代理

代理者想要销售产品时,对选择生产厂家有必要的准则,1是提供产品 2.是提供售后
在Java程序中,我们需要接口来提供这个规范
创建一个生产者的接口,这个生产者有两个功能:1,销售商品 2,售后服务,我们为它写两个方法,saleProduct 和
afterService,参数是销售的金额

IProductor

package proxy;

public interface IProductor {
    void saleProduct(Float money);
    void afterService(Float money);
}

ProductorImpl

package proxy;

public class ProductorImpl implements IProductor {

    public void saleProduct(Float money) {
        System.out.println("销售产品,并拿到钱:"+money);
    }
    public void afterService(Float money) {
        System.out.println("提供产品售后,并拿到钱:"+money);
    }
}

作为一个消费者,就要去购买了,我们创建一个Client类,模拟一个消费者.
原来购买产品的时候,通过生产厂家直接买,直接找到生产厂家,付款.

package proxy;

import java.lang.reflect.Proxy;

public class Client {
    public static void main(String[] args) {
       IProductor productor = new ProductorImpl();
        productor.saleProduct(10000f);   
    }
}

而现在,我们需要代理来完成这个功能,不再需要直接与生产厂家接触了.
当代理出现后,我们如何去连接这个代理呢?
动态代理

动态代理分两类:

基于接口的动态代理

invoke
* 作用:执行被代理对象的任何接口方法都会经过此方法(也就是该方法有一个拦截个功能)
* proxy:代理对象的引用
* method:当前执行的方法
* args:当前执行方法所需要的参数
* 和被代理的对象有相同的返回值

image.png
当我们把这些东西都分析完之后,其实只需要在return这个地方return method.invoke,第一个参数Object指的是谁的方法,这个方法就是被代理对象的方法,第二个args就是被代理对象的参数.
image.png
当匿名内部类访问外部成员方法时,外部成员方法要用final修饰
这里我们被代理对象时productor,当写上productor时,因为匿名内部类访问外部成员时要用final修饰,之前定义productor的地方用上final修饰
final IProdctor productor
写到这里其实只是写出了一个代理对象,并没有增强方法,要实现代码增强,还要写代码.
我们的思路就是消费者购买产品的时候给了10000,但是作为代理商,需要提取20%作为利润,生产厂家只能拿到8000块
那么如何去做这个操作呢?
第一步,获取方法执行的参数
第二步,判断当前方法是不是销售
增强的代码

提醒money * 0.8f的时候记得带f,否则会报错
Exception in thread "main" java.lang.IllegalArgumentException: argument type mismatch

money * 0.8 * f

这段代码写完以后,我们并没有对saleProduct进行改变,但我们已经实现了方法的增强,这就是基于接口的动态代理,但是它有一个问题如果我们的类不实现任何一个接口的时候,它是无法执行的

基于子类的动态代理

针对于我们的类不实现任何接口的情况,我们怎么解决我们如何代理一个普通的java类呢?
这时候就要用到基于子类的动态代理
之前有略微提到,基于子类的动态代理,提供者为第三方,叫cglib.
所以在pom.xml导入cglib的依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.itheima</groupId>
    <artifactId>day03_eesy_02proxy</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <maven.compiler.source>12</maven.compiler.source>
        <maven.compiler.target>12</maven.compiler.target>
    </properties>
    <dependencies>
        <!-- https://mvnrepository.com/artifact/cglib/cglib -->
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2.2</version>
        </dependency>
    </dependencies>
</project>

就在基于接口的动态代理的工程中,新建一个名叫cglib的pacage,复制ProductorImpl和Client进去,并修改ProductorImpl文件名为Productor,Productor不再实现任何接口


,复制ProductorImpl和Client进去,并修改ProductorImpl文件名为Productor

Productor 类如下:

package cglib;

public class Productor{

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

    public void afterService(Float money) {
        System.out.println("提供产品售后,并拿到钱:"+money);
    }
}
MethodInterceptor可以看到是继承了Callback类 Client

完整代码如下

package cglib;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import proxy.IProductor;

import java.lang.reflect.Method;

public class Client {


    public static void main(String[] args) {
        final Productor productor = new Productor();

        Productor CglibP = (Productor) Enhancer.create(productor.getClass(), new MethodInterceptor() {

            @Override
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                Object invoke = null;
                Float money = (Float) args[0];
                if ("saleProduct".equals(method.getName())) {
                    invoke = method.invoke(productor, money * 0.8f);
                }
                return invoke;
            }
        });
        CglibP.saleProduct(20000f);
    }
}

上一篇下一篇

猜你喜欢

热点阅读