8.Spring AOP

一、了解Spring AOP

1.什么是Spring AOP

面向切面编程,是一种思想,它是对某一类事情进行集中处理。

举个例子:比如用户登录权限的校验。

不用AOP:需要判断用户登录的界面,都需要各自实现或调用用户验证的方法。

用AOP:只需要配置一处方法,就可以供所有需要判定用户登录页面中的方法全部实现登录验证,不需要繁琐的每个方法写相同的登录验证。

再贴切的例子就是:五个室友点了 五份相同的外卖,外卖同一时间放在同一个地点。

不用AOP:五个室友同时过去,一个一个拿外卖,耗费资源和时间,

用AOP:派一个代拿,直接把五个外卖全部拿回来。节省资源和时间。

小结:AOP 是⼀种思想,⽽ Spring AOP 是⼀个框架,提供了⼀种对 AOP 思想的实现,它们的关系和IoC 与 DI 类似

二、了解 Spring AOP的构成

2.1 切面(Aspect)

a.切⾯(Aspect)由切点(Pointcut)和通知(Advice)组成,它既包含了横切逻辑的定义,也包括了连接点的定义。

b.切⾯是包含了:通知、切点和切⾯的类,相当于 AOP 实现的某个功能的集合

2.2 连接点(Join Point)

应用执行过程中,能够插入切面的一个点,这个点在方法调用时,抛出异常时,甚至修改字段时,切面代码可以利用这些点插入到应用的正常流程中,并添加新的行为。

连接点相当于需要被增强的某个 AOP 功能的所有⽅法。

2.3 切点(Pointcut)

提供一组规则来匹配 Join Point,给满足Join Point 添加 Advice

切点相当于保存了众多连接点的一个集合。

如果把切点看成一个表,连接点就是表中一条一条的数据。

2.4 通知(Advice)

切⾯也是有⽬标的 ——它必须完成的⼯作。在 AOP 术语中,切⾯的⼯作被称之为通知。

通知:定义了切面是什么,何时使用,描述切面要完成的工作,还解决何时执行这个工作的问题。

Spring切面类中,可以在方法上使用以下注释,会设置方法为通知方法,在满足条件后通知本方法进行调用

前置通知使用@Before:通知方法会在目标方法调用之间执行

后置方法使用@After:通知方法会在目标方法返回或者抛出异常后调用

返回之后通知使⽤ @AfterReturning:通知⽅法会在⽬标⽅法返回后调⽤。

抛异常后通知使⽤ @AfterThrowing:通知⽅法会在⽬标⽅法抛出异常后调⽤。

环绕通知使⽤ @Around:通知包裹了被通知的⽅法,在被通知的⽅法通知之前和调⽤之后执⾏⾃定义的⾏为

AOP整个组成部分的概念如下图所示,以多个页面需要访问用户登录权限为例:

三、Spring AOP的实现

Spring AOP 的实现步骤:1.添加Spring AOP框架支持 2.定义切面与切点 3.定义通知

3.1 添加 AOP框架支持

在pom.xml中添加如下配置:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

3.2 定义切面与切点

切点指的是具体要处理的某⼀类问题,⽐如⽤户登录权限验证就是⼀个具体的问题,记录所有⽅法的执⾏⽇志就是⼀个具体的问题,切点定义的是某⼀类问题。

Spring AOP 切点定义如下: 在切点中,要定义 拦截的规则。具体实现如下:

@Aspect//表明此类为一个切点
@Component
public class UserAspect {


        //定义切点,
        //这里使用AspectJ 表达式 语法
        @Pointcut("execution(* com.example.springdemo5.AOPTest.*(..))")
        public  void pointcut(){}

    }

3.3定义通知并执行

//前置通知
@Before("pointcut()")
public void doBefore(){
    System.out.println("执行了前置通知");

}
//后置通知
@After("pointcut()")
public void  doAfter(){
    System.out.println("执行了后置通知");
}
//环绕通知
@Around("pointcut()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable{
    System.out.println("环绕通知执行之前");
    // 执行目标方法
    Object result = joinPoint.proceed();
    System.out.println("环绕通知执行之后");
    return result;
}

3.4 定义相关通知

通知定义的是被拦截的⽅法具体要执⾏的业务,⽐如⽤户登录权限验证⽅法就是具体要执⾏的业务。

Spring AOP 中,可以在⽅法上使⽤以下注解,会设置⽅法为通知⽅法,在满⾜条件后会通知本⽅法进⾏调⽤:

前置通知使⽤@Before:通知⽅法会在⽬标⽅法调⽤之前执⾏。

后置通知使⽤@After:通知⽅法会在⽬标⽅法返回或者抛出异常后调⽤。

返回之后通知使⽤@AfterReturning:通知⽅法会在⽬标⽅法返回后调⽤。

抛异常后通知使⽤@AfterThrowing:通知⽅法会在⽬标⽅法抛出异常后调⽤。

环绕通知使⽤@Around:通知包裹了被通知的⽅法,在被通知的⽅法通知之前和调⽤之后执⾏⾃定义的⾏为

@Aspect//定义切面
@Component
public class UserAspect {
    //切点
    @Pointcut("execution(* com.example.springdemo5.controller.UserController.*(..))")
    public  void pointcut(){}

    //前置通知
    @Before("pointcut()")
    public void doBefore(){
        System.out.println("执行了前置通知");

    }
    //后置通知
    @After("pointcut()")
    public void  doAfter(){
        System.out.println("执行了后置通知");
    }
    //return 之前通知
    @AfterReturning("pointcut()")
    public void doAfterReturning(){
        System.out.println("执行了 AfterReturning方法");
    }
    //抛出异常之前通知
    @AfterThrowing("pointcut()")
    public void doAfterThrowing(){
        System.out.println("执行了 AfterThrowing 方法");
    }
    //环绕通知
    @Around("pointcut()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable{
        System.out.println("环绕通知执行之前");
        // 执行目标方法
        Object result = joinPoint.proceed();
        System.out.println("环绕通知执行之后");
        return result;
    }
}

四、AspectJ ⽀持三种通配符语法

*:匹配任意字符,只匹配⼀个元素(包,类,或⽅法,⽅法参数)

.. :匹配任意字符,可以匹配多个元素 ,在表示类时,必须和 * 联合使⽤。

+ :表示按照类型匹配指定类的所有类,必须跟在类名后⾯,如 com.cad.Car+ ,表示继承该类的所有⼦类包括本身

切点表达式由切点函数组成,其中 execution() 是最常⽤的切点函数,⽤来匹配⽅法,

语法为: 定义切⾯和切点切点表达式说明execution()

4.1修饰符的具体含义

修饰符和异常可以省略,具体含义如下:

修饰符,一般省略: public 公共方法 * 任意

返回值,不能省略: void 返回没有值,String 返回字符串, * 任意

包:

com.demo

固定包

com.demo.*.service

demo包下的子包任意

com.demo

demo包下的所有子包(包括自己)

com.demo.*.service..

demo包下面任意子包,固定目录service,

service目录任意包

类:

UserServiceImpl

指定类

*Impl

以lmpl结尾

User*

以User开头

*

任意

方法名,不可忽略:

addUser

固定方法

add*

以add开头

*Do

以Do结尾

*

任意

参数:

()

无参

(int)

一个整型

(int,int)

两个

(..)

参数任意

throws,可省略

4.2 表达式示例

execution(* com.cad.demo.User.*(..)) :匹配 User 类⾥的所有⽅法。

execution(* com.cad.demo.User+.*(..)) :匹配该类的⼦类包括该类的所有⽅法。

execution(* com.cad.*.*(..)) :匹配 com.cad 包下的所有类的所有⽅法。

execution(* com.cad..*.*(..)) :匹配 com.cad 包下、⼦孙包下所有类的所有⽅法。

execution(* addUser(String, int)) :匹配 addUser ⽅法,且第⼀个参数类型是 String,第⼆个参数类型是 int。

  • 18
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
java.lang.NullPointerException: null at com.datech.web.controller.system.TbappController.remove(TbappController.java:667) at com.datech.web.controller.system.TbappController$$FastClassBySpringCGLIB$$ea1c3ba.invoke(<generated>) at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:62) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:55) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) at org.apache.shiro.spring.security.interceptor.AopAllianceAnnotationsAuthorizingMethodInterceptor$1.proceed(AopAllianceAnnotationsAuthorizingMethodInterceptor.java:82) at org.apache.shiro.authz.aop.AuthorizingMethodInterceptor.invoke(AuthorizingMethodInterceptor.java:39) at org.apache.shiro.spring.security.interceptor.AopAllianceAnnotationsAuthorizingMethodInterceptor.invoke(AopAllianceAnnotationsAuthorizingMethodInterceptor.java:115) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691) at com.datech.web.controller.system.TbappController$$EnhancerBySpringCGLIB$$b3b02033.remove(<generated>) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
07-14
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值