Spring Boot 集成AOP

本文详细介绍了AOP的概念及核心术语,如切面、连接点等,并通过实例展示了如何在SpringBoot中使用AOP,包括配置依赖、定义切面类及通知等步骤。

在这里多谈一些关于AOP 方面的知识,如果你对AOP 方面的知识比较熟悉,可以直接略过这个段落,往下看。

一、AOP概述

AOP(面向切面编程) 概念:这种在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。

AOP 相关术语:

  • Aspect(切面):指横切性的关注点的抽象即为切面,它与类相似,只是两者的关注点不一样,类是对物体特征的抽象,而切面是对横切性关注点的抽象。是Pointcut和Advice的结合,切面可以由多个Poincut和Advice组成。
  • Joinpoint(连接点):被拦截的点(也就是需要被拦截的类的方法)。在spring中,这些点指的只能是方法,因为Spring只支持方法类型的拦截,实际上Joinpoint还可以拦截field或类构造器。
  • Pointcut(切点):对Jointpoint(连接点)进行拦截的定义,也就是在切面中定义的方法,并声明该方法拦截了Jointpoint(连接点)。
  • Advice(通知):切入点拦截到Jointpoint(连接点)之后要做的事情。通知分为前置通知(@Before)、后置通知(@AfterReturning)、异常通知(@AfterThrowing)、最终通知(@After)和环绕通知(@Around)。
  • Target(目标对象):代理的目标对象。
  • Weave(织入):指将aspects应用到target对象并使proxy对象创建的过程称为织入。

五种基本通知类型注解:

  • 前置通知(@Before):拦截目标方法,在目标方法执行之前开始执行。
  • 后置通知(After):在目标方法执行之后开始执行。也可以获取目标方法的返回值。
  • 返回通知(@AferRunning):在方法返回执行结果之后执行。
  • 异常通知(@AfterThrowing):在目标方法抛出异常后,执行增强。
  • 环绕通知(@Around):相当于整个代理模式过程,围绕方法执行。

二、在Spring Boot 中使用AOP

开发流程:

  1. 在pom.xml 中引入AOP 依赖。
  2. 写一个类,加上@Aspect 注解,封装横切关注点,配置对应的通知。
  3. 将这个类纳入到Spring 容器中。

过程实现:

在pom.xml 中添加AOP 依赖

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

Person 类

package com.jas.aop;

import org.springframework.stereotype.Component;

@Component
public class Person {
    public void sayHi(){
        System.out.println("Hello");
    }
}

Log 类

package com.jas.aop;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

/** 使用@Component 把这个类纳入到Spring 容器,@Aspect 注解表示这个类是一个切面类 */
@Component
@Aspect
public class Log {
    /** 定义一个前置通知*/
    /** 匹配com.jas.aop 包及其子包下的所有方法 */
    @Before("execution(* com.jas.aop..*.*(..))")
    public void log(){
        System.out.println("... before ...");
    }
}   

测试类(入口类)

package com.jas.springboot;

import com.jas.aop.Person;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication(scanBasePackages = "com.jas")
public class SpringbootApplication {

    public static void main(String[] args) throws Exception{

        ConfigurableApplicationContext context = SpringApplication.run(SpringbootApplication.class, args);

        Person person = context.getBean(Person.class);
        person.sayHi();

        System.out.println(person.getClass());
    }
}

启动入口类输出
这里写图片描述

三、Spring Boot AOP 两种动态代理方式

动态代理方式概述:

AOP 的源码中用到了两种动态代理来实现拦截切入功能:JDK 动态代理和CGLIB 动态代理。两种方式各有优劣。

JDK 动态代理是由java 内部的反射机制来实现的,CGLIB 动态代理底层则是借助asm 来实现的。总的来说,反射机制在生成类的过程中比较高效,而asm 在生成类之后的相关执行过程中比较高效(可以通过将asm 生成的类进行缓存,这样解决asm 生成类过程低效问题)。

还有一点必须注意:JDK 动态代理的应用前提,必须是目标类基于统一的接口。如果没有上述前提,JDK 动态代理不能应用。由此可以看出,JDK 动态代理有一定的局限性,CGLIB 这种第三方类库实现的动态代理应用更加广泛,且在效率上更有优势。。

关于JDK 动态代理知识,可参考博文:JDK 动态代理
但是从上面的输出来看使用的是基于CGLIB 的代理方式,因为JDK 的动态代理类必须是实现了接口的类。下面写一个接口类来测试一下。

动态代理方式演示:

在全局配置文件中配置代理方式,true 表示使用CGLIG,false 表示使用JDK 动态代理。
需要注意的是,当为false 时,如果代理类没有实现接口,则使用的也是基于CGLIB 的动态代理。

spring.aop.proxy-target-class=false

Animal 接口

package com.jas.aop;

public interface Animal {
    void yell();
}

Dog 类

package com.jas.aop;

import org.springframework.stereotype.Component;

@Component
public class Dog implements Animal{

    @Override
    public void yell() {
        System.out.println("wang wang ...");
    }
}

在入口类加上对应的代码

System.out.println(context.getBean(Animal.class).getClass());

输出
这里写图片描述

参考资料
http://blog.youkuaiyun.com/heyutao007/article/details/49738887

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值