文章目录
AOP
1.OOP开发思路
2.AOP简介
2.1AOP开发思路
2.2AOP概述
AOP:面向切面编程。它是一种编程范式。指导开发者如何组织程序结构。
AOP弥补了oop的不足,基于oop基础之上进行横向的开发。
OOP的程序开发以类为主题模型,一切围绕着对象进行。
AOP程序主要关注的是OOP开发中的一些共性功能。一切都是围绕着共性功能进行。
2.3.AOP的作用
AOP可以从各个行业的标准化,规范化开始入手。一步一步的将所有的共性功能逐一开发,最终以功能组合的方式完成业务模块甚至整个程序的开发。
目标:将软件开发由手动制作走向半自动化/全自动化阶段。实现"插拔式组件体系"。
2.4 AOP优点
提高了代码的复用性
业务代码更简洁
业务代码维护更加方便
3.AOP的入门程序
3.1 AOP相关概念
JoinPoint:连接点。就是所有的方法
Pointcut:切入点。就是需要挖掉共性代码的方法
Advice:通知。就是共性功能。最终以方法的形式存在
Aspect:切面。共性功能和所挖位置的对应关系
Target:目标对象。就是挖掉共性功能后的类所产生的对象。这种对象无法完成最终工作
Weaving:织入。讲挖掉功能的回调的动态过程
Proxy:代理。目标对象无法直接完成工作。需要对其进行功能回填。通过创建目标对象的代理对象实现
3.2 AOP入门开发思路
开发阶段:
正常的功能开发
挖出功能开发制作成通知。挖掉代码后的方法成为切入点的方法
在配置文件中声明切入点
在配置文件中声明切入点和通知的关系(切面)
运行阶段:
Spring容器加载配置,监控所有配置切入点方法的执行
当监控到切入点方法被运行,使用代理机制动态创建目标对象的代理对象。根据通知类型,在代理对象的对应位置将通知对应的功能(挖出的共性代码)织入。最终完成完整的代码逻辑并运行。
3.3 AOP入门制作
3.3.1 创建项目导入依赖
3.3.2 抽取共性代码
public class UserAdvice {
public void opentx() {
System.out.println("开启了事务");
}
public void closetxAndLog() {
System.out.println("关闭了事务");
System.out.println("记录了日志");
}
}
3.3.3 配置AOP的配置
注意:首先确保配置文件中存在aop的命名空间
<beans>
<!-- 把通知和目标对象加载到容器中 -->
<bean id="userService" class="com.lxk.service.UserService"></bean>
<bean id="userAdvice" class="com.lxk.advice.UserAdvice"></bean>
<!-- aop的配置 -->
<aop:config>
<!-- 配置切入点 -->
<aop:pointcut expression="execution(* *..*(..))" id="pt"/>
<!-- 配置切面 -->
<aop:aspect ref="userAdvice">
<aop:before method="opentx" pointcut-ref="pt"/>
<aop:after method="closetxAndLog" pointcut-ref="pt"/>
</aop:aspect>
</aop:config>
</beans>
3.4 配置详解
3.4.1 AOP配置
名称:aop:config
作用:代表设置AOP
说明:一个Spring中可以配置多个AOP
3.4.2 切入点
名称:aop:pointcut
作用:配置切入点
属性:expression:切入点表达式
说明:一个aop:config标签内可以配置多个aop:pointcut标签。而且这个标签可以配置在aop:aspect标签内
3.4.3 切面
名称:aop:aspect
作用:配置具体额AOP通知对应的切入点
3.5 通知类型
AOP中的通知类型一共5种。
前置通知:aop:before
简介:原始方法执行前执行。如果出现异常,阻止原始方法的执行
应用场景:数据校验
后置通知:aop:after
简介:原始方式执行后执行。无论原始方法是否出现异常都将执行此通知
应用场景:现场清理
返回后通知:aop:after-returning
简介:原始方法执行完毕并且返回结果后执行。如果原始方法抛出异常则无法执行。
引用场景:返回值的相关数据处理
抛出异常后通知:aop:after-throwing
简介:原始方法抛出异常后执行。如果没有异常则无法执行
应用场景:对原始方法中出现的异常信息进行处理
环绕通知:aop:around
简介:在原始方法执行前后都可以执行
注意:环绕通知是在原生方法的前后添加功能,在环绕通知中存在对原始方法的显式调用
方法必须设定Object类型的返回值。否则会拦截原始方法的返回。如果原始方法返回值类型为void,通知方法也可以设置成void。最终返回null。
使用proceed()调用原始方法时,由于无法预知原方法运行是否会出现异常,所以强制抛出异常对象,原始方法可能出现异常信息。
3.6切入点表达式
切入点表达式最终描述的就是某个方法。切入点表达式是一个快速匹配方法描述的通配格式。类似于正则。
格式:关键字(访问修饰符 返回值 包名.类名.方法名(参数)异常名)
关键字:描述表达式的匹配模式。execution:匹配执行指定方法
通配符:*:单个独立的任意符号。可以单独出现,也可以当成前缀和后缀出现。
…:多个连续的任意符号。一般用于简化包名和参数的书写。
+:用于匹配子类型
范例:
execution(* *(..))
execution(* *..*(..))
execution(* *..*.*(..))
//前三个等价
execution(public * *..*.*(..))
execution(public int *..*(..))
execution(public void com..*.*(..))
execution(public void com..*.find*(..))
execution(public void com..*.*(*,int))
execution(public void com..*.findAll())
execution(public void com.lxk.service.*.*())
4.AOP注解
4.1开启AOP注解
<!-- 支持AOP的注解 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<context:component-scan base-package="com.lxk"></context:component-scan>
4.2 注解开发
@Component
@Aspect
public class UserAdvice {
@Pointcut("execution(* *..*(..))")
public void pt() {}
@Before(value="pt()")
public void opentx() {
System.out.println("开启了事务");
}
@After(value="pt()")
public void closetxAndLog() {
System.out.println("关闭了事务");
System.out.println("记录了日志");
}
@AfterThrowing(value="pt()",throwing="yy")
public void afterThrowing(Throwable yy) {
System.out.println("异常通知");
}
@AfterReturning("pt()")
public void afterReturning() {
System.out.println("返回后通知");
}
@Around("pt()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕前");
//调用原始方法
Object proceed = pjp.proceed();
System.out.println("环绕后");
return proceed;
}
}
5.AOP注解驱动
使用@EnableAspectJAutoProxy。具体用法和Spring IOC的注解驱动开发一样。