读完阿里 P8 大佬 整理的这份Spring AOP 文档, 献上我的膝盖

222 阅读4分钟

Hello,今天给各位童鞋们分享Spring IOC,赶紧拿出小本子记下来吧!

image.png

1. 初识AOP

1.1 什么是AOP

AOP 为 Aspect Oriented Programming 的缩写,意思为面向切面编程。

AOP 是 OOP(面向对象编程) 的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

优点

在程序运行期间,在不修改源码的情况下对方法进行功能增强

逻辑清晰,开发核心业务的时候,不必关注增强业务的代码

减少重复代码,提高开发效率,便于后期维护

1.2 AOP底层实现

实际上,AOP 的底层是通过 Spring 提供的动态代理技术实现的。在运行期间,Spring通过动态代理技术动态的生成代理对象,代理对象方法执行时进行增强功能的介入,再去调用目标对象的方法,从而完成功能的增强。

常用的动态代理技术

我们可以将业务代码和事务代码进行拆分,通过动态代理的方式,对业务方法进行事务的增强。这样就不会对业务层产生影响,解决了耦合性的问题。

JDK动态代理方式

基于接口的动态代理技术·:利用拦截器(必须实现invocationHandler)加上反射机制生成一个代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理,从而实现方法增强。

CGLIB动态代理方式

基于父类的动态代理技术:动态生成一个要代理的子类,子类重写要代理的类的所有不是final的方法。在子类中采用方法拦截技术拦截所有的父类方法的调用,顺势织入横切逻辑,对方法进行增强。

在 Spring 中,框架会根据目标类是否实现了接口来决定采用哪种动态代理的方式。

当bean实现接口时,会用JDK代理模式

当bean没有实现接口,用cglib实现( 可以强制使用cglib:在spring配置中加入<aop:aspectj-autoproxy proxyt-target-class=”true”/>)

1.3 AOP开发明确事项

1.3.1 开发阶段(我们做的)

编写核心业务代码(目标类的目标方法) 切入点

把公用代码抽取出来,制作成通知(增强功能方法) 通知

在配置文件中,声明切入点与通知间的关系 切面

1.3.2 运行阶段(Spring框架完成的)

Spring 框架监控切入点方法的执行。一旦监控到切入点方法被运行,使用代理机制,动态创建目标对象的代理对象,根据通知类别,在代理对象的对应位置,将通知对应的功能织入,完成完整的代码逻辑运行。

2. 基于注解的AOP开发

步骤分析

  1. 创建java项目,导入AOP相关坐标
  2. 创建目标接口和目标实现类(定义切入点)
  3. 创建通知类(定义通知)
  4. 将目标类和通知类对象创建权交给spring
  5. 在通知类中使用注解配置织入关系,升级为切面类
  6. 在配置文件中开启组件扫描和 AOP 的自动代理
  7. 编写测试代码

1)创建java项目,导入AOP相关坐标

image.png 2)创建目标接口和目标实现类

public interface AccountService {

public void transfer();

}

image.png 3)创建通知类

public class MyAdvice {

public void before() {

System.out.println("前置通知...");

}

}

4)将目标类和通知类对象创建权交给spring

@Service

public class AccountServiceImpl implements AccountService {}

@Component

public class MyAdvice {}

5)在通知类中使用注解配置织入关系,升级为切面类

@Component

@Aspect //升级为切面类:配置切入点和通知的关系

public class MyAdvice {

@Before("execution(* com.lagou...(..))")

public void before() {

System.out.println("前置通知...");

}

}

6)在配置文件中开启组件扫描和 AOP 的自动代理

<context:component-scan base-package="com.lagou"/>

aop:aspectj-autoproxy</aop:aspectj-autoproxy>

7)编写测试代码

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration("classpath:applicationContext.xml")

class AccountServiceTest {

@Autowired

private AccountService accountService;

@Test

public void testTransfer() throws Exception {

accountService.transfer();

}

}

切点表达式

表达式语法:

execution([修饰符] 返回值类型 包名.类名.方法名(参数))

  • 访问修饰符可以省略
  • 返回值类型、包名、类名、方法名可以使用星号 * 代替,代表任意
  • 包名与类名之间一个点 . 代表当前包下的类,两个点 … 表示当前包及其子包下的类
  • 参数列表可以使用两个点 … 表示任意个数,任意类型的参数列表

切点表达式抽取

当多个增强的切点表达式相同时,可以将切点表达式进行抽取,在增强中使用 pointcut-ref 属性代替 pointcut 属性来引用抽取后的切点表达式。

image.png 通知类型

通知的配置语法:@通知注解(“切点表达式")

image.png 知识小结

  • 使用@Aspect注解,标注切面类

  • 使用@Before等注解,标注通知方法

  • 使用@Pointcut注解,抽取切点表达式

  • 配置aop自动代理 aop:aspectj-autoproxy/ 或 @EnableAspectJAutoProxy(纯注解,编写SpringConfig类)

好啦,今天的文章就到这里,希望能帮助到屏幕前迷茫的你们