Aop切面编程(2)--代理模式

news2024/11/15 10:16:37

1、代理模式的理解:不修改A对象的代码的基础上,对A代码块进行拓展。通过创建ProxyA代理对象,拓展A对象并调用A对象的核心功能;

即:不修改对象的源码基础上,创建代理对象,进行功能的附加和增强;

2、代理的分类:1)静态代理;2)动态代理(jdk,cglib);

3、静态代理:在编译的过程中就已经将代理对象、被代理对象、接口确定下来了,class文件已经生成了;

实现步骤:
1、定义一个接口及其实现类;
2、创建一个代理类同样实现这个接口
3、将目标对象注注入进代理类,然后在代理类的对应方法调用目标类中的对应方法。

3.1)定义一个接口及方法ParentPrint:

package com.example.demo.proxy;

public interface ParentPrint {
    void print(String content);
}

3.2)定义一个被代理的类,并实现接口ParentPrint,其中print方法就是我们需要代理的核心方法;

package com.example.demo.proxy;


public class Printer implements  ParentPrint {

    @Override
    public void print(String content) {
        System.out.println(content);
    }
}

3.3)定义代理类,构造一个有参数的构造器,并重写print方法(其中通过传入的参数调用被代理对象的print方法)。

package com.example.demo.proxy;

/*
1、首先需要代理类ProxyStaticPrinter和被代理类Printer同时实现一个共同的接口 ;
2、代理类ProxyStaticPrinter需要在构造方法中注入接口定义对象,并重写代理的方法print(前置后置处理),在其中加入注入对象的print方法;
3、实例化代理对象ProxyStaticPrinter,实例化被代理对象Printer;
4、将被代理对象通过参数注入到代理对象(ProxyStaticPrinter)有参构造器中;
5、代理对象调用处理过的方法;
*/
public class ProxyStaticPrinter implements ParentPrint {

    private ParentPrint parentPrint;


    public ProxyStaticPrinter(ParentPrint parentPrint) {
        this.parentPrint = parentPrint;
    }

    @Override
    public void print(String content) {
        System.out.println("前置操作");
        parentPrint.print(content);
        System.out.println("后置操作");
    }

}


3.4)测试,定义一个代理对象,将代理对象通过参数传入被代理的对象中;

    //测试
    public static void main(String[] args) {
        ParentPrint parentPrint = new Printer();
        ParentPrint ProxyParentPrint = new ProxyStaticPrinter(parentPrint);
        ProxyParentPrint.print("测试");
    }

运行

3.5)总结:

目标对象注注入进代理类,然后在代理类的对应方法调用目标类中的对应方法。这样的话,我们就可以通过代理类屏蔽对目标对象的访问;

优点:被代理类无需实现接口
缺点:只能代理这个类,要想代理其他类,要想代理其他类需要写新的代理方法。

4、动态代理:动态代理包含了jdk动态代理和cglib动态代理;

4.1)jkd动态代理:

实现步骤:
1、定义一个接口及其实现类;
2、自定义 InvocationHandler 并重写invoke方法,在 invoke 方法中我们会调用原生方法(被代理类的方法)并自定义一些处理逻辑;
3、通过 Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) 方法创建代理对象;

4.1.1)定义一个接口

package com.example.demo.proxy;

public interface ParentPrint {
    void print(String content);
}

4.1.2)定义一个接口及方法ParentPrint:

package com.example.demo.proxy;

public interface ParentPrint {
    void print(String content);
}

4.1.3)定义一个被代理的类,并实现接口ParentPrint,其中print方法就是我们需要代理的核心方法;

package com.example.demo.proxy;


public class Printer implements  ParentPrint {

    @Override
    public void print(String content) {
        System.out.println(content);
    }
}

4.1.4)定义一个代理类ProxyJdkPrinter并实现InvocationHandler,实现invoke方法,最终调用method.invoke(parentPrint,args);

注意该Proxy类中是静态方法,且接收的三个参数依次为:

