AOP简介
AOP:面向切面编程。于oop一样是一种软件的编程思想。
在日常的软件开发中,比如一个方法处理在处理核心的业务逻辑时,可能还要考虑到日志,事物,安全认证等方面,如果我们把这些代码都杂糅到一个方法里面,或者方法调用方法,会显得代码过于臃肿,不利于复用。有人说我们可以利用继承和委托来解决这个问题,但是继承会导致一个脆弱的体系。而aop更能优雅的解决问题。我们将最核心的方法只需要实现自己的功能就行,其余的日志和事物,缓存都可以移到切面上来。这样最核心的业务功能就可以被轻易的复用了。
AOP
连接点 join point|即被拦截的点,可能是字段或方法调用触发了通知,spring只支持方法粒度的连接点,如果要更细粒度请使用aspect。
切点 pointcut 可以定义多个连接点,一般用通配符配置多个连接点。
通知 Advice 连接点被拦截后执行的操作,spring有5中通知。
before 前置通知 | 在目标方法调用前执行通知功能 |
after 后置通知 | 在目标方法调用后执行通知功能, |
after-returning 返回通知 | 在目标方法执行后,获得返回结果执行相关操作 |
after-throwing 异常通知 | 在目标方法报出异常时执行通知功能 |
around 环绕通知 | 包裹被通知的方法,可以自定义实现上述的所有通知的功能 |
切面 Aspect 由切点和通知组成
引入 introduction允许我们向现有的类添加新的方法和属性,在不改变核心类的基础上
织入 Weaving创建把切面应用到目标对象的代理对象的过程。spring的AOP底层实现依赖于jdk的动态代理和cglib,如果有目标类有接口则应用jdk代理,而至用cglib
具体实现
通过一个例子来使用aop,上课铃响,老师走进房间讲课,班长会叫同学们起立,叫老师好,然后老师开始讲课,讲课的过程相当于核心业务方法,其他的都可以移到切面上来。
核心业务类,其被拦截的方法叫做连接点
@Component
public class Lecture {
public String teacher(String teacherName) throws Exception{
System.out.println(teacherName +"老师:正在上课");
//if(1==1)
//throw new Exception("");
return "明天补课";
}
}
定义通知类
@Component
public class LectureAdvice {
public void beforeLecture(){
System.out.println("上课了,同学们起立");
}
public void afterLecture(){
System.out.println("下课,同学们请起立");
}
public void throwLecture(){
System.out.println("老师临时有事,这节课先该自习");
}
public void returnLecture(Object result){
System.out.println("这节课的重点"+result);
}
public void lecture(ProceedingJoinPoint jp) throws Throwable{
System.out.println("上课了,同学们起立");
jp.proceed();
System.out.println("下课,同学们请起立");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!-- 查找最新的schemaLocation 访问 http://www.springframework.org/schema/ -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:amq="http://activemq.apache.org/schema/core"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<!--aop通知类,或连接点必须是一个bean-->
<context:component-scan base-package="com.aop"/>
<aop:config>
<!--定义切面-->
<aop:aspect ref="lectureAdvice">
<!--定义切点-->
<aop:pointcut expression="execution(* com.aop.Lecture.teacher(..))" id="teacher" />
<!--通知-->
<aop:before method="beforeLecture" pointcut-ref="teacher"/>
<aop:after method="afterLecture" pointcut-ref="teacher"/>
<aop:after-returning method="returnLecture" pointcut-ref="teacher" returning="result"/>
<aop:after-throwing method="throwLecture" pointcut-ref="teacher"/>
</aop:aspect>
</aop:config>
</beans>
aop支持Aspect切点表达式
args() | 为连接点指定匹配参数 |
@args | 注解驱动功能同上 |
within() | 限制连接点匹配类型 |
@within | 同上注解驱动 |
execution() | 匹配连接点方法,支持通配符 |
execution() | 匹配连接点方法,支持通配符 |
更多详情看官方文档 https://docs.spring.io/spring/docs/2.5.x/reference/aop.html
表达式还支持&& ,|| ,!逻辑表达式 或者and ,or ,not
expression="execution(* com.aop.*.teacher(..)) and args(name)"`
基于注解驱动
//启用Aspect创建代理类
@Aspect
@Component
public class LectureAdvice {
@Pointcut("execution(* com.aop.Lecture.teacher(java.lang.String)) && "+"args(teacherName))" )
public void teacher(String teacherName){};
@Before("teacher(teacherName)")
public void beforeLecture(String teacherName){
System.out.println("上课了,同学们起立");
}
@After("teacher(teacherName)")
public void afterLecture(String teacherName){
System.out.println("下课,同学们请起立");
}
@AfterThrowing("teacher(teacherName)")
public void throwLecture(String teacherName){
System.out.println("老师临时有事,这节课先该自习");
}
@AfterReturning(pointcut="teacher(teacherName)",returning="result")
public void returnLecture(String teacherName,Object result){
System.out.println("这节课的重点"+result);
}
public void lecture(ProceedingJoinPoint jp) throws Throwable{
System.out.println("上课了,同学们起立");
jp.proceed();
System.out.println("下课,同学们请起立");
}
}
xml配置
<context:component-scan base-package="com.aop"/>
<!--启动自动代理功能 -->
<aop:aspectj-autoproxy />