Spring-Aop核心技术

news2024/9/27 7:26:36

前言

spring一直以来都是我们Java开发中最核心的一个技术,其中又以ioc和aop为主要技术,本篇文章主要讲一下aop的核心技术,也就是ProxyFactory技术的使用,而基本的jdk动态代理和cglib代理技术并不涉及,如有需要,请自行寻找资料

背景

package com.zxc.boot.proxy;

public class OrderService {
    
    public void create() {
        System.out.println("创建订单");
    }
    
    public void payOrder() {
        System.out.println("支付订单");
    }
}

假设你有如上的对象,需要对两个方法前面都插入生成订单号的逻辑,如果是传统的方式就可以直接加入,但是过于麻烦,如果使用spring的话,就可以借助如下的工具类,如

ProxyFactory

package com.zxc.boot.proxy;

import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.framework.ProxyFactory;

import java.lang.reflect.Method;

public class Main {

    public static void main(String[] args) {

        //被代理对象
        OrderService orderService = new OrderService();

        ProxyFactory proxyFactory = new ProxyFactory();
        //设置代理对象
        proxyFactory.setTarget(orderService);
        //添加代理逻辑
        proxyFactory.addAdvice(new MethodBeforeAdvice() {
            @Override
            public void before(Method method, Object[] objects, Object o) throws Throwable {
                System.out.println("-----生成订单号------");
            }
        });

        //获取代理对象
        OrderService orderServiceProxy = (OrderService) proxyFactory.getProxy();

        orderServiceProxy.create();
        orderServiceProxy.payOrder();
    }
}

生成的结果如下(注:这里没有接口,肯定是使用cglib生成的代理对象)

是不是很简单呢,底层逻辑都是spring帮我们实现的,而MethodBeforeAdvice就是进行的代理逻辑,它的父接口是

Advice

这个简单理解就是对象被代理的逻辑,主要有以下的实现,如

MethodBeforeAdvice、AfterReturningAdvice、MethodInterceptor等等见名思义

但是这里有一个问题,我们两个方法都被进行了代理,那么是否有办法实现只代理某个方法,而某些方法不进行代理呢,答案是有的,代码如下

package com.zxc.boot.proxy;

import org.aopalliance.aop.Advice;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.Pointcut;
import org.springframework.aop.PointcutAdvisor;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.StaticMethodMatcherPointcut;

import java.lang.reflect.Method;

public class Main2 {

    public static void main(String[] args) {

        //被代理对象
        OrderService orderService = new OrderService();

        ProxyFactory proxyFactory = new ProxyFactory();
        //设置代理对象
        proxyFactory.setTarget(orderService);
        //添加代理逻辑
        proxyFactory.addAdvisor(new PointcutAdvisor() {
            @Override
            public Pointcut getPointcut() {
                //哪些方法进行代理
                return new StaticMethodMatcherPointcut() {
                    @Override
                    public boolean matches(Method method, Class<?> aClass) {
                        //方法名为create进行代理
                        return method.getName().equals("create");
                    }
                };
            }

            //代理逻辑
            @Override
            public Advice getAdvice() {
                return new MethodBeforeAdvice() {
                    @Override
                    public void before(Method method, Object[] objects, Object o) throws Throwable {
                        System.out.println("-----创建订单-----");
                    }
                };
            }

            @Override
            public boolean isPerInstance() {
                return false;
            }
        });

        //获取代理对象
        OrderService orderServiceProxy = (OrderService) proxyFactory.getProxy();

        orderServiceProxy.create();
        orderServiceProxy.payOrder();
    }
}

可以看到,只有创建订单的方法才会添加代理逻辑,而支付订单并不会加入这段逻辑,而核心的功能点就是依赖于Pointcut对象

Pointcut

Pointcut简单理解就是切掉,也就是用于判断要在哪些方法或者哪些类注入代理逻辑用的

Advisor

而Advisor简单理解就是Advice和Pointcut的组合,spring当中进行代理的逻辑也是用Advisor为维度进行处理的

以上,就是使用ProxyFactory进行代理逻辑的spring工具类,但是很明显这样使用相对来说还是比较麻烦的,所以spring提供了简易的方式让我们使用这种逻辑,如下

Spring提供的代理支持

ProxyFactoryBean

package com.zxc.boot.proxy;

import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.framework.ProxyFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import java.lang.reflect.Method;

@Configuration
@ComponentScan("com.zxc.boot.proxy")
public class AppConfig {