ClassLoader loader:指定当前目标对象使用类加载器,获取加载器的方法是固定的。
Class<?>[] interfaces:目标对象实现的接口的类型,使用泛型方式确认类型。
InvocationHandler:事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入。

package com.example.demo.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;


/*jdk动态代理:前提目标类必须有父接口(接口:ParentPrint,目标类:Printer)
1、创建ProxyJdkPrinter类,继承接口InvocationHandler创建代理类的调用处理程序;
2、同样引入代理类的参数对象private ParentPrint parentPrint;
3、实现invoke方法,最终调用method.invoke(parentPrint,args);
4、测试:
实例化代理类p1;
将p1放入代理类ProxyJdkPrinter;
通过Proxy类的WuDaInvocationHandler方法创建代理对象;
代理对象调用被代理的方法;
* */
public class ProxyJdkPrinter implements InvocationHandler {

    private ParentPrint parentPrint;


    public ProxyJdkPrinter(ParentPrint parentPrint) {
        this.parentPrint = parentPrint;
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String name = method.getName();
        if(name.equals("print")){
            System.out.println("jdk增加操作");
        }
        return method.invoke(parentPrint,args);
    }

}


4.1.5)测试,invoke() 方法: 当我们的动态代理对象调用原生方法的时候,最终实际上调用到的是 invoke() 方法,然后 invoke() 方法代替我们去调用了被代理对象的原生方法。

    public static void main(String[] args) {
        ParentPrint p1 = new Printer();
        ProxyJdkPrinter proxyJdkPrinter = new ProxyJdkPrinter(p1);
        //newProxyInstance:创建代理实例对象
        //三个参数:
        //1、 目标类的类加载器 2、目标类的父接口  3、handler
        ParentPrint proxyPrint = (ParentPrint)Proxy.newProxyInstance(p1.getClass().getClassLoader(), p1.getClass().getInterfaces(), proxyJdkPrinter);
        proxyPrint.print("测试");
    }

运行

4.1.6)总结:

通过java提供的Proxy类帮我们创建代理对象,基于接口的动态代理需要利用JDK中的API,在JVM内存中动态的构建Proxy对象;
优点:可以生成所有实现接口的代理对象
缺点:JDK反射生成代理必须面向接口, 这是由Proxy的内部实现决定的。生成代理的方法中你必须指定实现类的接口,它根据这个接口来实现代理类生成的所实现的接口。

4.2)cglib动态代理:当目标没有实现类的时候,可以使用;

实现步骤:

1、定义一个类;
2、自定义 MethodInterceptor 并重写 intercept 方法,intercept 用于拦截增强被代理类的方法,和 JDK 动态代理中的 invoke 方法类似;
3、通过 Enhancer 类的 create()创建代理类;

4.2.1)定义一个被代理类Printer

package com.example.demo.proxy;


public class Printer1 {

    public void print(String content) {
        System.out.println(content);
    }
}

4.2.2)定义一个代理类ProxyCglibPrinter,并实现MethodInterceptor

package com.example.demo.proxy;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;


/*cglib动态代理:(目标对象不需要实现接口)
实现MethodInterceptor 接口,在调用目标对象的方法时,就可以实现在调用方法之前、调用方法过程中、调用方法之后对其进行控制。
1.创建目标对象target;
2.创建interceptor对象
3.创建Enhancer对象,它以目标类和interceptor作为原料,生产出代理对象
4、enhancer设置参数setSuperclass,setCallback
5、创建代理类proxy,调用需要代理的方法;
* */
public class ProxyCglibPrinter implements MethodInterceptor {


    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        String name = method.getName();
        if(name.equals("print")){
            System.out.println("cglib增加操作");
        }
        methodProxy.invokeSuper(o,objects);
        return null;
    }

}


4.2.3)测试

    public static void main(String[] args) {
        Printer1 target = new Printer1();
        ProxyCglibPrinter interceptor = new ProxyCglibPrinter();
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(interceptor);
        Printer1 proxy = (Printer1)enhancer.create();
        proxy.print("测试");
    }

运行

