前言

  在Spring或者SpringBoot中,可以通过@Aspect注解和切点表达式等配置切面,实现对某一功能的织入。然而其内部到底是如何实现的呢?

  实际上,Spring在启动时为切点方法所在类生成了代理类,通过操作代理类代替操作实际类,从而实现在真正调用方法之前或之后,插入一些我们自定义的逻辑。

  如何生成代理类呢?

JDK动态代理

  • JDK动态代理要求 被代理类必须有接口抽象。
  • 通过实现  InvocationHandler 接口并实现  invoke(Object proxy, Method method, Object[] args) 方法进行自定义逻辑的织入:
    • proxy :当前的代理类实例;
    • method:被代理的方法;
    • args:方法入参;

invoke方法的官方说明如下:即在

* Processes a method invocation on a proxy instance and returns
* the result. This method will be invoked on an invocation handler
* when a method is invoked on a proxy instance that it is
* associated with. 

  使用示例:

1、被代理的方法:

// 方法实现
public class HelloAOPImpl implements HelloAOP {
@Override
public String sayHello() {
String hello = "你好,AOP";
System.out.println(hello);
return hello;
}
}

  

2、配置自定义调用处理器

public class MyInvocationHandler implements InvocationHandler {
private Object target;
  // 通过构造函数将配代理对象注入
public MyInvocationHandler(Object target) {
this.target = target;
} //回调
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我是代理,有人让我对你说:");
/**调用前,自定义业务*/
Object res = method.invoke(target, args);
/**调用后,自定义业务*/
return res;
}
//获取代理类实例
public <T> T getProxyInstance(){
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
}
}

2:调用与输出:

public static void main(String[] args) {
HelloAOPImpl helloAOP = new HelloAOPImpl();
MyInvocationHandler myInvocationHandler = new MyInvocationHandler(helloAOP);
HelloAOP proxy = myInvocationHandler.getProxyInstance();
proxy.sayHello();
} // 输出
我是代理,有人让我对你说:
你好,AOP

一个疑问:代理类如何取代被代理类的呢?

CGLIB动态代理

CGLIB动态代理不需要代理对象实现某个接口:

1、被代理类(没有接口实现)

public class HelloAOPImpl2 {
public void sayHello() {
String s = "你好,AOP";
System.out.println(s);
}
}

2、CGLIB代理

public class CgibAOP2 implements MethodInterceptor {
private Object target; /**
* 通过构造函数设置被代理对象
* @param target
*/
public CgibAOP2(Object target) {
this.target = target;
} /**
* 回调该方法。
* @param o
* @param method
* @param objects
* @param methodProxy
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("say之前:"+ method+"1");
Object res = method.invoke(target, objects);
System.out.println("say之后:"+ method+"1");
return res;
} /**
* 生成代理实例
* @return
*/
public Object getProxy(){
// 通过增强实现
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this); //设置回调
Object res = enhancer.create();
return res;
}
}

3、测试:

public class Test {
public static void main(String[] args) {
HelloAOPImpl2 helloAOP = new HelloAOPImpl2();
HelloAOPImpl2 proxy = (HelloAOPImpl2)new CgibAOP2(helloAOP).getProxy();
proxy.sayHello();
}
}

输出:

say之前:public void com.wht.springaop.DynamicProxy.Cglib.HelloAOPImpl2.sayHello()1
你好,AOP
say之后:public void com.wht.springaop.DynamicProxy.Cglib.HelloAOPImpl2.sayHello()1