    @Bean
    public ProxyFactoryBean proxyFactoryBean() {

        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
        proxyFactoryBean.setTarget(new OrderService());
        proxyFactoryBean.addAdvice(new MethodBeforeAdvice() {
            @Override
            public void before(Method method, Object[] objects, Object o) throws Throwable {
                System.out.println("-------创建订单-------");
            }
        });
        return proxyFactoryBean;
    }
}
package com.zxc.boot.proxy;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class SpringApplication {

    public static void main(String[] args) {

        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
        OrderService orderService = applicationContext.getBean(OrderService.class);

        orderService.create();
        orderService.payOrder();

    }
}

只要进行如上的配置,就可以识别到了,这种方式其实跟原有的差不多,只不过spring帮我们处理了最终会返回对应的代理bean回去,但是还有更简单的方式,如下

DefaultPointcutAdvisor

package com.zxc.boot.proxy;

import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.NameMatchMethodPointcut;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import java.lang.reflect.Method;

@Configuration
@ComponentScan("com.zxc.boot.proxy")
public class AppConfig2 {

    @Bean
    public OrderService orderService() {
        return new OrderService();
    }

    @Bean
    public DefaultPointcutAdvisor defaultPointcutAdvisor() {

        //方法名称蓝机器
        NameMatchMethodPointcut nameMatchMethodPointcut = new NameMatchMethodPointcut();
        nameMatchMethodPointcut.addMethodName("create");

        //设置拦截和代理逻辑
        DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();
        defaultPointcutAdvisor.setPointcut(nameMatchMethodPointcut);
        defaultPointcutAdvisor.setAdvice(new MethodBeforeAdvice() {
            @Override
            public void before(Method method, Object[] args, Object target) throws Throwable {
                System.out.println("-------创建订单------");
            }
        });
        return defaultPointcutAdvisor;
    }

    //核心类,一个BeanPostProccess后置处理器,用于把扫描到的Advisor进行代理
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        return new DefaultAdvisorAutoProxyCreator();
    }
}
package com.zxc.boot.proxy;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class SpringApplication {

    public static void main(String[] args) {

        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig2.class);
        OrderService orderService = applicationContext.getBean(OrderService.class);

        orderService.create();
        orderService.payOrder();

    }
}

不用我们多做其他处理,就可以对ioc容器中方法有create的类进行代理,你可以再添加一个类,如下

package com.zxc.boot.proxy;

public class UserService {

    public void create() {
        System.out.println("用户service哦哦哦");
    }
}
package com.zxc.boot.proxy;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class SpringApplication {

    public static void main(String[] args) {

        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig2.class);
        OrderService orderService = applicationContext.getBean(OrderService.class);

        orderService.create();
        orderService.payOrder();

        UserService userService = applicationContext.getBean(UserService.class);
        userService.create();

    }
}

这样的方式就方便多了

优化处理

其实DefaultAdvisorAutoProxyCreator只是需要导入到ioc容器中,所以配置类可以使用import进行处理,效果是一样的,如下

package com.zxc.boot.proxy;

import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.NameMatchMethodPointcut;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

import java.lang.reflect.Method;

@Configuration
@ComponentScan("com.zxc.boot.proxy")
@Import(DefaultAdvisorAutoProxyCreator.class)
public class AppConfig2 {

    @Bean
    public UserService userService() {
        return new UserService();
    }

    @Bean
    public OrderService orderService() {
        return new OrderService();
    }

    @Bean
    public DefaultPointcutAdvisor defaultPointcutAdvisor() {

        //方法名称蓝机器
        NameMatchMethodPointcut nameMatchMethodPointcut = new NameMatchMethodPointcut();
        nameMatchMethodPointcut.addMethodName("create");

        //设置拦截和代理逻辑
        DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();
        defaultPointcutAdvisor.setPointcut(nameMatchMethodPointcut);
        defaultPointcutAdvisor.setAdvice(new MethodBeforeAdvice() {
            @Override
            public void before(Method method, Object[] args, Object target) throws Throwable {
                System.out.println("-------创建订单------");
            }
        });
        return defaultPointcutAdvisor;
    }

//    //核心类,一个BeanPostProccess后置处理器,用于把扫描到的Advisor进行代理
//    @Bean
//    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
//        return new DefaultAdvisorAutoProxyCreator();
//    }
}