4.2.4)总结:

无需代理类实现接口,使用Cblib中的Enhancer来生成代理对象子类,并实现MethodInterceptor中的intercept方法,在此方法中可以实现增强功能。

如果目标对象需要实现接口,则使用JDK代理。
如果目标对象不需要实现接口,则使用Cglib代理。

5、综上所述,再次总结:

静态代理:

jdk动态代理:

cglib动态代理:

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

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

相关文章

【边缘计算网关教程】4.西门子PPI协议对接

前景回顾&#xff1a;【边缘计算网关教程】3.创建第二个流程-CSDN博客 目录 1. 硬件连接 2. PLC串口参数 2.1. 打开STEP7软件 2.2. 查看通信参数 3. 网关设置 3.1. PLC连接设置 3.2. 数据点位设置 3.3. 测试 西门子 PPI 协议 适配PLC&#xff1a;S7-200 西门子S7-200 PLC…

Python爬虫之路(2):爬天气情况

hello hello~ &#xff0c;这里是绝命Coding——老白~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#xff1a;绝命Coding-CSDN博客 &a…

Stable Diffusion 深度探索:从入门到精通的全方位教程

在人工智能艺术创作的浪潮中&#xff0c;Stable Diffusion 作为一股不可忽视的力量&#xff0c;正以其独特的魅力吸引着无数创作者和科技爱好者的目光。本文旨在为大家提供一份详尽的 Stable Diffusion 教程&#xff0c;从基础概念到高级应用&#xff0c;带领你一步步走进这个充…

k8s record 20240710 监控

不是adaptor 是opetator 案例 监控有了&#xff0c;日志搜集呢&#xff1f; 一、kubelet 的小弟 kubelet — 负责维护容器的生命周期&#xff0c;节点和集群其他部分通信 cAdvisor 集成在 Kubernetes 的 kubelet 中&#xff0c;能够自动发现和监控集群中所有的容器。dockers…

基于SpringBoot+Vue的数码论坛系统(带1w+文档)

基于SpringBootVue的数码论坛系统(带1w文档) 基于SpringBootVue的数码论坛系统(带1w文档) 数码论坛系统能够通过互联网得到广泛的、全面的宣传&#xff0c;让尽可能多的用户了解和熟知数码论坛系统的便捷高效&#xff0c;不仅为用户提供了服务&#xff0c;而且也推广了自己&…

SpringBoot整合JWT示例教程

1. JWT简介 JSON Web Token (JWT) 是一种开放标准&#xff08;RFC 7519&#xff09;&#xff0c;它定义了一种紧凑且自包含的方式&#xff0c;用于在各方之间作为 JSON 对象安全地传输信息。由于这些信息是经过数字签名的&#xff0c;因此可以被验证和信任。JWT 通常用于身份验…

深度学习论文: YOLOv5, YOLOv8 and YOLOv10: The Go-To Detectors for Real-time Vision

深度学习论文: YOLOv5, YOLOv8 and YOLOv10: The Go-To Detectors for Real-time Vision YOLOv5, YOLOv8 and YOLOv10: The Go-To Detectors for Real-time Vision PDF:https://arxiv.org/pdf/2407.02988v1 PyTorch: https://github.com/shanglianlm0525/PyTorch-Networks 1 概…

51单片机-第三节-LCD1602调试工具,矩阵键盘

一、LCD调试工具函数&#xff1a; 使用&#xff1a; 所有函数&#xff0c;前两个参数&#xff0c;均为指定显示位置。 四个参数的&#xff0c;第四个参数&#xff0c;为保留位数&#xff0c;少的保留后面&#xff08;123,2 -> 23&#xff09;&#xff0c;多的前面补零。 …

文章解读与仿真程序复现思路——电网技术EI\CSCD\北大核心《天气数据驱动下基于深度主动学习的新型电力系统供需失衡风险快速评估方法 》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

Apache-Flink未授权访问高危漏洞修复

