Spring-动态代理

动态代理

代理模式:为其他对象提供一种代理以控制对这个对象的访问,增强一个类中的某个方法,对程序进行扩展。

动态代理可以在不修改类源码的前提下,给类中方法增加额外逻辑

通过cglib来实现的代理对象的创建:

基于父子类,被代理类是父类,代理类是子类,代理对象就是代理类的实例对象,代理类是由cglib创建的

import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;// cglib动态代理单独使用
public class Test
{public static void main(String[] args){UserService target = new UserService();// 通过cglib技术Enhancer enhancer = new Enhancer();enhancer.setSuperclass(UserService.class);// 定义额外逻辑,也就是代理逻辑enhancer.setCallbacks(new Callback[] {new MethodInterceptor(){@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy)throws Throwable{System.out.println("before...");
//				// 写法一
//              Object result = methodProxy.invoke(target, objects);//				// 写法二
//				Object result = method.invoke(target, objects);// 写法三Object result = methodProxy.invokeSuper(o, objects);System.out.println("after...");return result;}}});// 动态代理所创建出来的UserService对象UserService userService = (UserService)enhancer.create();// 执行这个userService的test方法时,就会额外会执行一些其他逻辑userService.test();}
}public class UserService
{public void test(){System.out.println("test");}
}

利用JDK动态代理来生成一个代理对象:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class Test
{public static void main(String[] args){UserService target = new UserService();// UserInterface接口的代理对象Object proxy = Proxy.newProxyInstance(UserService.class.getClassLoader(),new Class[] {UserInterface.class}, new InvocationHandler(){@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable{System.out.println("before...");Object result = method.invoke(target, args);System.out.println("after...");return result;}});// 注意这里必须是接口类型UserInterface,如果是UserService类会报错UserInterface userService = (UserInterface)proxy;userService.test();}
}public class UserService implements UserInterface
{@Overridepublic void test(){System.out.println("test");}
}public interface UserInterface
{public void test();
}

注意:代理对象proxy必须是接口类型

ProxyFactory

Spring对上面的两种动态代理技术进行了封装,封装出来的类叫做ProxyFactory

表示创建代理对象的一个工厂,使用起来更加方便

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.framework.ProxyFactory;public class Test
{public static void main(String[] args){UserService target = new UserService();ProxyFactory proxyFactory = new ProxyFactory();proxyFactory.setTarget(target);proxyFactory.addAdvice(new MethodInterceptor(){@Overridepublic Object invoke(MethodInvocation invocation)throws Throwable{System.out.println("before...");Object result = invocation.proceed();System.out.println("after...");return result;}});UserInterface userService = (UserInterface)proxyFactory.getProxy();userService.test();}
}public class UserService implements UserInterface
{@Overridepublic void test(){System.out.println("test");}
}public interface UserInterface
{public void test();
}

ProxyFactory会自动判断是用cglib还是jdk动态代理

如果类实现了接口,那么ProxyFactory底层就会用jdk动态代理

如果没有实现接口,就会用cglib技术

Advice的分类

1、Before Advice:方法之前执行

2、After returning advice:方法return后执行

3、After throwing advice:方法抛异常后执行

4、After (finally) advice:方法执行完finally之后执行,这是最后的,比return更后

5、Around advice:这是功能最强大的Advice,可以自定义执行顺序

Advisor

一个Advisor是有一个Pointcut和一个Advice组成的,通过Pointcut可以指定需要被代理的逻辑

可以通过Advisor来控制具体代理哪个方法

public class Test
{public static void main(String[] args){UserService target = new UserService();ProxyFactory proxyFactory = new ProxyFactory();proxyFactory.setTarget(target);proxyFactory.addAdvisor(new PointcutAdvisor(){@Overridepublic Pointcut getPointcut(){return new StaticMethodMatcherPointcut(){@Overridepublic boolean matches(Method method, Class<?> targetClass){return method.getName().equals("testAbc");}};}@Overridepublic Advice getAdvice(){return new MethodInterceptor(){@Overridepublic Object invoke(MethodInvocation invocation)throws Throwable{System.out.println("before...");Object result = invocation.proceed();System.out.println("after...");return result;}};}@Overridepublic boolean isPerInstance(){return false;}});UserInterface userService = (UserInterface)proxyFactory.getProxy();userService.test();}
}

创建代理对象的方式

ProxyFactoryBean
public class UserService
{public void test(){System.out.println("test");}
}@ComponentScan(value = "com.gax")
public class AppConfig
{@Beanpublic ProxyFactoryBean userService(){UserService userService = new UserService();ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();proxyFactoryBean.setTarget(userService);proxyFactoryBean.addAdvice(new MethodInterceptor(){@Overridepublic Object invoke(MethodInvocation invocation)throws Throwable{System.out.println("before...");Object result = invocation.proceed();System.out.println("after...");return result;}});return proxyFactoryBean;}
}public class Test
{public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);UserService userServiceProxy = (UserService)applicationContext.getBean("userService");userServiceProxy.test();}
}

