目录
一、Aop简介
AOP相关术语
二、使用AOP
一、Aop简介
AOP(Aspect Oriented Programming)面向切面编程,一种编程范式,指导开发者如何组织程序结
构
原理:将复杂的需求分解出不同方面,将散布在系统中的公共功能集中解决
采用代理机制组装起来运行,在不改变原程序的基础上对代码段进行增强处理,增加新的功能
作用︰通过预编译和运行期动态代理的方式实现在不修改源代码的情况下给程序动态添加功能的技术
Spring理念︰无入侵式/无侵入式
AOP相关术语
增强处理(Advice):前置增强,后置增强,环绕增强,异常抛出增强,最终增强
切入点(Pointcut):匹配连接点的式子
在SpringAoP中,一个切入点可以只描述一个具体方法,也可以匹配多个方法
连接点(Join Point):程序执行过程中的任意位置,粒度为执行方法、抛出异常、设置变量等
在springAOP中,理解为方法的执行
切面(Aspect):描述通知与切入点的对应关系
目标对象(Target object)
AOP代理(AOP proxy)
织入(Weaving)
二、使用AOP
例如:使用Spring AOP实现日志输出
1.在项目中添加Spring AOP的jar文件
<!-- aop依赖 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<!--日志包-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>
2.编写前置增强和后置增强实现日志功能,创建一个AOP的包,里面建一个类,写如一个方法
public class LogBufferAop {
private static final Logger log = Logger.getLogger(LogBufferAop.class);
/* *//**
* 前置增强
* @param joinPoint
*/
public void before(JoinPoint joinPoint){
log.info("正在调用" + joinPoint.getTarget() + "的"
+ joinPoint.getSignature().getName()+"方法入参是:"
+ Arrays.toString(joinPoint.getArgs()));
}
}
3.编写Spring配置文件,对业务方法进行增强处理
<bean id="logBuffer" class="cn.smbms.aop.LogBufferAop"/>
<!-- 定义切面、连接点、目标对象、织入... -->
<!-- 将处理增强的对象与目标对象结合起来 -->
<aop:config>
<!-- 切入点,定义要被增强的方法的表达式 -->
<aop:pointcut id="pointcut" expression="execution(public boolean addUser(cn.smbms.pojo.User))"/>
<!-- 前置增强 -->
<aop:aspect ref="logBuffer">
<aop:before method="before" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
被增强的方法
public class UserServiceImpl {
public boolean addUser(User user){
System.out.println("service中添加用户成功....");
return true;
}
}
4.编写代码获取带有增强处理的业务对象
servlet中的方法
private UserServiceImpl userService;
public void doPost(){
User user = new User(1,"admin");
boolean isSuccess = userService.addUser(user);
System.out.println("servlet中添加用户的请求成功?" + isSuccess);
}
测试调用servlet中的方法
@Test
public void testServlet(){
UserServlet userServlet = act.getBean("userServlet", UserServlet.class);
userServlet.doPost();
}
定义切入点
切入点表达式标准格式︰动作关键字(访问修饰符 返回值﹑包名.类/接口名.方法名(参数)异常名)
execution (public User com.demo.service.UserService.findById (int) )
动作关键字︰描述切入点的行为动作,例如execution表示执行到指定切入点
访问修饰符: public , private等,可以省略
异常名︰方法定义中抛出指定异常,可以省略
表达式匹配规则举例
public * addNewUser(entity.User): “*”表示匹配所有类型的返回值。
public void *(entity.User): “*”表示匹配所有方法名。
public void addNewUser(..): “..”表示匹配所有参数个数和类型。
* com.service.*.*(..):匹配com.service包下所有类的所有方法。
* com.service..*.*(..):匹配com.service包及其子包下所有类的所有方法
切入点书写规范:
1、所有代码按照标准规范开发,否则以下技巧全部失效
2、描述切入点通常描述接口,而不描述实现类
3、访问控制修饰符针对接口开发均采用public描述(可省略访问控制修饰符描述)
4、返回值类型对于增删改类使用精准类型加速匹配,对于查询类使用*通配快速描述
5、包名书写尽量不使用..匹配,效率过低,常用*做单个包描述匹配,或精准匹配
6、接口名/类名书写名称与模块相关的采用*匹配,例如UserService书写成*Service,绑定业务层
接口名方法名书写以动词进行精准匹配,名词采用*匹配,例如getByld书写成getBy*;,selectAll书写
成selectAll
7、参数规则较为复杂,根据业务方法灵活调整
8、通常不使用异常作为匹配规则
异常抛出增强的特点
在目标方法抛出异常时织入增强处理
可拔插的异常处理方案
<aop:after-returning>后置增强
<aop:aspect ref="theLogger">
<aop:after-returning method="afterReturning" pointcut-ref="pointcut"
returning="result"/>
</aop:aspect>
<aop:after-throwing>元素:定义异常抛出增强
<aop:aspect ref="theLogger">
<aop:after-throwing method="afterThrowing"
pointcut-ref="pointcut" throwing="e" />
</aop:aspect>
<aop:after>最终增强
<aop:aspect ref="theLogger">
<aop:after method="after" pointcut-ref="pointcut"/>
</aop:aspect>
特点:
无论方法是否抛出异常,都会在目标方法最后织入增强处理,即:该增强都会得到执行
类似于异常处理机制中finally块的作用,一般用于释放资源
可以为各功能模块提供统一的,可拔插的处理方案
<aop:around>环绕增强
<aop:aspect ref="theLogger">
<aop:around method="around" pointcut-ref="pointcut"/>
</aop:aspect>
特点:
目标方法前后都可织入增强处理
功能最强大的增强处理
可获取或修改目标方法的参数、返回值,可对它进行异常处理,甚至可以决定目标方法是否执行
常用增强处理类型
增强处理类型 | 特点 |
Before | 前置增强处理,在目标方法前织入增强处理 |
AfterReturning | 后置增强处理,在目标方法正常执行(不出现异常)后织入增强处理 |
AfterThrowing | 异常增强处理,在目标方法抛出异常后织入增强处理 |
After | 最终增强处理,不论方法是否抛出异常,都会在目标方法最后织入增强处理 |
Around | 环绕增强处理,在目标方法的前后都可以织入增强处理 |
Spring AOP配置元素
AOP配置元素 | 描述 |
<aop:config> | AOP配置的顶层元素,大多数的<aop:*>元素必须包含在<aop:config>元素内 |
<aop:pointcut> | 定义切点 |
<aop:aspect> | 定义切面 |
<aop:after> | 定义最终增强(不管被通知的方法是否执行成功) |
<aop:after-returning> | 定义after-returning增强 |
<aop:after-throwing> | 定义after-throwing增强 |
<aop:around> | 定义环绕增强 |
<aop:before> | 定义前置增强 |
<aop:aspectj-autoproxy> | 启动@AspectJ注解驱动的切面 |