如果你不导入DefaultAdvisorAutoProxyCreator对象,那么代理逻辑就不会生效,本质就是DefaultAdvisorAutoProxyCreator类就是一个BeanPostProcessor处理器,它会针对所有类进行判断然后处理

总结

到这里本篇文章就结束了,spring的aop核心技术就是最终会利用到这个对象进行代理,而这里先把底层的代理逻辑进行讲明,后面对整个aop流程进行理解就方便多了

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

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

相关文章

2023前端vue面试题汇总

Vuex有哪几种属性&#xff1f; 有五种&#xff0c;分别是 State、 Getter、Mutation 、Action、 Module state > 基本数据(数据源存放地)getters > 从基本数据派生出来的数据mutations > 提交更改数据的方法&#xff0c;同步actions > 像一个装饰器&#xff0c;包…

【Python】3.3实现多线程

程序Program进程Process线程Thread为完成特定任务而用计算机语言编写的一组计算机能识别和执行的指令的集合。程序是指令、数据及其组织形式的描述&#xff0c;一段静态代码&#xff0c;静态对象。计算机中的程序关于某数据集合上的一次执行过程。进程是程序的实体&#xff0c;…

2022年全国职业院校技能大赛(中职组)网络安全竞赛试题A(10)

目录 竞赛内容 模块A 基础设施设置与安全加固 一、项目和任务描述&#xff1a; 二、服务器环境说明 三、具体任务&#xff08;每个任务得分以电子答题卡为准&#xff09; A-1任务一 登录安全加固&#xff08;Windows, Linux&#xff09; 1.密码策略&#xff08;Windows, …

创作者基金亮点总结|2023 年 2 月

新的一月&#xff0c;新的创作者基金亮点&#xff01;我们把 2 月份的精华作品都聚集在了一个地方&#xff1a;The Sandbox 市场平台&#xff01; 24 项全新资产已经加入创作者基金的作品集啦&#xff01; NFT 作品一览 一起来看看 2023 年 2 月份的作品集吧&#xff5e; 独眼巨…

一个基于 LKM 的 Linux 内核级 rootkit 的实现

博客已迁移至&#xff1a;https://gls.show/ GitHub链接 演示Slides overview rootkit是一种恶意软件&#xff0c;攻击者可以在获得 root 或管理员权限后安装它&#xff0c;从而隐藏入侵并保持root权限访问。rootkit可以是用户级的&#xff0c;也可以是内核级的。关于rootk…

基于Docker部署Dubbo+Nacos服务

一、说明 本文介绍基于 Docker 部署一套 Dubbo Nacos 的微服务环境&#xff0c;并解决容器里的 IP 及端口的访问问题。 基于上文《基于jib-maven-plugin快速构建微服务docker镜像》 中在阿里云镜像仓库构建的镜像来进行部署。 二、部署 Nacos 注册中心 拉取 nacos 注册中心镜…

linux基本功系列之uniq命令实战

文章目录前言一. uniq的命令介绍二. 语法格式及常用选项三. 参考案例3.1 统计行数3.2 对文本进行去重3.3 显示不重复的行3.4 仅显示重复的行&#xff0c;且显示重复的行的所有行3.5 忽略字母大小写总结前言 大家好&#xff0c;又见面了&#xff0c;我是沐风晓月&#xff0c;本…

【vulhub漏洞复现】CVE-2016-3088 ActiveMQ任意文件写入漏洞

一、漏洞详情影响版本&#xff1a;Apache ActiveMQ 5.x~5.14.0漏洞原理&#xff1a;ActiveMQ中存储文件的fileserver接口支持写入文件&#xff0c;但是没有执行权限。可以通过MOVE文件至其他可执行目录下&#xff0c;从而实现文件写入并访问。ActiveMQ在5.12.x~5.13.x版本中&am…

PowerShell Install Rabbitmq

Rabbitmq 前言 RabbitMQ是实现了高级消息队列协议&#xff08;AMQP&#xff09;的开源消息代理软件&#xff08;亦称面向消息的中间件&#xff09;。RabbitMQ服务器是用Erlang语言编写的&#xff0c;而集群和故障转移是构建在开放电信平台框架上的。所有主要的编程语言均有与代…

设计模式-第4章(装饰模式)

装饰模式装饰模型装饰模式示例商场收银程序&#xff08;简单工厂策略装饰模式实现&#xff09;装饰模式总结装饰模型 装饰模式&#xff08;Decorator&#xff09;&#xff0c;动态地给一个对象添加一些额外的职责&#xff0c;就增加功能来说&#xff0c;装饰模式比生成子类更为…