上面这种方式只能针对某一个Bean

ProxyFactoryBean还有额外的功能,比如可以把某个Advise或Advisor定义成为Bean,然后在ProxyFactoryBean中进行设置

public class UserService
{public void test(){System.out.println("test");}
}@ComponentScan(value = "com.gax")
public class AppConfig
{@Beanpublic MethodInterceptor gaxAroundAdvise(){return new MethodInterceptor(){@Overridepublic Object invoke(MethodInvocation invocation)throws Throwable{System.out.println("before...");Object result = invocation.proceed();System.out.println("after...");return result;}};}@Beanpublic ProxyFactoryBean userService(){UserService userService = new UserService();ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();proxyFactoryBean.setTarget(userService);proxyFactoryBean.setInterceptorNames("gaxAroundAdvise");return proxyFactoryBean;}
}public class Test
{public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);UserService userServiceProxy = (UserService)applicationContext.getBean("userService");userServiceProxy.test();}
}

BeanNameAutoProxyCreator

ProxyFactoryBean需要自己指定被代理的对象;BeanNameAutoProxyCreator可以通过指定某个bean的名字,来对该bean进行代理

通过BeanNameAutoProxyCreator可以对批量的Bean进行AOP,并且指定了代理逻辑,指定了一个InterceptorName,也就是一个Advise,前提条件是这个Advise也得是一个Bean,这样Spring才能找到的,但是BeanNameAutoProxyCreator的缺点很明显,它只能根据beanName来指定想要代理的Bean。

@Component
public class UserService
{public void test(){System.out.println("test");}
}@ComponentScan(value = "com.gax")
public class AppConfig
{@Beanpublic MethodInterceptor gaxAroundAdvise(){return new MethodInterceptor(){@Overridepublic Object invoke(MethodInvocation invocation)throws Throwable{System.out.println("before...");Object result = invocation.proceed();System.out.println("after...");return result;}};}@Beanpublic BeanNameAutoProxyCreator beanNameAutoProxyCreator(){BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();beanNameAutoProxyCreator.setBeanNames("userSe*");beanNameAutoProxyCreator.setInterceptorNames("gaxAroundAdvise");beanNameAutoProxyCreator.setProxyTargetClass(true);return beanNameAutoProxyCreator;}
}public class Test
{public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);UserService userServiceProxy = (UserService)applicationContext.getBean("userService");userServiceProxy.test();}
}

DefaultAdvisorAutoProxyCreator

@Component
public class UserService
{public void test(){System.out.println("test");}
}@ComponentScan(value = "com.gax")
public class AppConfig
{@Beanpublic MethodInterceptor gaxAroundAdvise(){return new MethodInterceptor(){@Overridepublic Object invoke(MethodInvocation invocation)throws Throwable{System.out.println("before...");Object result = invocation.proceed();System.out.println("after...");return result;}};}@Beanpublic DefaultPointcutAdvisor defaultPointcutAdvisor(){NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();pointcut.addMethodName("test");DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();defaultPointcutAdvisor.setPointcut(pointcut);defaultPointcutAdvisor.setAdvice(gaxAroundAdvise());return defaultPointcutAdvisor;}@Beanpublic DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();return defaultAdvisorAutoProxyCreator;}
}public class Test
{public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);UserService userServiceProxy = (UserService)applicationContext.getBean("userService");userServiceProxy.test();}
}

通过DefaultAdvisorAutoProxyCreator会直接去找所有Advisor类型的Bean,根据Advisor中的PointCut和Advice信息,确定要代理的Bean以及代理逻辑。

