spring的AOP配置之@注解方式

29 篇文章 0 订阅

AOP配置(注解)

spring的AOP概念在spring的AOP配置之XML方式这骗博客中详细介绍了,这篇博客就直接开始介绍AOP配置需要那些注解

AOP注解详解

@Aspect 标志为一个切面类

⚫ 名称:@Aspect
⚫ 类型:注解
⚫ 位置:类定义上方
⚫ 作用:设置当前类为切面类
⚫ 格式:

@Aspect
public class AopAdvice {
}

⚫ 说明:一个beans标签中可以配置多个aop:config标签
在这里插入图片描述

@Pointcut 使用当前方法名作为切入点引用名称

⚫ 名称:@Pointcut
⚫ 类型:注解
⚫ 位置:方法定义上方
⚫ 作用:使用当前方法名作为切入点引用名称
⚫ 格式:

@Pointcut("execution(* *(..))")
public void pt() {
}

⚫ 说明:被修饰的方法忽略其业务功能,格式设定为无参无返回值的方法,方法体内空实现(非抽象)
在这里插入图片描述

@Before 标注当前方法作为前置通知

⚫ 名称:@Before
⚫ 类型:注解
⚫ 位置:方法定义上方
⚫ 作用:标注当前方法作为前置通知
⚫ 格式:

@Before("pt()")
public void before(){
}

⚫ 特殊参数:
◆ 无
在这里插入图片描述

@After 标注当前方法作为后置通知

名称:@After
⚫ 类型:注解
⚫ 位置:方法定义上方
⚫ 作用:标注当前方法作为后置通知
⚫ 格式:

@After("pt()")
public void after(){
}

⚫ 特殊参数:
◆ 无
在这里插入图片描述

@AfterReturning 标注当前方法执行成功后作为返回后通知

⚫ 名称:@AfterReturning
⚫ 类型:注解
⚫ 位置:方法定义上方
⚫ 作用:标注当前方法作为返回后通知
⚫ 格式:

@AfterReturning(value="pt()",returning = "ret")
public void afterReturning(Object ret) {
}

⚫ 特殊参数:
◆ returning :设定使用通知方法参数接收返回值的变量名

在这里插入图片描述

@AfterThrowing 标注当前方法作为异常后通知

⚫ 名称:@AfterThrowing
⚫ 类型:注解
⚫ 位置:方法定义上方
⚫ 作用:标注当前方法作为异常后通知
⚫ 格式:

@AfterThrowing(value="pt()",throwing = "t")
public void afterThrowing(Throwable t){
}

⚫ 特殊参数:
◆ throwing :设定使用通知方法参数接收原始方法中抛出的异常对象名

在这里插入图片描述

@Around 标注当前方法作为环绕通知

AOP注解详解
⚫ 名称:@Around
⚫ 类型:注解
⚫ 位置:方法定义上方
⚫ 作用:标注当前方法作为环绕通知
⚫ 格式:

    @Around("pt()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {

        Object ret = null;
        try {
            //配置前置通知
            ret = pjp.proceed();
            //配置执行成功通知
        } catch (Exception e) {
            //配置异常通知
            e.printStackTrace();
        } finally {
            //配置后置通知
        }
        return ret;
    }

⚫ 特殊参数:
◆ 无
在这里插入图片描述

@EnableAspectJAutoProxy AOP注解驱动

⚫ 名称:@EnableAspectJAutoProxy
⚫ 类型:注解
⚫ 位置:Spring注解配置类定义上方
⚫ 作用:设置当前类开启AOP注解驱动的支持,加载AOP注解
⚫ 格式:

//标志为配置类
@Configuration
//扫描那些路径下的包的类的spring注解
@ComponentScan("com.fs")
//开启AOP注解支持   替换   xml <aop:aspectj-autoproxy/>
@EnableAspectJAutoProxy
public class SpringConfig {
}

注解开发AOP注意事项

  1. 切入点最终体现为一个方法,无参无返回值,无实际方法体内容,但不能是抽象方法
  2. 引用切入点时必须使用方法调用名称,方法后面的()不能省略
  3. 切面类中定义的切入点只能在当前类中使用,如果想引用其他类中定义的切入点使用“类名.方法名()”引用
  4. 可以在通知类型注解后添加参数,实现XML配置中的属性,例如after-returning后的returning属性

在这里插入图片描述

AOP注解代码实现

图解AOP从xml转变为XML

在这里插入图片描述

POM

 <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.9.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.1.9.RELEASE</version>
        </dependency>
        <!--        aop切面包-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.5</version>
        </dependency>
        <!--        junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

SpringConfig配置类

package com.fs.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
//标志为配置类
@Configuration
//扫描那些路径下的包的类的spring注解
@ComponentScan("com.fs")
//开启AOP注解支持   替换   xml <aop:aspectj-autoproxy/>
@EnableAspectJAutoProxy
public class SpringConfig {
}

模拟三层架构的server,动态代理service接口的实现类

AopService接口
package com.fs.service;

public interface AopService {
    void findAll();
    int add(String str);
    void findById();
    void del();
    void update();
}

AopServiceImpl实现类
package com.fs.service.impl;

import com.fs.service.AopService;
import org.springframework.stereotype.Service;

//把业务类交给spring管理
@Service
public class AopServiceImpl implements AopService {
    @Override
    public void findAll() {
        System.out.println("业务层执行了findAll~~~");
    }