【基础算法】双指针----字符串删减

&#x1f339;作者:云小逸 &#x1f4dd;个人主页:云小逸的主页 &#x1f4dd;Github:云小逸的Github &#x1f91f;motto:要敢于一个人默默的面对自己&#xff0c;强大自己才是核心。不要等到什么都没有了&#xff0c;才下定决心去做。种一颗树&#xff0c;最好的时间是十年前…

Java查漏补缺(13)泛型概述、使用泛型举例、自定义泛型结构、泛型在继承上的体现、通配符的使用

Java查漏补缺&#xff08;13&#xff09;泛型概述、使用泛型举例、自定义泛型结构、泛型在继承上的体现、通配符的使用本章专题与脉络1. 泛型概述1.1 生活中的例子1.2 泛型的引入2. 使用泛型举例2.1 集合中使用泛型2.1.1 举例2.1.2 练习2.2 比较器中使用泛型2.2.1 举例2.2.2 练…

Vue下载安装步骤的详细教程(亲测有效) 2 安装与创建默认项目

上篇请移步到Vue下载安装步骤的详细教程(亲测有效) 1_水w的博客-CSDN博客 上一篇博文已经对Node.js的安装与配置进行了详细介绍。 另外&#xff1a;文中项目存放的路径及项目名称可根据自身实际情况进行更改。 目录 三、Vue安装配置 1、搭建Vue脚手架 2、通过NPM安装Vue …

二手商品交易网站

技术&#xff1a;Java、JSP等摘要&#xff1a;随着科学技术和信息通讯的飞速发展&#xff0c;Internet极大地丰富和改变着我们生活的各个行业。随着Internet的普及应用&#xff0c;人们可以跨越时间和空间的限制&#xff0c;足不出户便能通过网络完成信息交流&#xff0c;而完成…

Windows如何查看某个端口被占用的情况?

在工作中&#xff0c;有时会发现端口被占用的情况&#xff0c;导致软件报错或者服务无法启动等问题。在不知道具体哪个进程占用该端口号的情况下&#xff0c;我们可以用下面方法来查找。 举例&#xff1a;我现在发现8090端口被占用了&#xff0c;我现在需要找到并杀掉该进程。…

ICA简介:独立成分分析

1. 简介 您是否曾经遇到过这样一种情况&#xff1a;您试图分析一个复杂且高度相关的数据集&#xff0c;却对信息量感到不知所措&#xff1f;这就是独立成分分析 (ICA) 的用武之地。ICA 是数据分析领域的一项强大技术&#xff0c;可让您分离和识别多元数据集中的底层独立来源。 …

嵌入式 STM32 红外遥控

目录 红外遥控 NEC码的位定义 硬件设计 软件设计 源码程序 红外遥控 红外遥控是一种无线、非接触控制技术&#xff0c;具有抗干扰能力强&#xff0c;信息传输可靠&#xff0c;功耗低&#xff0c;成本低&#xff0c;容易实现等显著的特点&#xff0c;被诸多电子设备特别…

二进制、十六进制和浮点数ASCII的转换机制--------IEEE754

我在使用GPS时&#xff0c;通过网口接收到了BESTPOS格式的输出结果&#xff0c;它以16进制表示。 当前常见的GPS都以ASCII表示&#xff0c;例如我们在串口助手中可以选择输出类型为ASCII或者是16进制&#xff0c;那么说明它们中见肯定存在某种转换机制&#xff0c;既可以表示出…

javaEE 初阶 — 网络层 IP 协议 的功能 — 路由选择与地址管理

文章目录IP 协议的功能1.IP 协议的路由选择2.IP 协议的地址管理2.1 网络号与主机号的分界2.2 特殊 IPIP 协议的功能 网络层主要做两件事&#xff1a; 地址管理 路由选择 网络层的代表就是 IP 协议 网络层主要是负责管理路由设备&#xff0c;要从两个结点之间找到一条具体的…

01 presto 概述: 特性 优缺点 场景 架构

文章目录1. Presto是什么2. Presto优缺点2.1. 优点2.2. 缺点3. Presto适用场景4. Presto数据模型5. Presto 架构5.1 执行流程关键词&#xff1a;MPP 多源 即席查询 统一SQL执行引擎 分布式SQL引擎 数据分析 1. Presto是什么 Presto是一款开源的分布式并行计算(MPP)引擎&#x…