Aop相关概念
AOP,Aspect Oriented Programming,面向切面编程,是对面向对象编程OOP的升华。OOP是纵向对一个 事物的抽象,一个对象包括静态的属性信息,包括动态的方法信息等。而AOP是横向的对不同事物的抽象,属 性与属性、方法与方法、对象与对象都可以组成一个切面,而用这种思维去设计编程的方式叫做面向切面编程。
目标对象(Target):被增强的方法所在的对象
代理对象(Proxy):对目标对象进行增强后产生的对接,客户端实际调用的对象
连接点(Joinpoint): 目标对象中可以被增强的方法
切入点(Pointcut): 目标对象中实际被增强的方法
通知(Advice):增强部分的代码逻辑
切面(Aspect):增强和切入点的组合
织入(Weaving):将通知和切入点组合动态组合的过程。
Aop 快速入门
准备目标对象类和增强类(通知类)
xml配置方式快速入门
1.pom导入aop包
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
2.配置目标类、增强类的bean
<!--目标类-->
<bean id="myTarget" class="spring.aop.target.MyTarget" />
<!--通知类-->
<bean id="myAdvice" class="spring.aop.advice.MyAdvice" />
3.配置切点表达式和织入
<aop:config>
<!--配置切点表达式, 指定被增强方法-->
<aop:pointcut id="myPointcut1" expression="execution(void spring.aop.target.MyTarget.targetMethod1())"/>
<aop:pointcut id="myPointcut2" expression="execution(void spring.aop.target.MyTarget.targetMethod2())"/>
<!--配置织入, 将通知和切入点动态组合-->
<aop:aspect ref="myAdvice">
<aop:before method="adviceBefore" pointcut-ref="myPointcut1"/>
<aop:after method="adviceAfter" pointcut-ref="myPointcut1"/>
<aop:before method="adviceBefore" pointcut-ref="myPointcut2"/>
</aop:aspect>
</aop:config>
测试效果
xml配置详解
切点表达式(配置连接点),语法如下:
execution([访问修饰符]返回值类型 包名.类名.方法名(参数))
- 访问修饰符可以省略不写;
- 返回值类型、某一级包名、类名、方法名 可以使用 * 表示任意;
- 包名与类名之间使用单点 . 表示该包下的类,使用双点 .. 表示该包及其子包下的类;
- 参数列表可以使用两个点 .. 表示任意参数
AspectJ五种通知类型:前置通知、后置通知、环绕通知、异常通知、最终通知
通知方法在被调用时,Spring提供的一些参数
advisor方式配置AOP,通知类通过实现Aop接口实现Aop通知配置,不再在xml中指定
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class MyAdvisor implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("before....");
}
}
<!--目标类-->
<bean id="myTarget" class="spring.aop.target.MyTarget" />
<!--通知类-->
<bean id="myAdvisor" class="spring.aop.advice.MyAdvisor" />
<aop:config>
<aop:pointcut id="myPointcut1" expression="execution(void spring.aop.target.MyTarget.targetMethod1())"/>
<aop:advisor advice-ref="myAdvisor" pointcut-ref="myPointcut1" />
</aop:config>
注解配置
@Aspost:将被标注的类声明为切面类
@Before:将方法标注为前置通知
@After: 将方法标注为最终通知
@AfterReturning: 将方法标注为后置通知
@AfterThrowing: 将方法标注为异常通知
@Around: 将方法标注为环绕通知
@PointCut: 声明一个公用的切入点表达式
@EnableAspectJAutoProxy: 开器AOP注解扫描
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class AnnoAdVice {
@Pointcut("execution(void spring.aop.target.MyTarget.targetMethod1())")
public void pointcut() {};
@Before("pointcut()")
public void before() {
System.out.println("前置通知....");
}
@AfterReturning("pointcut()")
public void afterReturning() {
System.out.println("后置通知....");
}
@Around("execution(void spring.aop.target.MyTarget.targetMethod2())")
public void Around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕前通知....");
proceedingJoinPoint.proceed();
System.out.println("环绕后通知");
}
@AfterThrowing(pointcut = "execution(void spring.aop.target.MyTarget.targetMethod3())", throwing = "e")
public void afterThrowing(Throwable e) {
System.out.println("异常类容:" + e);
System.out.println("异常通知....");
}
@After("execution(void spring.aop.target.MyTarget.*(..))")
public void After() {
System.out.println("最终通知....");
}
}