如何理解spring中的切面和过滤 springboot的切面方法怎么写
如何理解spring中的切面和过滤
1, 什么是AOP ?
面向方面/切面的编程:将程序中的交叉业务逻辑(公用代码)提取出来,称为切面,
将这些切面动态的织入到目标对象,生成一个新的代理对象的过程;
把程序划分为两部分:
1) 通用的交叉业务,公用的代码(日志,事务,安全)
2) 具体的业务逻辑处理代码
将切面动态的织入到业务代码中
面向方面/切面编程:将业务分解成切面与具体的业务逻辑模块,将切面透明的接入到业务逻辑模块中,形成一个完整的程序。比如:字符编码;日志;事务等等
2, AOP中的基本概念:
1)切面(Aspect): 指交叉业务逻辑的统称, 比如日志,事务,安全
2)通知(Advice): 指切面的具体实现
3)连接点(Joinpoint):指切面可以织入到(应用到)目标对象的位置(级别), 两个: 方法/属性
代理模式, 调用的是代理对象, 代理维护一个目标对象的属性
调用方法之前, 先写日志 再调用具体的实现方法
调用属性之前, 拦截一下做处理,很少用Spring目前不支持这个
4)切入点(Pointcut):指通知(切面的具体实现)应用到哪些目标对象的哪些方法或者哪些属性上
org.springframework.aop.Pointcut
Spring根据类名称及方法名称定义Pointcut,表示Advice织入至应用程序的时机
5)引入(introduction):指动态的给一个对象增加方法或者属性的过程是一种特殊的通知
6)织入(weaving):将切面(通知)应用到目标对象生成代理的过程
7)代理对象(Proxy): 目标对象应用切面以后生成的代理(切面织入之后生成的新的代理对象)
8)目标对象(Target): 具体业务逻辑的实现(需要织入切面的对象)
3, Spring的AOP, 使用的是动态代理
1) 代理的两种方式:
静态代理:
针对每个具体类分别编写代理类;
针对一个接口编写一个代理类;
IRegister
RegisterService <--- RegisterProxy
目标对象 代理对象
IRegister ir 调用代理的方法, 代理再去调用目标对象的方法
IReport
ReportService <--- ReportProxy
目标对象 代理对象
每一个代理对象只为一个目标对象服务
动态代理:
针对一个方面编写一个InvocationHandler,
然后借用JDK反射包中的Proxy类为各种接口动态生成相应的代理类
告诉一个类,我的接口是什么, 目标类是什么, 自动生成代理
2) 动态代理例子:
public class MyProxyCreater implements java.lang.reflect.InvocationHandler {
private Object target
public MyProxyCreater(Object target) {
super()
this.target = target
}
public static Object createProxy(Object o){
//类加载器,实现的接口,代理生成的类
//根据三个参数创建一个代理对象;
//通过类加载器,借口,和实现类得到一个代理对象
//目标对象最少要实现一个接口
return
Proxy.newProxyInstance(o.getClass().getClassLoader(),
o.getClass().getInterfaces(),new MyProxyCreater(o))
}
//代理对象,目标方法,目标对象的参数
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object rst=null
//加切面
System.out.println("loging...")
rst=method.invoke(target, args)
return rst
}
}
spring思想:
1,将切面使用动态代理的方式动态地织入到目标对象(被代理对象)生成新的代理对象;
2,目标对象如果没有实现代理接口,spring采用CGLIB来生成代理对象,
该代理对象是目标对象的子类;
3,目标对象如果是final类,并且没有实现代理接口,就不能运用AOP了;
目标对象如果没有实现接口, spring采用CGLIB库来动态生成一个代理,
代理是目标对象的子类 目标对象不能是final的
Spring采用动态代理来实现AOP, 在运行时,spring将切面应用到目标对象生成动态代理,
客户端使用动态代理来调用
AspectJ: 需要学习一些别的语言,
支持属性连接点 可以在编译期生成代理 需要把编译器重新写一遍
难度比较大
3) Advice :
切面的实现:
类型:
(1)org.springframework.aop.MethodBeforeAdvice
在方法调用之前,做处理。
不能够改变返回值
不能够改变目标方法的流程,也不能中断流程的处理过程(除非抛出异常)
before(目标方法,目标方法的参数,目标对象)
public void before(Method method, Object[] objectArray, Object object) throws Throwable
(2)org.springframework.aop.AfterReturningAdvice
在方法调用之后,做处理。
不能够改变返回值
不能够改变目标方法的流程,也不能中断流程的处理过程(除非抛出异常)
void afterReturning(Object returnValue, Method method, Object[] args, Object target)
(3)org.aopalliance.intercept.MethodInterceptor
aop联盟框架 保证代码兼容别的aop框架
拦截器, 通知,跟filter差不多
在方法调用之前以及之后,做处理。
可以改变返回值,也可以改变流程。
public Object invoke(MethodInvocation methodInvocation) throws Throwable
(4)org.springframework.aop.ThrowsAdvice
在目标方法抛出异常后,会根据异常类型选择的做处理。
当该通知处理完异常后,会简单地将异常再次抛出给客户端调用。
public void afterThrowing(IllNameException e)
public void afterThrowing(IllAgeException e)
内置的创建代理类:
org.springframework.aop.framework.ProxyFactoryBean
proxyInterfaces,interceptorNames,target
作用:依照配置信息,将切面应用到目标对象,生成动态代理对象;
配置过程:
(1)配置目标对象,
(2)注入切面: 通知, Advisor, 拦截器
(3)利用ProxyFactoryBean将切面织入到目标对象,生成动态代理对象
客户端调用的是代理的对象
如果目标对象没有实现指定接口,不用配置ProxyInterfaces, (cglib会生成一个)
实现了接口,也可以不写的
(4)客户端使用动态代理来访问目标对象的方法。
注: 在默认情况下,通知会应用到目标对象的所有方法之上。
编码过程: 目标对象--通知--代理--客户端调用
例子: (aop3)四种通知
练习: (aop4)在拦截器设置一个属性,记录方法超时的时间
4) 切入点:
通知具体应用到哪些类的哪些方法之上
自定义切入点:用来约束Advice
步骤:
1)实现org.springframework.aop.ClassFilter--->用来过滤类(哪些类可以应用切面)
如果返回值为true时, 则应用切面 否则不应用切面
对类进行过滤,看要不要将切面应用到该类上
2)实现org.springframework.aop.MethodMatcher--->用来过滤方法(类中的哪些方法应用切面)
方法1: boolean matches(Method, Class)//
方法2: boolean isRunTime() 返回值为真,该切入点是动态切入点
否则是静态切入点 方法3不会被执行
方法3: boolean matches(Method, Class,Object[])//这个方法可以动态的获得方法的信息;
解释:
静态切入点:
在目标方法被执行以前, 确定切面是否应用到目标方法之上
根据目标方法的静态特征(方法所在的类名A, 方法名f1), 来决定
一般用这个
动态切入点:
在目标方法每一次执行,会依照方法的动态的特征来决定是否应用切面
动态特征: 当前方法的参数值, 等等
会影响性能很大, 很少使用
3)实现org.springframework.aop.Pointcut
4)实现org.springframework.aop.PointcutAdvisor:将Pointcut与Advice结合到一起。
是一个特殊的通知,它包含了切入点在内;
注意:
在此可定义两个属性,并且通过配置文件来完成装配工作;
private Advice advice//通知的实现
private Pointcut pointcut//通知的应用地点
在配置文件中,将自定义的切入点与通知绑订到一起,成为Advisor
5)利用ProxyFactoryBean将advisor织入到目标对象
springboot的切面方法怎么写
它分成以下几个步骤: 建立mock; 将mock和待测试的对象连接起来; 在mock上设置预期的返回值; 开启replay模式,准备记录实际发生的调用; 进行测试; 验证测试结果,调用顺序是否正确,返回值是否符合期望;
spring 怎么自定义切面加入默认方法执行
当我们使用AOP时,大部分时候我们使用的是其声明式事务管理的功能,可以很便捷的为我们提供事物的控制,但很多时候,除事物控制外,我们还希望做更多的操作,例如权限控制、日志记录、失败后数据记录等等,这时我们可以自定义切面,并自己实现一个切面的实现类,去实现我们自己的业务规则。
本文中Spring版本为2.5。
spring aop切面织入方式有哪些
1.通知(Advice):
通知定义了切面是什么以及何时使用。描述了切面要完成的工作和何时需要执行这个工作。
2.连接点(Joinpoint):
程序能够应用通知的一 个“时机”,这些“时机”就是连接点,例如方法被调用时、异常被抛出时等等。
3.切入点(Pointcut)
通知定义了切面要发生的“故事”和时间,那么切入点就定义了“故事”发生的地点,例如某个类或方法的名称,spring中允许我们方便的用正则表达式来指定
4.切面(Aspect)
通知和切入点共同组成了切面:时间、地点和要发生的“故事”
5.引入(Introduction)
引入允许我们向现有的类添加新的方法和属性(spring提供了一个方法注入的功能)
6.目标(Target)
即被通知的对象,如果没有AOP,那么它的逻辑将要交叉别的事务逻辑,有了AOP之后它可以只关注自己要做的事(AOP让他做爱做的事)
7.代理(proxy)
应用通知的对象,详细内容参见设计模式里面的代理模式
8.织入(Weaving)
把切面应用到目标对象来创建新的代理对象的过程,织入一般发生在如下几个时机:
(1)编译时:当一个类文件被编译时进行织入,这需要特殊的编译器才可以做的到,例如AspectJ的织入编译器
(2)类加载时:使用特殊的ClassLoader在目标类被加载到程序之前增强类的字节代码
(3)运行时:切面在运行的某个时刻被织入,SpringAOP就是以这种方式织入切面的,原理应该是使用了JDK的动态代理技术