代理模式——Java

代理模式

在Java中代理模式是一种设计模式,是通过代理类来代替原始的对象,可以在不改变原始对象的基础上,对它进行扩展(新增一些新功能)。在目标方法的执行的执行前后添加一些自定义的方法。

静态代理

步骤:
1.创建一个接口以及它的实现类
2.创建它的代理类实现该接口(重写接口中的方法,自定义一些新功能)
3.在代理类中注入目标类,并且调用代理类中的相关方法。
具体实现如下:
(1.)接口和其实现类

public interface SsSercive {void say(String message);
}

实现类

public class ImpService implements SsSercive {public void say(String message){System.out.println("信息:"+message);}
}

(2)代理类[也要实现该接口,并重写接口中的新方法,自定义新功能]

public class ProxyImpl implements SsSercive {private final SsSercive service;//构造器public ProxyImpl(SsSercive service){this.service=service;}@Overridepublic void say(String message) {System.out.println("操作前可以添加一些方法");service.say(message);System.out.println("操作后面也可以添加一些操作");}
}

(3)真正实现

public class Main {public static void main(String[] args) {SsSercive service=new ImpService();//在代理类中调用目标类ProxyImpl proxy=new ProxyImpl(service);//调用代理类中的相关方法proxy.say("hello world");}
}

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

总结:
在静态代理中,对目标类的每个方法的增强都是手动的(因为代理类实现接口要重写各个方法),一个目标类对应一个代理类,因此十分不灵活,扩展性差。
从JVM角度来说,静态编译在接口中就将接口类、实现类、代理类转化成为class文件。

动态代理

动态代理不需要为每一个目标类创建一个代理类,也可以不实现接口(CGLIB动态代理不需要实现接口)。
从JVM角度来看,动态代理是在运行时生成类字节码,并且加载到JVM中。

JDK动态代理

JDK动态代理还是需要实现接口类Invocation,核心是Proxy代理类
(1.)接口类

public interface SsSercive {void say(String message);void send(String name);
}

实现类

public class ImpService implements SsSercive {@Overridepublic void say(String message){System.out.println("信息:"+message);}@Overridepublic void send(String name) {System.out.println("发送:"+name);}
}

(2)代理类

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
//代理类实现InvocationHandler接口
public class DebugInvocationHandler implements InvocationHandler {private Object target;public DebugInvocationHandler(Object target){this.target=target;}@Override/*proxy:是动态代理生成的代理类method:调用的相关方法args:调用方法的相关参数*/public Object invoke(Object proxy, Method method,Object[] args) throws InvocationTargetException, IllegalAccessException {System.out.println("方法之前可以添加一些功能:"+method.getName());//动态代理调用的是invoke方法,invoke方法代替我们去调用原方法Object result=method.invoke(target,args);System.out.println("方法之后可以添加一些功能:"+method.getName());return result;}
}

(3)代理对象的工厂类

import java.lang.reflect.Proxy;
public class JdkProxyFactory {
//getProxy方法的本质是调用Proxy.newProxyInstance( ),获取某个类的代理对象public static Object getProxy(Object target){return Proxy.newProxyInstance(target.getClass().getClassLoader(),//类加载器target.getClass().getInterfaces(),//代理对象实现的接口new DebugInvocationHandler(target)//自定义实现的Invocation接口);}
}

(4)实际使用

public class Main {public static void main(String[] args) {SsSercive service=(SsSercive) JdkProxyFactory.getProxy(new ImpService());service.send("hello World");service.say("我是张三");}
}

(5)运行结果
在这里插入图片描述

CGLIB动态代理

(1)引入依赖
说明:Spring Boot 的 parent POM(如 spring-boot-starter-parent)已经为所有常用 Spring 模块定义好了兼容版本。显式指定版本可能导致找不到依赖或版本冲突,所以可以不用显示指定版本。

<dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId></dependency>

(2)目标类

public class ImpService  {public void send(String name) {System.out.println("发送:"+name);}
}

(3)自定义方法拦截器

mport org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;import java.lang.reflect.Method;public class DebugMethodInterceptor implements MethodInterceptor {@Overridepublic Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {//调用方法之前,我们可以添加自己的操作System.out.println("before method " + method.getName());Object object = methodProxy.invokeSuper(o, args);//调用方法之后,我们同样可以添加自己的操作System.out.println("after method " + method.getName());return object;}}

(4)代理类

import org.springframework.cglib.proxy.Enhancer;public class CglibProxyFactory {public static Object getProxy(Class<?> clazz) {// 创建动态代理增强类Enhancer enhancer = new Enhancer();// 设置类加载器enhancer.setClassLoader(clazz.getClassLoader());// 设置被代理类enhancer.setSuperclass(clazz);// 设置方法拦截器enhancer.setCallback(new DebugMethodInterceptor());// 创建代理类return enhancer.create();}
}

(5)使用

 public static void main(String[] args) {ImpService SmsService = (ImpService) CglibProxyFactory.getProxy(ImpService.class);SmsService.send("java");

(6)运行结果
在这里插入图片描述

JDK动态代理与CGLIB动态代理的区别

(1)JDK动态代理只能直接代理接口类或是代理实现接口的类,
CGLIB动态代理可以代理不实现任何接口的类。
(2)CGLIB在运行时生成代理类的子类,不需要通过实现接口,因此不能代理声明为final的类。

动态代理与静态代理的区别

(1)JVM角度:静态代理在编译时就将接口、实现类、代理类生成class文件,
而动态代理在运行时动态生成类字节码,并加载到jvm中。
(2)动态代理要比静态代理更加灵活,不用必须实现接口,可直接代理。不用针对每个目标类实现一个代理类。对于目标类中方法的改动,静态代理需要对代理类、目标对象进行修改,十分麻烦。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/88747.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/88747.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于Catboost算法的茶叶数据分析及价格预测系统的设计与实现

文章目录有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主项目介绍数据采集数据预处理数据分析与可视化大屏设计模型构建系统展示每文一语有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主 项目介绍 本研究基于京东官网…

【数据库基础 1】MySQL环境部署及基本操作

目录 一、MySQL部署 1.更新软件包列表 2.查看合适的安装包&#xff1a; 3.安装MySQL 4.启动数据库服务并设置开机自启 5.检测MySQL当前状态 6.配置文件修改 二、基本操作指令 1.登陆MySQL 2.创建用户&修改用户密码 3.查看版本 4.退出MySQL 5.停止MySQL 6.数据…

(C++)任务管理系统(正式版)(迭代器)(list列表基础教程)(STL基础知识)

源代码&#xff1a;#include <iostream> #include <list> #include <string>using namespace std;void menu(){cout<<"\n 任务管理系统 "<<endl;cout<<"1.添加普通任务"<<endl;cout<<"2.添加紧急任务…

创建uniapp项目引入uni-id用户体系使用beforeRegister钩子创建默认昵称

需求描述 基于uniCloud开发项目&#xff0c;通常会使用用户体系&#xff0c;uni-id就是基于uniCloud的用户体系&#xff0c;满足常规需要的账号密码注册、登录&#xff0c;微信登录等快捷方式&#xff0c;如果使用uni-id自带的uni-id-pages插件&#xff0c;账号密码注册的话&a…

Opencv---深度学习开发

在OpenCV中进行深度学习开发&#xff0c;主要围绕其dnn模块展开&#xff0c;该模块支持加载预训练模型、预处理输入数据、执行推理计算以及解析输出结果。本文讲解基于OpenCV进行深度学习开发的基本流程。 一、准备工作 在开始开发前&#xff0c;需完成环境配置和资源准备&…

【C++11】右值引用详解

文章目录前言1. 左、右值的概念1.1 左值1.2 右值1.3 右值引用2. 右值引用的价值和使用场景2.1 左值引用的价值和缺陷2.2 右值引用的价值和使用场景2.3 小结3. 完美转发4. 类的移动构造和移动赋值前言 在C11之前&#xff0c;面对C11之前出现的临时对象的传参构造&#xff0c;都…

如何用自指理解世界

自指即自我指涉&#xff0c;即自己的描述关联到了自己&#xff0c;典型例子是“这句话是假话”这个悖论。人类对自指的研究由来已久&#xff0c;很多概念、定理都与之相关&#xff0c;由于它的巧妙性&#xff0c;很多学者对其展开了深入研究&#xff0c;并且认为自指是理解宇宙…

Next.js 实战笔记 2.0:深入 App Router 高阶特性与布局解构

Next.js 实战笔记 2.0&#xff1a;深入 App Router 高阶特性与布局解构 上一篇笔记&#xff1a; Next.js 实战笔记 1.0&#xff1a;架构重构与 App Router 核心机制详解 上篇笔记主要回顾了一些 Next12 到 Next15 的一些变化&#xff0c;这里继续学习/复习一些已有或者是新的…

TCP 传输时 sk_buff 的 clone 和 unclone

周一有位朋友咨询个问题&#xff0c;问题本身不重要&#xff0c;但牵扯出的细节却是非常有趣。 Linux 内核协议栈的 skb 设计非常高效和精巧&#xff0c;多个 skb 可以指向同一块 data&#xff0c;这就是 clone&#xff0c;当 data 不止一个 skb 指示时&#xff0c;任何一个 s…

【51单片机】51单片机学习笔记-课程简介

00. 目录 文章目录00. 目录01. 学习哪种类型的单片机02. 学习单片机方法03. 学习单片机硬件设备04. 学习单片机软件设备05. 学完单片机能做什么06. 附录01. 学习哪种类型的单片机 单片机的型号那么多&#xff0c;该如何选择一款合适的进行学习呢&#xff1f;这里给读者首推的当…

【Docker基础】Docker端口映射(-p参数)深度解析与实践指南

目录 前言 1 Docker网络基础 1.1 Docker网络模型概述 1.2 容器网络隔离性 2 端口映射基础 2.1 端口映射概念 2.2 为什么需要端口映射 3 -p参数详解 3.1 基本语法 3.2 四种映射格式 3.2.1 完整格式 3.2.2 省略宿主机IP 3.2.3 随机宿主机端口 3.2.4 指定协议类型 …

2、鸿蒙Harmony Next开发:ArkTS语言

目录 什么是ArkTS&#xff1f; ArkTS的发展趋势 ArkTS的定位及约束 ArkTS的对UI的拓展 1、UI描述 2、状态管理&#xff1a; ArkTS语法基础 基本知识&#xff1a;声明 基本知识&#xff1a;类型 基本知识&#xff1a;空安全 基本知识&#xff1a;类型安全与类型推断 …

【Elasticsearch】function_score

如果你希望在 Elasticsearch 查询中降低某些特定 `id` 的文档评分,可以通过 `function_score` 查询结合 `script_score` 函数来实现。`script_score` 允许你使用自定义脚本对文档的评分进行调整。 以下是一个示例,展示如何降低某些特定 `id` 的文档评分: 示例场景 假设我们…

vscode打开stm32CubeIDE的项目的注释问题

文章目录 目的是为消除红色底线打开命令面板&#xff1a;CtrlShiftP 搜索并打开&#xff1a;C/C: Edit Configurations (JSON) 修改并添加。&#xff08;注意里面的版本号&#xff09; {"configurations": [{"name": "Win32","includePath&…

ESP32使用freertos更新lvgl控件内容

LVGL不是线程安全&#xff0c;所有 lv_xxx方法只能在GUI主线程调用。 freertos都是线程池&#xff0c;子线程&#xff0c;不能直接更新lvgl&#xff0c;不然看门狗被触发&#xff0c;死机。 推荐方法案例&#xff1a; 假如搜索wifi列表得到参数是wifi_options&#xff0c;需要通…

OBOO鸥柏丨满天星(MTSTAR)多媒体信息发布系统技术解析

初次启动欢迎您使用鸥柏(OBOO)满天星(MTSTAR)多媒体信息发布系统&#xff0c;在使用本系统的独立服务器模式前&#xff0c;我们需要完成设备的一些必须设置教程技术说明。其总体流程分为两步&#xff1a;录入本地服务器IP地址->连接网络您获取到的OBOO鸥柏满天星(MTSTAR)液晶…

数据结构:栈、队列、链表

目录 栈 ​队列 链表 栈 栈数据结构特点&#xff1a;先入栈的数据后出&#xff0c;此数据结构常用的方法有&#xff1a;入栈push、出栈pop、查看栈顶元素peek等&#xff0c;下方示例以数组实现栈结构。 package com.ginko.datastructure; import lombok.extern.slf4j.Slf4j…

Python-难点-uinttest

1 需求要求&#xff1a;unittest.TestCase放在列表中&#xff0c;列表存储的是脚本文件名import使用动态加载方式&#xff1a;importlib.import_module()unittest.TestLoader使用loadTestsFromModule()2 接口3 示例4 参考资料

开源 python 应用 开发(五)python opencv之目标检测

最近有个项目需要做视觉自动化处理的工具&#xff0c;最后选用的软件为python&#xff0c;刚好这个机会进行系统学习。短时间学习&#xff0c;需要快速开发&#xff0c;所以记录要点步骤&#xff0c;防止忘记。 链接&#xff1a; 开源 python 应用 开发&#xff08;一&#xf…

ABP VNext + OpenTelemetry + Jaeger:分布式追踪与调用链可视化

ABP VNext OpenTelemetry Jaeger&#xff1a;分布式追踪与调用链可视化 &#x1f680; &#x1f4da; 目录ABP VNext OpenTelemetry Jaeger&#xff1a;分布式追踪与调用链可视化 &#x1f680;背景与动机 &#x1f31f;环境与依赖 &#x1f4e6;必装 NuGet 包系统架构概览…