SpringAOP--代理的更多相关文章

  1. SpringAOP代理报错问题

    public class BaseDataSyncPushJob implements StatefulJob{ /*** 日志 */ private static final Log LOG = L ...

  2. spring-aop代理的生效原理

    主要说下spring里aop的生效的原理吧,并不是讲底层的cglib和gdk动态代理. 还是老一套的分析流程,先找到了aop的标签的handler,然后看下在解析这个标签的时候,都干了些什么,其实主要 ...

  3. SpringAOP深入学习

    ----------------------Spring AOP介绍------------------ 1.编程范式概念 面向过程编程:C 面向对象编程:c++,Java 函数式编程 事件驱动编程: ...

  4. spring源码学习之路---深入AOP(终)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 上一章和各位一起看了一下sp ...

  5. 教育单元测试mock框架优化之路(中)

    转载:https://sq.163yun.com/blog/article/169564470918451200 三.间接依赖的bean的mock替换 对于前面提供的@Mock,@Spy+@Injec ...

  6. 面试真题--------spring源码解析AOP

    接着上一章对IOC的理解之后,再看看AOP的底层是如何工作的. 1.实现AOP的过程    首先我们要明白,Spring中实现AOP,就是生成一个代理,然后在使用的时候调用代理. 1.1 创建代理工厂 ...

  7. Spring中AOP实现

    1.什么是SpringAOP 什么是aop:Aspect Oriented Programming的缩写,面向切面编程,通过预编译和动态代理实现程序功能的 统一维护的一种技术 主要功能:日志记录,性能 ...

  8. Spring5参考指南:AspectJ注解

    文章目录 什么是AspectJ注解 启用AOP 定义Aspect 定义Pointcut 切入点指示符(PCD) 切入点组合 Advice 访问JoinPoint Advice参数 Advice参数和泛 ...

  9. @Transactional-同一个类中方法自调,调用方法事物失效

    问题分析 一个类中的方法调用另一个事物传播性为创建事物的方法,调用的方法事物失效? SpringAOP 代理的Service对象调用了其方法,这个方法再去调用这个Service中的其他方法是没有使用A ...

  10. Spring事务的介绍,以及基于注解@Transactional的声明式事务

    前言 事务是一个非常重要的知识点,前面的文章已经有介绍了关于SpringAOP代理的实现过程:事务管理也是AOP的一个重要的功能. 事务的基本介绍 数据库事务特性: 原子性 一致性 隔离性 持久性 事 ...

随机推荐

  1. 图的深度遍历(C语言)邻接矩阵表示

    知识讲解: 图的遍历分为两种,深度遍历与广度遍历.这里讨论深度遍历. 以上图为例讨论图(图片来自<算法笔记>)的深度遍历: 设图形的顶点数为n. 先从顶点v0开始,用一个数组vis[n]来 ...

  2. k8s节点简介、移除节点、新增节点

    简介 Node是Pod真正运行的主机,可以是物理机也可以是虚拟机. Node本质上不是Kubernetes来创建的, Kubernetes只是管理Node上的资源. 为了管理Pod,每个Node节点上 ...

  3. 「Excel实用技巧」拿下这个报表工具,轻松给报表加水印!

    水印报表是什么?怎么给excel表格加水印? 许多时候,为了防止报表被盗.保护信息安全和保护版权,采用水印能够有效实现该需求.水印是为了防止报表被盗.进行真伪鉴别.版权保护等,而在报表中添加半透明的图 ...

  4. XML序列化反序列化

    using System; using System.Collections.Generic; using System.IO; using System.Xml.Serialization; nam ...

  5. Python回顾笔记(此讲大致说明,详情请看之前的笔记)

    内容概要 数据分析(numpy,pandas,matplib) 数据清洗 爬虫 teableau软件 今日内容概要 Python知识回顾 数据分析 ipython模块 anaconda软件 numpy ...

  6. while + else 使用,while死循环与while的嵌套,for循环基本使用,range关键字,for的循环补充(break、continue、else) ,for循环的嵌套,基本数据类型及内置方法

    今日内容 内容概要 while + else 使用 while死循环与while的嵌套 for循环基本使用 range关键字 for的循环补充(break.continue.else) for循环的嵌 ...

  7. 超强视频超分AI算法,从此只看高清视频

    最近发现一个特别强的视频超分算法----BasicVSR,在真实世界数据集中,实现了前所未有的视觉重建效果,最近它还拿下了超分比赛NTIRE 2021三冠一亚的优异成绩,登上了CVPR 2022. 视 ...

  8. jvm初步理解

    1.什么是运行时数据区? 1.什么是运行时数据区 ​ javac 指令:编译java文件生成class文件 ​ java指令:运行class文件即将数据放到jvm中 ​ class文件运行,后将不同的 ...

  9. 如何在 MWeb 中配置 Hexo 等静态网站

    原文链接 参考链接: https://zh.mweb.im/mweb-1.4-add-floder-octpress-support.html https://zhuanlan.zhihu.com/p ...

  10. Windows 下 MySQL 简单定时自动备份、删除过期备份

    Windows 下 MySQL 简单定时自动备份.删除过期备份 MySQL Workbench 客户端虽然好用,但并不提供自动备份功能.手工备份,确实繁琐. 新建一个 数据库备份文件存放目录,本例为D ...