简化成注解方式

@Aspect
@Component
public class GaxAspect 
{@Before("execution(public void com.gax.service.UserService.test())")public void gaxBefore(JoinPoint joinPoint) {System.out.println("gaxBefore");}
}

要代理的类:表达式

代理逻辑:被@Before修饰的方法

Spring只要去解析这些注解就好了,解析之后得到对应的Pointcut对象、Advice对象,生成Advisor对象,扔进ProxyFactory中,进而产生对应的代理对象,具体怎么解析这些注解就是@EnableAspectJAutoProxy注解所要做的事情

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

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

相关文章

MES系统如何赋能制造企业实现4M防错追溯?

生产过程4M管理和MES系统的结合是现代制造业中关键的质量管理实践&#xff0c;它有助于提高生产效率、降低生产成本并保证产品质量。本文将深入探讨4M管理的概念&#xff0c;以及MES系统如何赋能制造企业实现4M防错追溯。 一、4M管理的概念 4M管理是指在制造过程中管理和控制四…

浅谈数据结构之递归

1. 递归的定义 递归是一种在解决问题时使用自身的特殊方法。在计算机科学和数据结构中&#xff0c;递归是一种通过将问题分解成更小的、相似的子问题来解决复杂问题的方法。递归可以直接或间接地调用自身&#xff0c;将大问题转化为规模较小的子问题&#xff0c;直到达到基本情…

leetCode 92.反转链表 II + 图解

92. 反转链表 II - 力扣&#xff08;LeetCode&#xff09; 给你单链表的头指针 head 和两个整数 left 和 right &#xff0c;其中 left < right 。请你反转从位置 left 到位置 right 的链表节点&#xff0c;返回 反转后的链表 206. 反转链表 - 力扣&#xff08;LeetCode&am…

区块链链游合约系统开发项目模式技术方案

​随着区块链技术的发展&#xff0c;链游合约系统开发逐渐成为了一个备受关注的项目。本文将探讨区块链链游合约系统开发项目的技术方案&#xff0c;包括项目背景、开发目标、技术架构、系统流程、安全措施等方面的内容。 一、项目背景 链游是一种基于区块链技术的游戏&#xf…

加密磁盘密钥设置方案浅析 — LUKS1

虚拟化加密磁盘密钥设置方案浅析 前言元数据分析元数据格式整体格式头部格式加密算法密码校验key slot格式其它字段 流程验证 前言 我们在虚拟化加密磁盘密钥设置方案浅析 — TKS1中介绍了加密磁盘密钥设置方案&#xff0c;TKS1对密钥设置(Linux Unified Key Setup)的流程和方…

阿里云容器镜像服务的运维总结

一、背景 容器镜像服务&#xff0c;作为一个可选付费产品&#xff0c;主要作用是存储docker的镜像仓库&#xff0c;供k8s拉取到Pod节点里。 你可以自己搭建一个harbor镜像仓库&#xff0c;在公司的开发环境下&#xff0c;将image推送到仓库&#xff1b;然后在生产k8s从仓库拉取…

7-5 计算每个学生的平均成绩

7-5 计算每个学生的平均成绩 分数 15 作者 殷伟凤 单位 浙江传媒学院 输入所有学生的姓名和成绩&#xff0c;以#结束。输出每个学生的平均成绩表。 输入格式: 每一行输入一个学生的姓名和成绩&#xff0c;以空格分隔。 输入完成后以#结束 输出格式: 每行显示一个学生的姓名和…

QtC++与QTreeView详解

介绍 QTreeView 是 Qt 框架中的一个视图控件&#xff0c;用于显示树形结构的数据。它是 QAbstractItemView 类的子类&#xff0c;通常与数据模型结合使用。以下是 QTreeView 的详细讲解和在 Qt 中的作用&#xff1a; QTreeView 的作用&#xff1a; 显示层次数据&#xff1a; …

ECharts:显示暂无数据

ECharts 是一个使用 JavaScript 实现的开源可视化库&#xff0c;涵盖各行业图表&#xff0c;满足各种需求&#xff0c;实现各种炫酷的统计图表效果。 如上图所示&#xff0c;有数据的时候固然好看&#xff0c;但是当它没有数据的时候&#xff0c;就是光秃秃的一片&#xff0c;所…

