Spring实现`aop`过程

AOP术语进行解释

1.连接点
类里面哪些方法可以被增强,这些方法称为连接点【如下面Student类中的study review note方法都可以被增强,所以都可以称为连接点】

public class Student {
    public void study(){
        System.out.println("海康学习aop。。。");
    }

    public void review(){
        System.out.println("海康aop。。。");
    }
    
    public void note(){
        System.out.println("做aop笔记。。。");
    }
}

2.切入点
实际被真实增强的方法,称为切入点【表示要增强那个方法,例如:增强study方法,那么study就是切入点】

3.通知(增强)
(1)实际增强的逻辑部分称为通知(增强)
(2)通知多种类型:

  1. 前置通知:就是在增强该方法前执行:使用@Before注解
  2. 后置通知:就是在增强该方法后执行:使用@AfterReturning注解,如果出现异常则不会该增强方法
  3. 环绕通知:就是在该方法前后都会执行:@Around注解,需要传入ProceedingJoinPoint类调用proceed()方法表示调用需要增强的方法
  4. 异常通知:就是该方法出现异常才会执行:@AfterThrowing注解
  5. 最终通知:就是该方法不管是否出现异常都会执行【相当于try中的finally@After注解

4.切面
把通知的行为应用到切入点过程中

例如:对`study`方法进行增强,
在`study`执行前先执行`paly方法`,
这一过程就可以理解为切面

AOP实现准备工作

1.Spring框架一般都是基于AspectJ实现AOP操作

AspectJ不是Spring组成部分,独立AOP框架,一般把AspectJSpring框架一起使用,进行AOP操作

2.基于AspectJ实现AOP操作有两种方式:
  1. 基于xml配置文件方式

  2. 基于注解方式实现方式(推荐)

  3. 使用AspectJ实现AOP操作第一步引入 jar

4.切入点表达式

(1)切入点表达式作用:知道对哪个类里面的哪个方法进行增强

(2)语法结构:execution([权限修饰符][返回类型][类全路径][方法名](参数列表))

返回类型可以不写

举例1:
对com.haikang.dao.UserDao类里面的`add`方法进行增强
	execution(* com.haikang.dao.UserDao.add(..))
	
	
举例2:
对com.haikang.dao.UserDao类里面所有方法进行增强
	execution(* com.haikang.dao.UserDao.*(..) )
	
	
举例3:
对com.haikang.dao包里面所有有类,类里面所有方法进行增强
	execution(* com.haikang.*.*(..))

AOP操作AspectJ

1.创建类,在类里面定义方法
2.创建增强类(编写增强逻辑代码)【需要在该类中 @Aspect表示是增强类】
3.进行通知的配置
1.在Spring配置文件中,需要开启两个命名空间contextaop
2.开启注解扫描
3.使用注解注入被增强类和增强类的对象
4.在增强类上面添加@Aspect【表示该类为代理类】
5.Spring配置文件中开启生成代理对象
4.配置不同类型通知
在增强类的里面,在作为通知方法上面添加通知类型注解,使用切入点表达式配置

步骤

1.创建类,在类里面定义方法,并且在IOC容器中注入该类对象

@Component
public class Student {
    public void study(){
        System.out.println("海康学习aop。。。");
    }

    public void review(){
        System.out.println("海康aop。。。");
    }

    public void note(){
        System.out.println("做aop笔记。。。");
    }
}

2.定义增强类,并且添加@Aspect注解表示是代理类,同时并在IOC容器中注入该类对象

@Component
@Aspect
public class StudentProxy {
    // 表示在执行Study方法先打一小王者荣耀,三个小时
    @Before("execution(* com.haikang.aop.jdk2.Student.study(..))")
    public void before(){
        System.out.println("执行前增强...");
        System.out.println("表示在执行Study方法先打一小王者荣耀,三个小时");
    }
}

3.创建bean.xml文件,引入context命名空间和aop命名空间,在配置文件中开启组件扫描和开启自动生成代理对象

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

        <!--开启组件扫描-->
        <context:component-scan base-package="com.haikang.aop.jdk2"/>
        <!--开启生成代理类-->
       <aop:aspectj-autoproxy />
</beans>

test

public class AopTest {
    @Test
    public void testAop(){
        ClassPathXmlApplicationContext context = 
                new ClassPathXmlApplicationContext("bean1.xml");
        Student student = context.getBean("student", Student.class);
        student.study();
    }
}

前置增强
表示是在执行被增强的方法执行,不管被增强的方法是否出现异常,都会执行

