Spring AOP

AOP为Aspect Oriented Programming
面向切面编程,和动态代理的思想类似(?我觉得)
设计模式——动态代理

1. AOP相关术语介绍

1. Joinpoint(连接点)

连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点

2. Pointcut(切入点)

所谓切入点是指我们要对哪些Joinpoint进行拦截的定义

3. Advice(通知/增强)

所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)

4. Introduction(引介)

引介是一种特殊的通知在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field

5. Target(目标对象)

代理的目标对象

6. Weaving(织入)

是指把增强应用到目标对象来创建新的代理对象的过程

7. Proxy(代理)

一个类被AOP织入增强后,就产生一个结果代理类

8. Aspect(切面)

是切入点和通知的结合,以后咱们自己来编写和配置的

9. Advisor(通知器、顾问)

Aspect很相似

2 AspectJ

ApectJ采用的就是静态织入(编译期织入)的方式。使用AspectJ的acj编译器(类似javac)把aspect类编译成class字节码后,在java目标类编译时织入,即先编译aspect类再编译目标类
在这里插入图片描述

3 Spring AOP

Spring AOP是通过动态代理技术实现的
动态代理技术的实现方式有两种:基于接口的JDK动态代理和基于继承的CGLib动态代理。

3.1 Demo1 前置通知

除了spring IoC中列出的Spring基本依赖,还需要添加spring-aspects依赖

<!-- 基于Aspect的aop依赖 -->
<dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-aspects</artifactId>
     <version>${spring-version}</version>
 </dependency>

 <dependency>
     <groupId>aopalliance</groupId>
     <artifactId>aopalliance</artifactId>
     <version>1.0</version>
 </dependency>

3.1.1 定义切面

@Component // 交给IoC容器管理
@Aspect // 定义一个切面类
public class MyAspects {

    @Before(value = "execution(* com.cc.service.*.*(..))")
    public void log(){
        System.out.println("日志处理........");
    }
}
3.1.1.1 通知类型

@Before 前置通知

执行时机:在目标对象方法执行之前执行
应用场景:可以在方法开始之前进行校验

@After() 最终通知

执行时机:目标对象方法之后执行通知,有异常则不执行
应用场景:释放资源

@AfterReturning:后置通知

执行时机:目标对象方法之后执行通知,有异常则不执行
应用场景:修改方法的返回值

@AfterThrowing()异常抛出通知

执行时机:在抛出异常后执行
应用场景:包装异常

@Around:环绕通知

执行时机:执行目标对象方法之前和之后都会执行
应用场景:事物、统计代码执行时间等

3.1.1.2 切入点表达式execution

固定格式:execution([修饰符] 返回值 包名.类名.方法名(参数))
修饰符:public等,可省略
返回值:可采用通配符**
包名:多级包名使用 .分割,省略中间的包名可以使用..
类名:可以使用*,也可以写成*ServiceImpl
方法名:可以使用*,也可以写成add*
形参:可以用*代替,多个参数可以写成..

3.1.2 @EnableAspectJAutoProxy

开启AOP

@Configuration
@ComponentScan(basePackages = "com.cc")
@Import(ProertiesConfig.class)
@EnableAspectJAutoProxy
public class SpringConfiguration {
    //spring容器初始化时,会调用配置类的无参构造函数
    public SpringConfiguration(){
        System.out.println("容器启动初始化");
    }
}

3.1.3 测试

测试类和业务类都和spring IoC中SpringJunitTest的配置一样
输出结果为:

容器启动初始化
日志处理........
userDao: saveUser:id为100, name为:cc

3.2 Demo2 环绕通知

@Around(value = "execution(* com.cc.service.*.*())")
public Object logTime(ProceedingJoinPoint joinPoint){
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
    String sign = null;
    Object rtValue = null;
    try {
        //获取方法所需的参数
        Object[] args = joinPoint.getArgs();
        // 获取方法签名
        Signature signture =joinPoint.getSignature();
        sign = signture.getName();
        // 前置通知:打印方法开始时间
        System.out.println(sign +" 开始时间:"+sdf.format(new Date()));
        Arrays.stream(args).forEach(System.out::println);
        // 执行目标方法
        rtValue = joinPoint.proceed(args);
    }catch (Throwable t){
        t.printStackTrace();//异常通知:可以回滚事物等
    }finally {
        // 可以用来 释放资源
    }
    // 后置通知:打印结束时间
    System.out.println(rtValue +" "+ sign+" 结束时间:"+sdf.format(new Date()));
    return rtValue;
}

demo1和demo2结合使用,输出为

容器启动初始化
saveUser 开始时间:2018-12-19 10:54:49 518
日志处理........
userDao: saveUser:id为100, name为:cc
null saveUser 结束时间:2018-12-19 10:54:49 520

3.3 Demo3

@Aspect
@Component
public class MyAspects2 {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
    String sign;//目标对象的方法

    @Before(value = "fun()")
    public void startLog(JoinPoint joinPoint){
        sign = joinPoint.getSignature().getName();
        System.out.println(sign+" 开始:"+sdf.format(new Date()));
    }

    @Before(value = "fun()")
    public void validate(JoinPoint joinPoint){
        //目标对象的形参
        Object[] args = joinPoint.getArgs();
        Arrays.stream(args).forEach(x->System.out.println("参数为:"+x));
        System.out.println("参数校验.....");
    }

    @After(value = "fun()")
    public void endLog(JoinPoint joinPoint){
        sign = joinPoint.getSignature().getName();
        System.out.println(sign+" 结束:"+sdf.format(new Date()));
        System.out.println("释放资源.....");
    }

    @AfterReturning(value = "fun()",returning = "result")
    public void endDeal(JoinPoint joinPoint,Object result){
        System.out.println("执行结果为:"+result);
        System.out.println("结果参数处理.....");
    }

    @AfterThrowing(value = "fun()",throwing = "ex")
    public void throwExpection(JoinPoint joinPoint,Exception ex){
        ex.printStackTrace();
        System.out.println("异常处理.....");
    }

    @Pointcut(value = "execution(* *..service.*.*(..))")
    public void fun(){

    }
}

输出结果

容器启动初始化
saveUser 开始:2018-12-19 15:08:07 209
参数为:com.cc.pojo.User@7e057f43
参数校验.....
userDao: saveUser:id为100, name为:SpringJunit
saveUser 结束:2018-12-19 15:08:07 210
释放资源.....
执行结果为:null
结果参数处理.....
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值