说说React Router有几种模式?实现原理?

一、是什么 在单页应用中,一个web项目只有一个html页面,一旦页面加载完成之后,就不用因为用户的操作而进行页面的重新加载或者跳转,其特性如下: 改变 url 且不让浏览器像服务器发送请求在不刷新页面的前提下动态改变浏览器地址栏中的URL地址其中主要分成了两种模式: has…

【GitHub】PR的学习笔记

PR流程 Fork the repository.Clone the fork-repo.Make the desired changes.Stage files: git add.Commit the changes: git commitPush them to the fork-online: git push.Create a pull request.

排序算法之-快速

算法原理 丛待排序的数列中选择一个基准值&#xff0c;通过遍历数列&#xff0c;将数列分成两个子数列&#xff1a;小于基准值数列、大于基准值数列&#xff0c;准确来说还有个子数列&#xff1a;等于基准值即&#xff1a; 算法图解 选出基准元素pivot&#xff08;可以选择…

[文件读取]shopxo 文件读取(CNVD-2021-15822)

1.1漏洞描述 漏洞编号CNVD-2021-15822漏洞类型文件读取漏洞等级⭐⭐漏洞环境VULFOCUS攻击方式 描述: ShopXO是一套开源的企业级开源电子商务系统。 ShopXO存在任意文件读取漏洞&#xff0c;攻击者可利用该漏洞获取敏感信息。 1.2漏洞等级 高危 1.3影响版本 ShopXO 1.4漏洞复现…

【Git】第一篇:Git安装(centos)

git查看安装版本 以我自己的centos7.6为例&#xff0c;我们可以输入以下指令查看自己是否安装了git. git --version安装了的话就会显示自己安装的版本。 git 安装 安装很简单&#xff0c;一条命令即可 sudo yum install git -ygit 卸载 sudo yum remove git -y

《使用EasyExcel在Excel中增加序号列的方法》

《使用EasyExcel在Excel中增加序号列的方法》 1、简介2、正文3、核心代码4、使用方法5、效果 1、简介 在处理Excel文件时&#xff0c;有时候需要为表格增加序号列。本文介绍了如何使用Java代码实现在Excel中增加序号列的功能&#xff0c;并提供了一个示例代码。 2、正文 在处理…

神经风格转化

深入到神经风格转换的领域。你就会发现尽管NST在概念上很容易理解&#xff0c;但要生成高质量图像却出奇地困难。为了获得良好的结果&#xff0c;必须正确实施许多复杂的细节和未提及的技巧。在本文中&#xff0c;我们将深入研究神经风格转换的知识&#xff0c;并详细研究这些技…

【数学】Pair of Topics—CF1324D

Pair of Topics—CF1324D 思路 很明显&#xff0c;需要对 a i a j > b i b j a_i a_j > b_i b_j ai​aj​>bi​bj​ 化简&#xff1a; a i − b i > b j − a j a_i - b_i > b_j - a_j ai​−bi​>bj​−aj​ a i − b i > − ( a j − b j ) a_…

Android 图层列表 、 LayerDrawable 、 layer-list \ 改变 seekbar thumb 滑块 的颜色

android 官网 &#xff1a; 图层列表 LayerDrawable / layer-list LayerDrawable 是管理其他可绘制对象数组的可绘制对象。列表中的每个可绘制对象均按照列表顺序绘制。列表中的最后一个可绘制对象绘于顶部。 每个可绘制对象均由单个 <layer-list> 元素内的 <item>…

Jetson TX2 Ubuntu18.04安装ROS

1. 配置软件源 2. 使用aptitude解决依赖问题 3.一些报错 主要参考一下两个教程&#xff1a; https://zhuanlan.zhihu.com/p/372481181 https://blog.csdn.net/weixin_45266691/article/details/117427775 2. 安装完aptitude后&#xff0c;使用一下指令进行安装 sudo apti…

读书笔记:彼得·德鲁克《认识管理》第16章 使工作富有成效:核查与工具

一、章节内容概述 我们需要控制生产的方向、质量、数量、标准及经济性。控制是员工的工具&#xff0c;而不能反客为主成为做工的障碍。控制遵循经济原则而不是道德原则。控制不能处理例外情况&#xff0c;只能确保例外情况不会成为常规过程的障碍。控制必须符合常规的模式&…