spring的aop_Spring AOP 小结
![](/assets/blank.gif)
1. AOP专业概述
在软件行业,AOP为Aspect Oriented Programming的缩写,意思为:面向切面编程,通过预编译方法和运行期动态代理实现程序功能的统一维护的一种技术。
要理解切面变成,就需要先理解什么是切面。用刀把一个西瓜分成两瓣,切开的切口就是切面;炒菜,锅与炉子共同来完成炒菜,锅与炉子就是切面。web层级设计中,web层->网关层->服务层->数据层,每一层之间也是一个切面。编程中,对象与对象之间,方法与方法之间,模块与模块之间都是一个个切面。
在实际工程中,我们一般做活动的时候,一般对每一个接口都会做活动的有效性校验(是否开始、是否结束等等)、以及这个接口是不是需要用户登录。按照正常的逻辑我们可以这么做:
![](/assets/blank.gif)
但是这样做有个问题:有多少接口,就要多少次代码的copy。
![](/assets/blank.gif)
上图,提出一个公共的方法,每个接口都来调用这个接口。
![](/assets/blank.gif)
每个接口总得要调用这个方法,于是就有了切面的概念,我将方法注入到接口调用的某个地方(切点)。
2. AOP中的相关概念
- Aspect(切面): Aspect 声明类似于 Java 中的类声明,在 Aspect 中会包含着一些 Pointcut 以及相应的 Advice。
- Joint point(连接点):表示在程序中明确定义的点,典型的包括方法调用,对类成员的访问以及异常处理程序块的执行等等,它自身还可以嵌套其它 joint point。
- Pointcut(切点):表示一组 joint point,这些 joint point 或是通过逻辑关系组合起来,或是通过通配、正则表达式等方式集中起来,它定义了相应的 Advice 将要发生的地方。
- Advice(增强):Advice 定义了在 Pointcut 里面定义的程序点具体要做的操作,它通过 before、after 和 around 来区别是在每个 joint point 之前、之后还是代替执行的代码。
- Target(目标对象):织入 Advice 的目标对象。
- Weaving(织入):将 Aspect 和其他对象连接起来, 并创建 Adviced object 的过程。
列举一个比较容易理解的例子:
从前有一个叫爪哇的小县城,在一个月黑风高的晚上。这个县城中发生了命案,作案的凶手十分狡猾,现场没有留下什么有价值的线索。不过万幸的是, 刚从隔壁回来的老王恰好在这时候无意中发现了凶手行凶的过程,但是由于天色已晚,加上凶手蒙着面,老王并没有看清凶手的面目,只知道凶手是个男性,身高约七尺五寸。爪哇县的县令根据老王的描述,对守门的士兵下命令说: 凡是发现有身高七尺五寸的男性,都要抓过来审问。士兵当然不敢违背县令的命令,只好把进出城的所有符合条件的人都抓了起来。
首先我们知道,在 Spring AOP 中 Joint point 指代的是所有方法的执行点, 而 point cut 是一个描述信息,它修饰的是 Joint point,通过 point cut,我们就可以确定哪些 Joint point 可以被织入 Advice。对应到我们在上面举的例子,我们可以做一个简单的类比,Joint point 就相当于 爪哇的小县城里的百姓,pointcut 就相当于老王所做的指控,即凶手是个男性,身高约七尺五寸,而 Advice 则是施加在符合老王所描述的嫌疑人的动作:抓过来审问。
- Joint point : 爪哇的小县城里的百姓: 因为根据定义, Joint point 是所有可能被织入 Advice 的候选的点, 在 Spring AOP中, 则可以认为所有方法执行点都是 Joint point. 而在我们上面的例子中, 命案发生在小县城中, 按理说在此县城中的所有人都有可能是嫌疑人.
- Pointcut :男性, 身高约七尺五寸: 我们知道, 所有的方法(joint point) 都可以织入 Advice, 但是我们并不希望在所有方法上都织入 Advice, 而 Pointcut 的作用就是提供一组规则来匹配joinpoint, 给满足规则的 joinpoint 添加 Advice. 同理, 对于县令来说, 他再昏庸, 也知道不能把县城中的所有百姓都抓起来审问, 而是根据凶手是个男性, 身高约七尺五寸, 把符合条件的人抓起来. 在这里 凶手是个男性, 身高约七尺五寸 就是一个修饰谓语, 它限定了凶手的范围, 满足此修饰规则的百姓都是嫌疑人, 都需要抓起来审问.
- Advice :抓过来审问, Advice 是一个动作, 即一段 Java 代码, 这段 Java 代码是作用于 point cut 所限定的那些 Joint point 上的. 同理, 对比到我们的例子中, 抓过来审问 这个动作就是对作用于那些满足 男性, 身高约七尺五寸 的爪哇的小县城里的百姓.
- Aspect::Aspect 是 point cut 与 Advice 的组合, 因此在这里我们就可以类比: “根据老王的线索, 凡是发现有身高七尺五寸的男性, 都要抓过来审问” 这一整个动作可以被认为是一个 Aspect.
3. Spring AOP实现原理
代理模式:(UML图如下)
![](/assets/blank.gif)
代理类实现了被代理类的接口,同时与被代理类是组合的关系。
静态代理:
// 接口类:
interface Person{void speak();
}// 真实实体类
class Actor implements Person{private String content;public Actor(String content){this.content = content;}@Overridepublic void speak() {System.out.println(this.content);}
}//代理类
class Agent implements Person{private Actor actor;private String before;private String after;public Agent(Actor actor, String before, String after){this.actor = actor;this.before = before;this.after = after;}@Overridepublic void speak(){//before speakSystem.out.println("Before actor speak, Agent say: " + before);//real speakthis.actor.speak();//after speakSystem.out.println("After actor speak, Agent say: " + after);}
}
动态代理
首先是java.lang.reflect包里面的InvocationHandler接口:
public interface InvocationHandler{public Object invoke(Object proxy, Method method, Object[] args)throws Throwable;
}
我们对于被代理的类的操作都会由该接口中的invoke()方法来实现,其中的参数的含义是:
- proxy:被代理的类的实例;
- method:调用被代理类的方法;
- args:该方法需要的参数;
使用方法首先是需要实现该接口,并且我们可以在invoke方法中调用被代理类的方法并获得返回值,自然也可以在调用该方法的前后去做一些额外的事情,从而实现动态代理,
另外一个很重要的静态方法是java.lang.reflect包中的Proxy类的newProxyInstance方法:
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException
其中参数含义如下:
loader:被代理的类的类加载器;
inferfaces:被代理类的接口数组;
invocationHandler:就是刚刚介绍的调用处理器类的对象实例;
该方法会返回一个被修改过的实例,从而可以自由的调用该实例的方法。
// Fruit接口
public interface Fruit{public void show();
}//Apple实现Fruit接口:
public class Apple implements Fruit{@Overridepublic void show() {System.out.println("<<<<show method is invoked");}
}//代理类Agent.java
public class DynamicAgent{// 实现InvocationHandler接口,并且可以初始化被代理类的对象static class MyHandler implements InvocationHandler{private Object proxy;public MyHandler(Object proxy){this.proxy = proxy;}// 自定义invoke方法@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable{System.out.println(">>>>>>>>>>before invoking");// 真正调用方法的地方Object ret = method.invoke(this.proxy, args);System.out.println(">>>>>>>>>>after invoking");return ret;}//返回一个被修改过的对象public static Object agent(Class interfaceClazz, Object proxy){return Proxy.newProxyInstance(interfaceClazz.getClassLoader(), new Class[]{interfaceClazz}, new MyHandler(proxy));}}
}public class ReflectTest {public static void main(String[] args) throws InvocationTargetException, IllegalAccessException {//注意一定要返回接口,不能返回实现类否则会报错Fruit fruit = (Fruit) DynamicAgent.agent(Fruit.class, new Apple());fruit.show();}
}
可以看到对于不同的实现类,可以用同一个动态代理类来进行代理,实现了“一次编写到处代理”的效果,但是这种方法有个缺点,就是被代理的类一定要实现了某个接口。
CGLIB库的方法:
CGLib是一个字节码增强库,为AOP等提供了底层的支持。它的实现方式如下:
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;public class CGlibAgent implements MethodInterceptor {private Object proxy;public Object getInstance(Object proxy) {this.proxy = proxy;Enhancer enhancer = new Enhancer();enhancer.setSuperclass(this.proxy.getClass());// 回调方法enhancer.setCallback(this);// 创建代理对象return enhancer.create();}//回调方法@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println(">>>>before invoking");//真正调用Object ret = methodProxy.invokeSuper(o, objects);System.out.println(">>>>after invoking");return ret;}public static void main(String[] args) {CGlibAgent cGlibAgent = new CGlibAgent();Apple apple = (Apple) cGlibAgent.getInstance(new Apple());apple.show();}
}// 运行结果:
// before invoking
// show method is invoked
// after invoking
spring的aop_Spring AOP 小结相关推荐
- 一文读懂Spring中的AOP机制
一.前言 这一篇我们来说一下 Spring 中的 AOP 机制,为啥说完注解的原理然后又要说 AOP 机制呢? 1.标记日志打印的自定义注解 @Target({ElementType.METHOD}) ...
- Spring 实践:AOP
AOP引介 AOP(Aspect Oriented Programing)面向切面编程采用横向抽取机制,以取代传统的纵向继承体系的重复性代码(如性能监控/事务管理/安全检查/缓存实现等). 横向抽取代 ...
- 详解Spring框架的AOP机制
AOP是Spring框架面向切面的编程思想,AOP采用一种称为"横切"的技术,将涉及多业务流程的通用功能抽取并单独封装,形成独立的切面,在合适的时机将这些切面横向切入到业务流程指定 ...
- 【Spring 源码阅读】Spring IoC、AOP 原理小总结
Spring IoC.AOP 原理小总结 前言 版本约定 正文 Spring BeanFactory 容器初始化过程 IoC 的过程 bean 完整的创建流程如下 AOP 的过程 Annotation ...
- Spring 框架的AOP之注解的方式
1. 环境搭建 1.1 导入 jar 包 Spring 框架的基本开发包(6个); Spring 的传统AOP的开发包 spring-aop-4.3.10.RELEASE org.aopallianc ...
- 动态代理——》AOP —— Spring 中的 AOP||AOP 相关术语||学习 spring 中的 AOP 要明确的事
AOP 概述 什么是 AOP AOP:全称是 Aspect Oriented Programming 即:面向切面编程 AOP 的作用及优势 作用: 在程序运行期间,不修改源码对已有方法进 ...
- Spring(IOC+AOP)
Spring 容器(可以管理所有的组件(类))框架: 核心关注:IOC和AOP: Test:Spring的单元测试模块: spring-test-4.0.0.RELEASE Core C ...
- Spring系列之AOP实现的两种方式
Spring只支持XML方式而没有实现注解的方式(也叫AspectJ方式)的AOP,所以要使用@Aspect注解,只能引入AspectJ相关的 jar 包: aopalliance-1.0.jar 和 ...
- Spring源码-AOP(六)-自动代理与DefaultAdvisorAutoProxyCreator
2019独角兽企业重金招聘Python工程师标准>>> Spring AOP 源码解析系列,建议大家按顺序阅读,欢迎讨论 Spring源码-AOP(一)-代理模式 Spring源码- ...
最新文章
- SAP UI5 group function调试
- jboss 配置上下文路径_为单个Web应用程序配置多个上下文根– JBoss
- python判断阿姆斯特朗数_Python 程序检查阿姆斯特朗数
- 如何迁移outlook邮件到另一个硬盘_猎头如何有效的搜寻与筛选简历
- python基础字典(七)
- 本周论文推荐(10.26-11.1)
- 变形金刚图纸_变形金刚救援
- 认知无线电网络中的频谱切换
- python 绝对值计算
- android scroller,深入理解Android中Scroller的滚动原理
- 2022年8月6日(星期六):骑行宁湖公园
- nginx转发post请求
- (六) 自己写简单的u-boot
- 汇编MOVSX指令详解
- 什么是Perl语言?
- 漫画版python_不能错过的Python漫画
- Flink基础系列7-通过Web UI执行jar文件
- java decvm_java – 如何使用-XX:UnlockDiagnosticVMOptions -XX:CompileCommand =打印选项与JVM HotSpot...
- 开源爬虫神器,Playwright vs Puppeteer 对比,你应该选择哪个?
- c语言实现MD5计算