// 表示在执行Study方法先打一小王者荣耀,三个小时
    @Before("execution(* com.haikang.aop.jdk2.Student.study(..))")
    public void before(){
        System.out.println("执行前增强...");
        System.out.println("表示在执行Study方法先打一小王者荣耀,三个小时");
    }

在这里插入图片描述

环绕增强:

	public void review(){
        System.out.println("海康复习aop两分钟。。。呵呵,够了");
    }


// 表示在执行review方法前面都需要进行增强
    @Around("execution(* com.haikang.aop.jdk2.Student.review(..))")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("在复习`aop前打三个小时王者荣耀......`");
        joinPoint.proceed();//调用增强方法
        System.out.println("复习完`aop`刷五个小抖音......");
    }

在这里插入图片描述
注意是:环绕增强,被增强的方法如果出现了异常,只会执行前的增强,没有对被方法执行后进行增强
例如:手动模拟一个算数异常

// 表示在执行review方法前面都需要进行增强
    @Around("execution(* com.haikang.aop.jdk2.Student.review(..))")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("在复习`aop前打三个小时王者荣耀......`");
        joinPoint.proceed();//调用增强方法
        System.out.println("复习完`aop`刷五个小抖音......");
    }

public void review(){
        int i = 10/0;
        System.out.println("海康复习aop两分钟。。。呵呵,够了");
    }

在这里插入图片描述

后置增强
特点是:后置通知,当被增强的程序出现异常时,则该增强方法则不会被执行

	public void note(){
        System.out.println("海康做aop笔记是认真的。。。");
    }

    // 表示后置对`note`增强,表示在被`note`执行后进行增强
    @AfterReturning("execution(* com.haikang.aop.jdk2.Student.note(..))")
    public void afterReturning(){
        System.out.println("对做笔记方法进行后置增强,做笔记我是认真的,哈哈。。。");
    }

在这里插入图片描述

异常通知:表示只有被增强的方法出现异常时,才会执行该增强方法

	public void study(){
        int[] arr = {1,2};
        arr[5] = 10;//数组下标越界异常
        System.out.println("海康学习aop。。。");
    }

// 异常通知,表示只有出现了异常该方法才会被执行
    @AfterThrowing("execution(* com.haikang.aop.jdk2.Student.study(..))")
    public void throwing(){
        System.out.println("被增强的方法出现异常了。。。呵呵");
    }

在这里插入图片描述

最终异常:【不管是否出现异常都会执行方法】

    public void finallyMethod(){
        System.out.println("学习。。。");
    }

    // 最终通知,不管是否出现异常都会被执行的方法
    @After("execution(* com.haikang.aop.jdk2.Student.finallyMethod(..))")
    public void after(){
        System.out.println("最终还是要好好学习的,不管是否出现异常。。。");
    }

在这里插入图片描述

综合案例

1.定义被增强类

/**
 * @Author 海康
 * @Version 1.0
 */
@Component
public class Student {
    public void study(){
        int[] arr = {1,2};
        arr[5] = 10;//数组下标越界异常
        System.out.println("海康学习aop。。。");
    }

    public void review(){
        int i = 10/0;
        System.out.println("海康复习aop两分钟。。。呵呵,够了");
    }

    public void note(){
        System.out.println("海康做aop笔记是认真的。。。");
    }

    public void finallyMethod(){
        System.out.println("学习。。。");
    }
}

2.定义增强类

/**
 * @Author 海康
 * @Version 1.0
 */
@Component
@Aspect
public class StudentProxy {
    // 表示在执行Study方法先打一小王者荣耀,三个小时
//    @Before("execution(* com.haikang.aop.jdk2.Student.study(..))")
    public void before(){
        System.out.println("执行前增强...");
        System.out.println("表示在执行Study方法先打一小王者荣耀,三个小时");
    }

    // 表示在执行review方法前面都需要进行增强
    @Around("execution(* com.haikang.aop.jdk2.Student.review(..))")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("在复习`aop前打三个小时王者荣耀......`");
        joinPoint.proceed();//调用增强方法
        System.out.println("复习完`aop`刷五个小抖音......");
    }

    // 表示后置对`note`增强,表示在被`note`执行后进行增强
    @AfterReturning("execution(* com.haikang.aop.jdk2.Student.note(..))")
    public void afterReturning(){
        System.out.println("对做笔记方法进行后置增强,做笔记我是认真的,哈哈。。。");
    }

    // 异常通知,表示只有出现了异常该方法才会被执行
    @AfterThrowing("execution(* com.haikang.aop.jdk2.Student.study(..))")
    public void throwing(){
        System.out.println("被增强的方法出现异常了。。。呵呵");
    }

    // 最终通知,不管是否出现异常都会被执行的方法
    @After("execution(* com.haikang.aop.jdk2.Student.finallyMethod(..))")
    public void after(){
        System.out.println("最终还是要好好学习的,不管是否出现异常。。。");
    }
}