    /**
     *
     * @param str 传递一个参数,在切面类的通知方法中去接收查看
     * @return 返回一个值,在切面类的通知方法中去接收
     */
    @Override
    public int add(String str) {
        System.out.println("业务层执行了add~~~");
        //返回一个值,在切面类的通知方法中去接收
        return 54088;
    }
    @Override
    public void findById() {
        System.out.println("业务层执行了findById~~~");
        //制造异常来是异常通知生效
//        int i = 1/0;
    }
    @Override
    public void del() {
        System.out.println("业务层执行了del~~~");
    }

    @Override
    public void update() {
        System.out.println("业务层执行了update~~~");
    }
}

@Aspect 切面类

package com.fs.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/*
这个类是AOP的切面类
    里面编辑一些织入的方法
 */

//将这个类交给spring管理
@Component
//标志这个类为切面类
@Aspect
public class AOPDemoAdvice {

    //配置切入点,切入这个com.fs.service.AopService.find*(..)方法,因为ioc中存入了实现类,执行切方法的时候会从ioc中获取实现类
    @Pointcut("execution(* com.fs.service.AopService.find*(..))")
    public void pt(){}


//    @Before("pt()")
    public void proxyAOPBefore(JoinPoint jp){
        Object[] args = jp.getArgs();
        System.out.println("给切入点(方法)添加了前置通知~~~"+".."+ Arrays.toString(args)+"...");
    }


//    @After("pt()")
    public void proxyAOPAfter(){
        /*
        这个后置通知是无论代码是否出现异常,都会执行这个通知
         */
        System.out.println("给切入点(方法)添加了后置通知~~~");
    }

    //测试获取切入点的的参数和返回值
    //这个注解,可以获取方法正常执行后,获取方法的返回值 returning是返回值的名字,自己定义名字
//    @AfterReturning(value = "execution(* com.fs.service.impl.*.add(..))",returning = "num")
    //直接切入点位接口的方法也行.因为我们在ioc中有存入了实现类的
    @AfterReturning(value = "execution(* com.fs.service.AopService.add(..))",returning = "num")
    public void proxyAOPAfterReturning(JoinPoint jp,Object num) {
        /*
        BeforeReturning
            表示的是代码运行成功无任何异常,会执行的通知
         */
        //获取传递的参数
        Object[] args = jp.getArgs();
        System.out.println("给切入点(方法)添加了代码运行成功后的后置通知~~~"+".切入点传递的参数."+Arrays.toString(args)+".切入点返回的值."+num);
    }

//    @AfterThrowing("pt()")
    public void proxyAOPAfterThrowing() {

        System.out.println("给切入点(方法)添加了代码运行异常后的后置通知~~~");
    }

    /*
    环绕通知
        环绕通知可以将上面的通知方法全部实现
        ProceedingJoinPoint
            这类就代表切入点,可以给这个切入点执行配置通知
     */
    @Around("pt()")
//    @Around("execution(* com.fs.service.impl.*.find*(..))")也可以在后面直接写切入点的表达式
    public Object proxyAOPAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {

        Object proceed = null;
        try {
            //proceedingJoinPoint切入点执行前配置前置通知
            System.out.println("环绕通知的前置通知执行的代码");
            //切入点(被动态代理的方法)执行
            proceed = proceedingJoinPoint.proceed();
            //proceedingJoinPoint切入点执行成功无报错后配置前置通知
            System.out.println("环绕通知的-成功运行-后执行的代码");
        } catch (Throwable throwable) {
            //proceedingJoinPoint切入点执行前配置异常通知
            System.out.println("环绕通知的切入点执行-异常后-执行的代码");
            throwable.printStackTrace();
        } finally {
            //proceedingJoinPoint切入点执行前后通知,就是代码无论是异常,还成功运行,都会执行的增强代码
            System.out.println("环绕通知的后置通知执行的代码");
        }
        return proceed;
    }
}

测试类

package com.fs.aop;

import com.fs.config.SpringConfig;
import com.fs.service.AopService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import static org.junit.Assert.*;
//开启junit的执行器
@RunWith(SpringJUnit4ClassRunner.class)
//加载spring的配置类
@ContextConfiguration(classes = SpringConfig.class)
public class AopDemoTest {

    //从ioc中获取
    @Autowired
    private AopService aopService;

    @Test
    public void method() {
        //调用方法
        aopService.findById();

//        int add = aopService.add("牛批");
    }


}
aopService.findById();执行结果

在这里插入图片描述

aopService.add(“牛批”);执行结果

在这里插入图片描述

AOP注解开发通知执行顺序控制(了解)

⚫ AOP使用XML配置情况下,通知的执行顺序由配置顺序决定,在注解情况下由于不存在配置顺序的概念
的概念,参照通知所配置的方法名字符串对应的编码值顺序,可以简单理解为字母排序
◆ 同一个通知类中,相同通知类型以方法名排序为准
◆ 不同通知类中,以类名排序为准
◆ 使用@Order注解通过变更bean的加载顺序改变通知的加载顺序
⚫ 企业开发经验
◆ 通知方法名由3部分组成,分别是前缀、顺序编码、功能描述
◆ 前缀为固定字符串,例如baidu、itheima等,无实际意义
◆ 顺序编码为6位以内的整数,通常3位即可,不足位补0
◆ 功能描述为该方法对应的实际通知功能,例如exception、strLenCheck
◆ 控制通知执行顺序使用顺序编码控制,使用时做一定空间预留
◼ 003使用,006使用,预留001、002、004、005、007、008
◼ 使用时从中段开始使用,方便后期做前置追加或后置追加
◼ 最终顺序以运行顺序为准,以测试结果为准,不以设定规则为准

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值