Spring-Aop的使用

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、Aoc的相关术语
  • 二、aop使用步骤
  • 三、aop中获取切面的一些信息
  • 三、aop中设置切面的优先级


前言

Spring两大核心之一aop,也就是用切面管理类

一、Aoc的相关术语

一;横切关注点;

  • 从每个方法中抽取出来的非核心业务,在同一个项目中,我们可以使用多个横切关注点对方法进行增强
  • (也就是需要添加额外操作的位置)

二;通知

  • 每一个横切关注点上要做的是需要重写一个方法来实现,这个方法就叫做通知(类似打印日志功能,打印前的信息就叫通知)
  • 前置通知;在被代理的目标方法前执行@Before
  • 后置通知;在被代理的目标方法成功结束后执行@After
  • 异常通知;在被代理的目标方法异常结束后执行@AfterRunning
  • 后置通知;在被代理的目标方法最终结束后执行@AfterThrowing
  • 环绕通知;包括上面四种方法,永try-catch-finaly包围的结构、

三;切面;封装通知方法的类(也就是管理通知方法的类)
*
四;目标;被代理的对象

五;代理;向目标对象应用通知后创建的代理对象

六;连接点,需要将通知接入的点(逻辑概念)

七;切入点;定位连接点的方式(也就是最后会将通知插入到核心代码的位置)

总结;找到目标的横切关注点,写出需要的通知, 交给切面管理,然后aop会自动创建代理对象(动态代理)之后根据切入点加载到方法中去

二、aop使用步骤

首先我们要知道,我们使用aop需要两个东西,一个是需要代理的类,也就是目标类,一个是如何代理的类,也就是切面类,这两个类都需要我们创建

首先创建我们需要代理的类

注意添加@Component注解加载进ioc中

@Component
public class calculatorImp implements calcolator{

    public int add(int i , int j){
        int sum = i + j;
        return sum;
    }
}

然后我们创建切面类,也就是calculatorImp的切面类

注意要添加@Aspect注解,让ioc知道这是一个切面

@Component
@Aspect
public class LoggerAspect {
    public void BeforeMessage(JoinPoint joinPoint){
        Signature signature = joinPoint.getSignature();//获取对应方法的签名信息
        Object[] args = joinPoint.getArgs();//获取对应方法的参数信息
        System.out.println("前置通知LoggerAspect");
        System.out.println("方法名为:"+signature);
        System.out.println("参数名为:"+ Arrays.toString(args));

    }
}

这时候我们如何让ioc知道,LoggerAspect 是calculatorImp 的切面呢----添加@Before注解

将上面的LoggerAspect 添加@Before注解

@Component
@Aspect
public class LoggerAspect {
    /*
    * 切入点表达式;设置在标识通知的注解value属性中
    * execution(public int com.ligong.spring.pojo.calculatorImp.add(..)
    * 表示返回值为int的com.ligong.spring.pojo包下的calculatorImp类中的任意参数的add方法(..表示任意参数列表)
    */

    //在切面中,需要通过指定的注解将方法标识为通知方法
    @Before("execution(* com.ligong.spring.pojo.calculatorImp.add(..))")
    public void BeforeMessage(JoinPoint joinPoint){
        Signature signature = joinPoint.getSignature();//获取对应方法的签名信息
        Object[] args = joinPoint.getArgs();//获取对应方法的参数信息
        System.out.println("前置通知LoggerAspect");
        System.out.println("方法名为:"+signature);
        System.out.println("参数名为:"+ Arrays.toString(args));

    }
}

最后将这两个类加载进ioc容器中

加载ioc容器的代码

aop注意事项;
切面类和目标类都要交给ioc管理
切面类必须通过@Aspect注解标识为一个切面
在Spring配置文件中设置aop:aspectj-autoproxy/开机基于注解的aop
扫描文件,也就是说,aop的基础是ioc

    <context:component-scan base-package="com.ligong.spring.pojo"></context:component-scan>

    <!--开启基于注解的aop;如果想实现通过注解管理切面这个标签必须配置-->
    <aop:aspectj-autoproxy/>

三、aop中获取切面的一些信息

这里我们学习一些获取切面的一些信息,比如切面中的通知的方法名,获取通知的参数等等
如果想要获取参数的信息,需要在通知方法的参数位置,设置joninpoint类型的参数,就可以获取连接点所对应方法的信息
例如;
在切面LoggerAspect的BeforeMessage中设置joninpoint

Spring-Aop的使用_第1张图片

三、aop中设置切面的优先级

问题引入;

现在有一种情况,例如我们有两个切面,我们需要切面A先知性之后切面B再执行,该怎么实现呢?
----遇到这种考虑切面优先级的情况,我们需要使用order注解,设置切面优先级(默认order中的参数越小,优先级越高)
例子见MetondAspect中的oder标签

创建两个切面
切面A;

@Component
@Aspect
public class LoggerAspect {
    @Before("execution(public int com.ligong.spring.pojo.calculatorImp.add(..))")
    public void BeforeMessage(JoinPoint joinPoint){
        Signature signature = joinPoint.getSignature();//获取对应方法的签名信息
        Object[] args = joinPoint.getArgs();//获取对应方法的参数信息
        System.out.println("前置通知LoggerAspect");
        System.out.println("方法名为:"+signature);
        System.out.println("参数名为:"+ Arrays.toString(args));

    }
}

切面B;

Order注解设置切面优先级,数字越小优先级越高

@Component
@Aspect
@Order(1)//Order注解设置切面优先级,数字越小优先级越高
public class MetondAspect {
    @Before("execution(public int com.ligong.spring.pojo.calculatorImp.add(..))")
    public void BeforeMessage() {
        System.out.println("前置通知MetondAspect");
    }
}

测试

public class testAspect {
    @Test
    public void test1(){
        //因为aop也是给ioc管理的,所以一样的先获取ioc
        ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("Aop-annotation.xml");


        //注意这里不能直接获取calculatorImp.class,因为aop是通过动态代理生成了calculatorImp.class的代理类
        //如果在这里还是直接获取calculatorImp.class就会空指针;NoSuchBeanDefinitionException
        //calculatorImp bean1 = ioc.getBean(calculatorImp.class);报错

        //那么因为我们知道jdbc的动态代理是必须实现和被代理类同样的接口的,我们就可以通过接口来获取到该bean
        calcolator bean = ioc.getBean(calcolator.class);
        bean.add(1,1);
    }
}

测试结果

前置通知MetondAspect
前置通知LoggerAspect
方法名为:int com.ligong.spring.pojo.calcolator.add(int,int)
参数名为:[1, 1]

你可能感兴趣的:(spring,java,后端)