漏洞等级 高危漏洞!!! 一、漏洞描述 攻击者没有获取到登录权限或未授权的情况下,或者不需要输入密码,即可通过直接输入网站控制台主页面地址,或者不允许查看的链接便可进行访问,同时进行操作。 二、修复建议 根据业务/系统具体情况,结合如下建议做出具体选择: 配…

产品经理-研发流程-敏捷开发-迭代-需求评审及产品规划(15)

敏捷开发是以用户的需求进化为核心&#xff0c;采用迭代、循序渐进的方法进行软件开发。 通俗来说&#xff0c;敏捷开发是一个软件开发流程&#xff0c;是一个采用了迭代方法的开发流程 简单来说&#xff0c;迭代就是把一个大产品拆分出一些最小的实现单位。完成不同的迭代就最…

交易平台Zero Hash现已支持SUI交易

Zero Hash是一家领先的加密货币和稳定币基础设施平台&#xff0c;为包括Stripe、Shift4和Franklin Templeton在内的公司提供支持&#xff0c;现在也支持对SUI的访问。此举使Zero Hash的客户及其终端用户能够使用SUI。 提供API和SDK以及专注于无缝连接法币、加密货币和稳定币的…

Python | Leetcode Python题解之第231题2的幂

题目&#xff1a; 题解&#xff1a; class Solution:BIG 2**30def isPowerOfTwo(self, n: int) -> bool:return n > 0 and Solution.BIG % n 0

【Redis】哨兵(sentinel)

文章目录 一、哨兵是什么&#xff1f;二、 哨兵sentinel文件参数三、 模仿主机redis宕机四、哨兵运行流程和选举原理SDOWN主观下线ODOWN客观下线 五、 使用建议 以下是本篇文章正文内容 一、哨兵是什么&#xff1f; 哨兵巡查监控后台master主机是否故障&#xff0c;如果故障了…

PostgreSQL 如何应对因大量并发删除操作导致的性能问题?

&#x1f345;关注博主&#x1f397;️ 带你畅游技术世界&#xff0c;不错过每一次成长机会&#xff01;&#x1f4da;领书&#xff1a;PostgreSQL 入门到精通.pdf 文章目录 PostgreSQL 如何应对因大量并发删除操作导致的性能问题一、优化索引二、批量删除三、分区表四、调整参…

kotlin数据类型

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 Kotlin基本数值类型 基本数据类型包括 Byte、Short、Int、Long、Float、Double 整数类型 类型位宽最小值最大…

GloVe: Global Vectors for Word Representation论文笔记解读

基本信息 作者Jeffrey Penningtondoi10.3115/v1/D14-1162发表时间2014期刊EMNLP网址https://aclanthology.org/D14-1162.pdf 研究背景 1. What’s known 既往研究已证实 全局矩阵分解方法&#xff1a;LSA&#xff0c;考虑整个语料库词频的统计信息得到共现矩阵&#xff0c;通…

访问 Postman OAuth 2.0 授权的最佳实践

OAuth 2.0 代表了 web 安全协议的发展&#xff0c;便于在多个平台上进行授权服务&#xff0c;同时避免暴露用户凭据。它提供了一种安全的方式&#xff0c;让用户可以授权应用程序访问服务。 在 Postman 中开始使用 OAuth 2.0 Postman 是一个流行的API客户端&#xff0c;支持 …

FlinkModule加载HiveModule异常

HiveModule这个模块加载不出来 加在不出来这个模块&#xff0c;网上查说是要加下面这个依赖 <dependency><groupId>org.apache.flink</groupId><artifactId>flink-connector-hive_${scala.binary.version}</artifactId><version>${flink.…

.Net Core 微服务之Consul(二)-集群搭建

引言: 集合上一期.Net Core 微服务之Consul(一)(.Net Core 微服务之Consul(一)-CSDN博客) 。 目录 一、 Consul集群搭建 1. 高可用 1.1 高可用性概念 1.2 高可用集群的基本原理 1.3 高可用集群的架构设计 1.3.1 主从复制架构 1.3.2 共享存储架构 1.3.3 负载均衡…