SpringAOP
什么是AOP
AOP(Aspect Orient Programming) ,直译过来就是 面向切面编程 . AOP 是一种编程思想 , 是面向对象编程 (OOP) 的一种补充. 面向对象编程将程序抽象成各个层次的对象, 而面向切面编程是将程序抽象成各个切面.
为什么需要AOP
想象下面的场景,开发中在多个模块间有某段重复的代码,我们通常是怎么处理的?显然,没有人会靠“复制粘贴”吧。在传统的面向过程编程中,我们也会将这段代码,抽象成一个方法,然后在需要的地方分别调用这个方法,这样当这段代码需要修改时,我们只需要改变这个方法就可以了。然而需求总是变化的,有一天,新增了一个需求,需要再多出做修改,我们需要再抽象出一个方法,然后再在需要的地方分别调用这个方法,又或者我们不需要这个方法了,我们还是得删除掉每一处调用该方法的地方。实际上涉及到多个地方具有相同的修改的问题我们都可以通过 AOP 来解决。
AOP术语
AOP 领域中的特性术语:
- 通知(Advice): AOP 框架中的增强处理。通知描述了切面何时执行以及如何执行增强处理。
- 连接点(join point): 连接点表示应用执行过程中能够插入切面的一个点,这个点可以是方法的调用、异常的抛出。在 Spring AOP 中,连接点总是方法的调用。
- 切点(PointCut): 可以插入增强处理的连接点。
- 切面(Aspect): 切面是通知和切点的结合。
- 引入(Introduction):引入允许我们向现有的类添加新的方法或者属性。
- 织入(Weaving): 将增强处理添加到目标对象中,并创建一个被增强的对象,这个过程就是织入。
通过注解声明 5 种通知类型
@Before(前置通知)
通知方法会在目标方法调用之前执行
@After(最终通知)
通知方法会在目标方法返回或异常后调用
@AfterReturning(返回通知)
通知方法会在目标方法返回后调用
@AfterThrowing(异常通知)
通知方法会在目标方法抛出异常后调用
@Around(环绕通知)
它将覆盖原有方法,但是允许你通过反射调用原有方法
简单切面Demo
/*** 切面* 切入点和通知的抽象* 定义 切入点 和通知* 切入点:定义要拦截哪些类的哪些方法* 通知:定义了拦截之后方法要做什么*/@Component // 将对象交给IOC容器进行实例化@Aspect // 声明当前的类是一个切面public class LogCut {/*** 切入点* 定义要拦截哪些类的哪些方法* 匹配规则,拦截什么方法* 定义切入点** @Pointcut("匹配规则") AOP切入点表达式* 1.执行所有的公共方法* execution(pulice *(..))* 2.执行任意的set方法* execution(* set*(..))* 3.设置指定包下的任意类的任意方法(指定包: com.yf.service)* execution(* com.yf.service.*.*(..))* 4.设置指定包及子包下的任意类的任意方法 (指定包: com.yf.service)* execution(* com.yf.service..*.*(..))* 表达式中的第一个** 代表的是方法的修饰范围(public,private,protected)* 如果取值是 *,则表示所有范围*/@Pointcut("execution(* com.yf.service..*.*(..))")public void cut() {}/*** 声明前置通知,并将通知运用到指定的切入点上* 目标类的方法执行前,执行该通知*/@Before(value = "cut()")public void before() {System.out.println("前置通知...");}/*** 声明返回通知,并将通知运用到指定的切入点上* 目标类的方法无异常执行后,执行该通知*/@AfterReturning(value = "cut()")public void afterReturn() {System.out.println("返回通知...");}/*** 声明异常通知,并将通知运用到指定的切入点上* 目标类出现异常后,执行该通知*/@AfterThrowing(value = "cut()")public void afterThrowing() {System.out.println("异常通知...");}/*** 声明异常通知,并将通知运用到指定的切入点上* 目标类执行方法后,有无异常都会执行*/@After(value = "cut()")public void after() {System.out.println("最终通知...");}/*** 声明环绕通知,并将通知应用到指定的切入点上* 目标类的方法执行前后,都可以通过环绕通知定义的响应的处理* 需要显示调用的方法,否则无法访问指定的方法 pjp.proceed()** @param pjp* @return*/@Around(value = "cut()")public Object around(ProceedingJoinPoint pjp) {System.out.println("环绕通知-前置通知...");Object object = null;try {//显示调用对应的方法object = pjp.proceed();System.out.println(pjp.getTarget());System.out.println("环绕通知-返回通知...");} catch (Throwable e) {e.printStackTrace();System.out.println("环绕通知-异常通知...");}System.out.println("环绕通知-最终通知...");return object;}}
@Servicepublic class UserService {public void test() {System.out.println("UserService test...");}}
public class App {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");UserService userService = (UserService) context.getBean("userService");userService.test();}}
<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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 开启自动化扫描 --><context:component-scan base-package="com.yf"/><!-- 配置AOP代理 --><aop:aspectj-autoproxy/></beans>