3.定义xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

        <!--开启组件扫描-->
        <context:component-scan base-package="com.haikang.aop.jdk2"/>
        <!--开启生成代理类-->
       <aop:aspectj-autoproxy />
</beans>

4.test类

public class AopTest {
    @Test
    public void testAop(){
        ClassPathXmlApplicationContext context =
                new ClassPathXmlApplicationContext("bean1.xml");
        Student student = context.getBean("student", Student.class);
//        student.study();
//        student.review();
//        student.note();
        student.finallyMethod();
    }
}

细节1:相同的切入点抽取

就是在对同一个切入点进行增强,可以将相同的切入点进行抽取

使用的@Pointcut注解

@Pointcut(value = "execution(* com.haikang.aopAnno.User.add(..))")
@Component
@Aspect
public class UserProxy {
    // 抽取相同的切入点
    @Pointcut(value = "execution(* com.haikang.aopAnno.User.add(..))")
    public void pointcutDemo(){
    }
    
    // 表示对User中的add方法在执行前进行增强
//    @Before("execution(* com.haikang.aopAnno.User.add(..))")
    @Before("pointcutDemo()")
    public void before(){
        System.out.println("before执行前方法前进行增强。。。");
    }

    // 表示对User中的add方法在执行后进行增强
//    @AfterReturning("execution(* com.haikang.aopAnno.User.add())")
    @Before("pointcutDemo()")
    public void afterReturning(){
        System.out.println("执行方法后进行增强");
    }

    // 表示对User中的add方法环绕增强
//    @Around("execution(* com.haikang.aopAnno.User.add())")
    @Before("pointcutDemo()")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        // 注意是:add方法出现异常时,只会执行add方法执行前的操作
        System.out.println("表示对add方法执行前进行增强");
        // 表示执行add方法
        joinPoint.proceed();
        System.out.println("表示对add方法执行后进行增强");
    }
    // 表示对User中的add方法最终增强
//    @After("execution(* com.haikang.aopAnno.User.add())")
    @Before("pointcutDemo()")
    public void after(){
        System.out.println("表示对add方法进行最终增强,不管是否出现异常都会执行");
    }

    // 异常通知【只能该方法出现异常才会被执行】
    @AfterThrowing("execution(* com.haikang.aopAnno.User.add())")
    public void afterThrowing(){
        System.out.println("add方法出现异常了。。。");
    }
}
细节2:有多个增强类对同一个方法进行增强,设置增强优先级[重点]

在增强类上面添加注解@Order(数字类型值),数字类型值越小优先级越高

就是在多个类对一个类中的一个方法都进行增强时,可以设置优先级

@Component
@Aspect
@Order(1)//数值越小优先级越高
public class PersonProxy {
    // 表示都对User中的add方法在执行前进行增强
    @Before("execution(* com.haikang.aopAnno.User.add(..))")
    public void before(){
        System.out.println("personProxy before执行前方法前进行增强。。。");
    }
}
@Component
@Aspect
@Order(2)//数值越小优先级越高
public class UserProxy {

    // 表示对User中的add方法在执行前进行增强
    @Before("execution(* com.haikang.aopAnno.User.add(..))")
    public void before(){
        System.out.println("before执行前方法前进行增强。。。");
    }
 }

表示PersonProxy增强的优先级高于UserProxy,所以PersonProxy增强方法先执行

细节3:完全使用注解开发

创建配置类,不需要创建xml配置文件

注意是:需要添加@EnableAdpectJAutoProxy(proxyTargetClass = true)注解,表示该类是一个aop代理类,就是Spring配置文件中开启生成代理对象作用

@Configuration
@ComponentScan(basePackages = "com.haikang.aopAnno")
@EnableAspectJAutoProxy(proxyTargetClass = true)// 默认是false,需要传入true
public class ConfigProxy {
}

test

@Test
    public void proxyAnno(){
        ApplicationContext context =
                new AnnotationConfigApplicationContext(ConfigProxy.class);
        // 注意:获取是被增强的类
        User user = context.getBean("user", User.class);
        user.add();
    }
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值