AOP(Aspect Oriented Programing)面向切面编程
AOP是一种编程范式,隶属于软工范畴,指导开发 者如何组织程序结构
AOP弥补了OOP的不足,基于OOP基础之上进行 横向开发
AOP联盟
一、OOP范式编程
OOP规定程序开发以类为模型,一切围绕对象进行, OOP中完成某个任务首先构建模型,基于模型展开 业务
OOP主要应用于WEB开发,围绕OOP的主思想, 对开发过程进行了分层设计
二、AOP范式编程
AOP范式编程研究的不是层与层之间的关系,也不 是每层内部如何开发,AOP主要关注同一层面的各 个不同功能模块之间的共性功能。
AOP时代的到来,使开发模块化的思想进行了进一 步的提升,从刀耕火种的纯手工开发阶段,向半自 动化/自动化阶段进行了一个大的突破。IT研发朝着 “插拔式组件体系结构”又近了一步。
三、基本概念(重点)
1、连接点(Joinpoint)
2、切入点(Pointcut)
3、通知(Advice)
4、目标对象(Target Object)
5、AOP代理(AOP Proxy)
6、织入(Weaving)
7、切面(Aspect)
1、连接点(Joinpoint)
①、程序运行过程中,JVM负责程序运行。执行到某个 方法时,JVM能识别当前执行的是哪个方法。这些 定义在类中的方法,每个具有独立的功能,在AOP 中,将这些具有特定功能的方法称为连接点。
②、连接点指类中的方法
2、切入点(Pointcut)
①、 类中的方法具有很多,某些方法具有一些共同的流 程,例如数据库连接的获取与关闭,事务的开启与 提交,等等。将这些公共的特性抽取出来,抽取完 毕后,原始方法中就缺少了这些被抽取的代码。在 实际运行时,缺少这些代码是无法完成原始的功能 的。这些被抽取了公共功能的方法称为切入点。
②、切入点一定是连接点,连接点不一定是切入点
③、切入点指被抽取了共性功能的方法
3、通知(Advice)
①、切入点对应的方法的共性功能被抽取后,组成独立 代码逻辑,被封装在某个类的某个方法中,在被抽 取了共性功能的方法被执行时,这些代码逻辑还要 加入原始方法的执行,这些被抽取出来组成独立代 码逻辑的共性功能称为通知。
②、共性功能被抽取后,可能来自于切入点对应的方法 中的任何位置,因此通知不仅描述共性的代码逻辑, 还是描述被抽取时从何处抽取。例如切入点代码逻 辑的前面、中间还是后面,被抽取的代码在切入点 中的具体位置,称为通知类别。
4、目标对象(Target Object)
①、切入点对应的共性功能被抽取后创建独立的通知完 成共性功能,在程序运行时,动态的为类对象执行 切入点方法时动态加入被抽取的共性功能,此时需 要使用代理的模式完成。此时被代理创建的对象, 称为目标对象。
②、目标对象指包含切入点的类对象
5、AOP代理(AOP Proxy)
①、切入点所在的类对象执行切入点方法时,需要将原 始的共性功能(通知)加入,此时通过代理的形式创 建类对象,并完成共性功能(通知)的加入,上述过 程称为AOP代理。
②、AOP代理的意义是将被抽取共性功能的类对象创建 出,同时将共性功能(通知)加入,完成原始的完整 操作的执行过程。
6、切面(Aspect)
①、切面是一个设计概念,指切入点与通知的匹配模式, 换句话说指被抽取了共性功能的方法(切入点)与被 抽取了共性功能(通知)对应的绑定关系。
②、程序设计时,可以设置多个切面,用来描述切入点 与通知之间的关系。
7、织入(Weaving)
①、通过AOP代理,完成了切入点与通知的融合,并组 成了完整的代码逻辑,将通知加入到切入点对应位 置的动作称为织入。
②、织入是一个动态过程,不对应任何代码,可以理解 为动态的运行过程。
③、织入可以在三个阶段进行,编译时,类加载时,运 行时。Spring采用的是运行时织入。
四、AOP工作流程
1、 开发阶段(开发者完成) 将共性功能独立开发出来,制作成通知 将非共性功能开发到对应的目标对象类中,并制作成切入点 方法 在配置文件中,声明切入点与通知间的关系,即切面
2、运行阶段(AOP完成) JVM读取配置文件中的信息,监控切入点方法的执行 一旦监控到切入点方法被运行,使用代理机制,动态创建目 标对象的代理对象,根据通知类别,在代理对象的对应位置, 将通知对应的功能织入,完成完整的代码逻辑运行。
⑤、XML配置开发AOP
导入jar包
基本
Spring核心包(4个) 日志相关(2个) 集成JUnit(1个)
AOP相关
Spring进行AOP开发(1个)(3.2资源包)
spring-aop-3.2.0.RELEASE.jar
Spring整合AspectJ框架(3.2资源包)
spring-aspects-3.2.0.RELEASE.jar
AOP联盟规范(1个) (3.0.2依赖包)
com.springsource.org.aopalliance-1.0.0.jar
aspectJ支持(1个) (3.0.2依赖包)
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
六、AspectJ
1、AspectJ是一个面向切面的框架,它扩展了Java语 言。AspectJ定义了AOP语法,所以它有一个专门的 编译器用来生成遵守Java字节编码规范的Class文 件。
2、Spring2.0+提供对AspectJ的支持
3、早期的SpringAOP开发十分繁琐,Spring2.x推荐使 用AspectJ进行SpringAOP开发
七、AOP开发——
1、目标对象制作
制作目标对象类,制作连接点方法,并将其配置成 Spring所控制的Bean
2、AOP开发——通知制作
制作通知对应的类,并制作出被抽取的通用功能, 将其封装到方法中,并将该类配置成Spring所控制 的Bean
3、AOP开发——开启AOP配置
在XML配置文件中,开启AOP命名空间
4、AOP开发——配置切面
在XML配置文件中使用aop命名空间进行AOP配置
5、AOP切入点表达式
AOP切入点表达式支持多种形式的定义规则
execution:匹配方法的执行(常用)
execution(public * *(..))
within:匹配包或子包中的方法(了解)
within(com.bdyc.aop..*)
this:匹配实现接口的代理对象中的方法(了解)
this(com.bdyc.aop.user.UserDAO)
target:匹配实现接口的目标对象中的方法(了解)
target(com.bdyc.aop.user.UserDAO) args:匹配
参数格式符合标准的方法(了解) args(int,int)
execution:
匹配方法的执行(常用)
格式:execution(方法格式表达式)
例一:匹配所有指定返回值类型的方法
void *(..) int *(..) double *(..)
例二:匹配指定包或子包中类的方法
*..*() com.bdyc.aop.user.dao.*.*(..) cn..dao.*.*(..)
例三:匹配指定类或接口的方法
* *..UserImpl.*(..) * *..*Impl.*(..) * *..*DAO.*(..)
例四:匹配指定方法名或部分匹配方法名的方法
*..*.add(..) *..*.*e*(..) *..*.get*(..)
例五:匹配所有指定参数个数或类型的方法
* *..*.*(int,int) * *..*.*(*,*) * *..*.*(*,..)
6、AOP切入点配置
AOP配置中,由于切入点使用量很大,Spring提供 了AOP切入点配置的引用格式
以下两种格式是等效的
格式一:直接配置切入点
7、AOP通知类型
AOP的通知类型共5种
①、before:前置通知(应用:各种校验) 在方法执行前执行,如果其中抛出异常
②、after:后通知(应用:清理现场) 方法执行完毕后执行,无论方法中是否出现异常
③、afterReturning:返回后通知(应用:常规数据处理) 方法正常返回后执行,如果方法中抛出异常(没处理)无法执行
④、afterThrowing:抛出异常后通知(应用:包装异常信息) 方法抛出异常后执行,如果方法没有抛出异常,无法执行
⑤、around:环绕通知(应用:十分强大,可以做任何事情) 方法执行前后分别执行,可以阻止方法的执行
8、AOP通知类型配置
使用aop命名空间,配置5种通知类型
常用属性
pointcut:配置切入点表达式
pointcut-ref:配置切入点引用对象
method:配置切入点执行的通知方法
AOP通知类型对应的方法
注解开发AOP(@AspectJ支持)(重点)
@AspectJ提供使用注解开发SpringAOP
开启Spring对@AspectJ注解开发的支持
注解开发AOP
使用注解开发AOP要保障所有的相关类必须受到 Spring控制,因此在进行注解开发AOP之前,首先 将所有相关类配置成Bean
配置式 注解式
注解开发AOP——配置aspect
使用@Aspect将Bean设置为切面
使用注解配置@Aspect与下列效果等同,注解免去了配置 时指定对应Bean的环节
注解开发AOP——配置通知类型
通知类型通过注解的形式完成 使用@Before将指定方法设置为前置通知
注解开发AOP——切入点
只用注解形式开发公共切入点 使用@Pointcut配置切入点,@Pointcut声明在无返回值方 法上方,方法名即切入点名称,方法最好声明为private
注解开发AOP——各种通知类型
前置通知
@Before(value="execution(* *..*.*(..))")
后置通知
@After(value="execution(* *..*.*(..))")
抛出异常通知
@AfterThrowing(value="execution(* *..*.*(..))",throwing=“ex")
返回后通知
@AfterReturning(value="execution(* *..*.*(..))",returning=“ret")
环绕通知
@Around(value="execution(* *..*.*(..))")
eg:
/** * 接口 * @author Thinkpad * */ public interface UserServiceI { public void add(); public void del(); public void update(); public void fnn(); } /** * 业务类 * @author Thinkpad * */ //目标对象 public class UserService implements UserServiceI{ //连接点/切入点 public void add() { //1、抽查公共模块到通知类中 System.out.println("3、执行添加"); } public void del() { // TODO Auto-generated method stub } public void update() { // TODO Auto-generated method stub } public void fnn() { // TODO Auto-generated method stub } } <!--XML配置文件--> <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd "> <!-- 创建一个通知类对象:advice --> <bean id="myAdvice" class="com.wd.aop.Advice"></bean> <!-- AOP配置 --> <aop:config> <!-- 配置切面 ref:使用通知类对象 --> <aop:aspect ref="myAdvice"> <!-- method:要切入的通知方法 --> <aop:before method="fn1" pointcut="execution(public void com.wd.aop.UserService.add())"/> <aop:after method="fn2" pointcut="execution(public void com.wd.aop.UserService.add())"/> </aop:aspect> </aop:config> <!-- spring 内部默认支持代理是: JDKProxy:只能代理基于接口的对象 CGLIBProxy:能代理任何对象 --> <bean id="userService" class="com.wd.aop.UserService" ></bean> </beans> /** * 测试类 * @author Thinkpad * */ public class Test { public static void main(String[] args){ ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); UserServiceI userService = (UserServiceI) ac.getBean("userService");//spring 内部默认支持代理是:JDKProxy:只能代理基于接口的对象 // CGLIBProxy:能代理任何对象
userService.add(); } }
输出结果:
eg(cglib代理模式):
首先导入cglib.jar
/** * 业务类 * @author Thinkpad * */ //目标对象 public class UserService{ //连接点/切入点 public void add() { //1、抽查公共模块到通知类中 System.out.println("3、执行添加cglib代理"); } public void del() { // TODO Auto-generated method stub } public void update() { // TODO Auto-generated method stub } public void fnn() { // TODO Auto-generated method stub } } <!--XML配置文件--> <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd "> <!-- 创建一个通知类对象:advice --> <bean id="myAdvice" class="com.wd.aop.Advice"></bean> <!-- AOP配置 --> <aop:config> <!-- 配置切面 ref:使用通知类对象 --> <aop:aspect ref="myAdvice"> <!-- method:要切入的通知方法 --> <aop:before method="fn1" pointcut="execution(public void com.wd.aop.UserService.add())"/> <aop:after method="fn2" pointcut="execution(public void com.wd.aop.UserService.add())"/> </aop:aspect> </aop:config> <!-- spring 内部默认支持代理是: JDKProxy:只能代理基于接口的对象 CGLIBProxy:能代理任何对象 --> <bean id="userService" class="com.wd.aop.UserService" ></bean><!--开启cglib代理--> <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy> </beans> /** * 测试类 * @author Thinkpad * */ public class Test { public static void main(String[] args){ ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService userService = (UserService) ac.getBean("userService");//注:用类而不是接口 userService.add(); } }
输出结果:
来源:https://www.cnblogs.com/xsdf/p/7699058.html