IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> PHP知识库 -> [Java]代理 -> 正文阅读

[PHP知识库][Java]代理

代理

Java中有一个经典的设计模式叫做代理模式(Proxy),在我们平时开发和框架源码中无处不在。

在这里插入图片描述
这里可以看到,代理模式并没有改变对象A,而是换了一种方式访问对象A的方法,通过代理对象ProxyA来访问对象A,这样做的好处是——在A的基础上拓展,实现它的额外附加功能。

静态代理

创建一个接口ICar,里面有一个run方法,然后定义宝马的实现类来实现它:
在这里插入图片描述

public interface ICar {
    void run();
}

public class BmwCar implements ICar {
    @Override
    public void run() {
        System.out.println("宝马车跑起来了。");
    }
}

因为汽车需要启动才能跑,跑完以后需要熄火,毕竟油价挺贵的。新建一个CarProxy类:

/**
* 静态代理,与目标对象实现相同的接口或继承相同的父类
**/

public class CarProxy implements ICar {

    /**
     * 目标对象
     */
    private ICar target;

    public CarProxy(ICar target) {
        this.target = target;
    }

    @Override
    public void run() {
        System.out.println("汽车启动。。。");
        target.run();
        System.out.println("汽车熄火。。。");
    }
}

测试一下:

public class CarApp {
    public static void main(String[] args) {
        CarProxy carProxy = new CarProxy(new BmwCar());
        carProxy.run();
    }
}

运行结果如下图所示:
在这里插入图片描述
静态代理虽然在学习中经常会看到,但是在框架和实际编码中却不经常使用:
1.优点: 不修改目标对象的代码, 完成了目标对象的扩展。
2.缺点: 代理对象会随着目标对象的修改需要相应的修改。比如在ICar中加了接口,代理也需要做相应代码的修改。

静态代理的缺点过于明显了,有没有什么办法规避呢?
有,动态代理。

动态代理

JDK动态代理

代理类Proxy所在包:java.lang.reflect。核心方法是:

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)

调用调用该方法即可对目标对象生成对应的代理对象。
这里需要传入三个参数:

  • ClassLoader loader: 目标对象使用的类加载器,target.getClass().getClassLoader()
  • Class<?>[] interfaces: 目标对象实现接口类型,使用泛型方式类型,target.getClass().getInterfaces()
  • InvocationHandler h: 当执行目标对象的方法时,会先调用InvocationHandlerinvoke方法,
    同时把当前执行目标对象的方法作为参数传入。

ICarPro:

public interface ICarPro {
    /**
     * 汽车加油
     */
    void refueling();

    /**
     * 汽车运行
     */
    void run();
}

BenzProCar:

public class BenzProCar implements ICarPro {
    @Override
    public void refueling() {
        System.out.println("给我的大奔加油!");
    }

    @Override
    public void run() {
        System.out.println("大奔跑起来了。");
    }
}

CarProFactory:

public class CarProFactory {

    private ICarPro target;

    public CarProFactory(ICarPro target) {
        this.target = target;
    }

    //对目标对象包装成代理对象
    public Object genProxyBean() {
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("--操作前");
                        Object returnValue = method.invoke(target, args);
                        System.out.println("--操作后");
                        return returnValue;  //返回已经扩展后的代理对象
                    }
                }
        );
    }
}

测试运行:

public class CarApp {
    public static void main(String[] args) {
        CarProFactory carProFactory = new CarProFactory(new BenzProCar());
        ICarPro benz = (ICarPro)carProFactory.genProxyBean();
        benz.refueling();
        benz.run();
    }
}

运行结果:
在这里插入图片描述
JDK动态代理对象生成的类:

// $proxy0代理对象已经继承了jdk的Proxy, 所以JDK动态代理只能以实现ICarPro接口的方式完成
public class $proxy0 extends Proxy implements ICarPro

Cglib动态代理

无论是静态代理还是JDK动态代理,其本质是目标对象一定要实现一个接口。有时候我们写业务代码就是一个类,没有实现接口,这时候可以使用Cglib动态代理。
pom文件依赖引入:

<dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.3.0</version>
        </dependency>

建立CGLIB动态工厂类CarProxyFactoryByCglib

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

import java.lang.reflect.Method;

public class CarProxyFactoryByCglib implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println(method.getName()+"方法调用...");
        Object obj = methodProxy.invokeSuper(o, objects);
        System.out.println(method.getName()+"方法调用结束...");
        return obj;
    }
}

测试:

public class CarApp {
    public static void main(String[] args) {
        CarProxyFactoryByCglib cglibProxy = new CarProxyFactoryByCglib();
        Enhancer enhancer = new Enhancer();
        // 设置父类
        enhancer.setSuperclass(BenzProCar.class);
        // 设置回调对象
        enhancer.setCallback(cglibProxy);
        BenzProCar proxy = (BenzProCar) enhancer.create();
        proxy.refueling();
        System.out.println("1.加油完成");
        proxy.run();
        System.out.println("2.运行完成");
    }
}

运行结果:
在这里插入图片描述

  PHP知识库 最新文章
Laravel 下实现 Google 2fa 验证
UUCTF WP
DASCTF10月 web
XAMPP任意命令执行提升权限漏洞(CVE-2020-
[GYCTF2020]Easyphp
iwebsec靶场 代码执行关卡通关笔记
多个线程同步执行,多个线程依次执行,多个
php 没事记录下常用方法 (TP5.1)
php之jwt
2021-09-18
上一篇文章      下一篇文章      查看所有文章
加:2021-09-18 09:51:10  更:2021-09-18 09:52:35 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/16 23:51:11-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码