Spring学习-5
AOP(面向切面编程)
英文名称:(Aspect Oriented Programming)
正常程序执行流程都是纵向执行流程
又叫面向切面编程,在原有纵向执行流程中添加横切面
- 特点:
- 不需要修改原有程序代码
- 高扩展性
- 原有功能相当于释放了部分逻辑.让职责更加明确.
面向切面编程是什么?
在程序原有纵向执行流程中,针对某一个或某一些方法添加通知,形成横切面过程就叫做面向切面编程.
常用概念
- 原有功能: 切点,pointcut
- 前置通知: 在切点之前执行的功能.beforeadvice
- 后置通知: 在切点之后执行的功能,afteradvice
- 如果切点执行过程中出现异常,会触发异常通知.throwsadvice
- 所有功能总称叫做切面.
- 织入: 把切面嵌入到原有功能的过程叫做织入
- spring 提供了 2 种 AOP 实现方式
- Schema-based
- 每个通知都需要实现接口或类
- 配置 spring 配置文件时在
<aop:config>
配置
- AspectJ
- 每个通知不需要实现接口或类
- 配置 spring 配置文件是在
<aop:config>
的子标签<aop:aspect>
中配置
- Schema-based
1)目标方法的调用由环绕通知决定,即你可以决定是否调用目标方法,而前置和后置通知 是不能决定的,他们只是在方法的调用前后执行通知而已,即目标方法肯定是要执行的。
2) 环绕通知可以控制返回对象,即你可以返回一个与目标对象完全不同的返回值,虽然这很危险,但是你却可以办到。而后置方法是无法办到的,因为他是在目标方法返回值后调用
Schema-based 实现AOP
导入jar
前置通知
新建前置通知类–实现MethodBeforeAdvice接口
- method: 切点方法对象 Method 对象
- objects: 切点方法参数
- o:切点在哪个对象中
后置通知
1.新建后置通知类–实现AfterReturningAdvice接口
- o:切点方法返回值
- method:切点方法对象
- objects:切点方法参数
- o1:切点方法所在类的对象
2.配置 spring 配置文件
- 引入 aop 命名空间
- 配置通知类的<-bean>
- 配置切面
‘*’
通配符,匹配任意方法名,任意类名,任意一级包名- 如果希望匹配任意方法参数
(..)
3.测试
异常通知
1.异常通知–实现ThrowsAdvice接口
- 必须自己写方法,且必须叫
afterThrowing
- 有两种参数方式 必须是 1 个或 4 个
- 异常类型要与切点报的异常类型一致
2.在 ApplicationContext.xml 配置
3.测试
环绕通知
1.环绕通知–实现MethodInterceptor接口
新建一个类实现 MethodInterceptor
2.配置spring配置文件
3.测试
总结
新建一个通知,要创建一个类来实现相应通知的接口。
在spring配置文件中,首先要通过bean标签将通知类交给spring实例化。然后通过aop:config标签配置切面,在此标签下通过aop:pointcut配置切点,expression属性配置切点的具体所在位置。通过aop:advisor标签引入相应已经给spring实例类。
AspectJ方式实现AOP
xml
1.新建类,不用实现。类中方法名任意
2.配置 spring 配置文件
<aop:after/>
后置通知,是否出现异常都执行<aop:after-returing/>
后置通知,只有当切点正确执行时执行<aop:after/>
和<aop:after-returing/>
和<aop:after-throwing/>
执行顺序和配置顺序有关execution() 括号不能扩上 args
中间使用 and 不能使用&& 由 spring 把 and 解析成&&
args(名称) 名称自定义的.顺序和 demo1(参数,参数)对应
<aop:before/>
arg-names=” 名称 ” 名称来源 于expression=”” 中 args(),名称必须一样- args() 有几个参数,arg-names 里面必须有几个参数
arg-names=”” 里面名称必须和通知方法参数名对应
总结
使用AspectJ方式不需要实现通知接口,自定义通知方法。
在spring配置文件中首先通过bean标签将存在通知方法的的类交给spring管理实例化。在通过aop:config标签配置切面,在标签内使用aop:aspect标签声明使用的是AspectJ方式并通过ref引用含有通知方法的类。通过aop:pointcut配置切点expression属性配置切点的具体所在位置。通过aop:before标签声明前置通知,aop:after标签声明后置通知,aop:after-throwing声明异常通知,aop:around声明环绕通知。此类标签通过pointcut-ref引用切点,method引用具体方法,arg-names引用参数。
注解
spring 不会自动去寻找注解,必须告诉 spring 哪些包下的类中可能有注解,引入xmlns:context
和<context:component-scan>
标签
@Component
- 相当于
<bean>
- 如果括号里没有参数,默认实例化后id为把类名首字母变小写,相当于<-bean id=””/>
- @Component(“自定义名称”)
在 Demo 类中添加@Componet,在方法上添加@Pointcut(“execution(* 包名+类名+方法名”)
定义切点
在通知类中配置
- @Component 类被 spring 管理
- @Aspect 相当于
<aop:aspect/>
表示通知方法在当前类中
spring配置文件中修改代理模式默认为jdk模式
代理设计模式
设计模式:前人总结的一套解决特定问题的代码.
- 代理设计模式优点:
- 保护真实对象
- 让真实对象职责更明确.
- 扩展
- 代理设计模式
- 真实对象.(老总)
- 代理对象(秘书)
- 抽象对象(抽象功能),谈小目标
静态代理设计模式
- 由代理对象代理所有真实对象的功能.
- 自己编写代理类
- 每个代理的功能需要单独编写
- 静态代理设计模式的缺点:
- 当代理功能比较多时,代理类中方法需要写很多.
动态代理
为了解决静态代理频繁编写代理功能缺点.
分类:
- JDK 提供的
- cglib 动态代理
JDK 动态代理
和 cglib 动态代理对比
- 优点:jdk 自带,不需要额外导入 jar
缺点:
- 真实对象必须实现接口
- 利用反射机制.效率不高.
使用 JDK 动态代理时可能出现下面异常
出现原因:希望把接口对象转换为具体真实对象
cglib 动态代理
- cglib 优点:
- 基于字节码,生成真实对象的子类.
- 运行效率高于 JDK 动态代理.
- 不需要实现接口
- cglib 缺点:
非 JDK 功能,需要额外导入 jar - 使用 springaop 时,只要出现 Proxy 和真实对象转换异常
- 设置为 true 使用 cglib
- 设置为 false 使用 jdk(默认值)
1
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>