朱晔和你聊Spring系列S1E6:容易犯错的Spring AOP

标题有点标题党了,这里说的容易犯错不是Spring AOP的错,是指使用的时候容易犯错。本文会以一些例子来展开讨论AOP的使用以及使用过程中容易出错的点。

几句话说清楚AOP

朱晔和你聊Spring系列S1E6:容易犯错的Spring AOP

有关必要术语:

切面:Aspect,有的地方也叫做方面。切面=切点+增强,表示我们在什么点切入蛋糕,切入蛋糕后我们以什么方式来增强这个点。

切点:Pointcut,类似于查询表达式,通过在连接点运行查询表达式来寻找匹配切入点,Spring AOP中默认使用AspjectJ查询表达式。

增强:Advice,有的地方也叫做通知。定义了切入切点后增强的方式,增强方式有前、后、环绕等等。Spring AOP中把增强定义为拦截器。

连接点:Join point,蛋糕所有可以切入的点,对于Spring AOP连接点就是方法执行。

有关使用方式:

Spring AOP API:这种方式是Spring AOP实现的基石。最老的使用方式,在Spring 1.2中的时候用这种API的方式定义AOP。

注解声明:使用@AspectJ的@Aspect、@Pointcut等注解来定义AOP。现在基本都使用这种方式来定义,也是官方推荐的方式。

配置文件:相比注解声明方式,配置方式有两个缺点,一是定义和实现分离了,二是功能上会比注解声明弱,无法实现全部功能。好处么就是XML在灵活方面会强一点。

编程动态配置:使用AspectJProxyFactory进行动态配置。可以作为注解方式静态配置的补充。

有关织入方式:

织入说通俗点就是怎么把增强代码注入到连接点,和被增强的代码融入到一起。

运行时:Spring AOP只支持这种方式。实现上有两种方式,一是JDK动态代理,通过反射实现,只支持对实现接口的类进行代理,二是CGLIB动态字节码注入方式实现代理,没有这个限制。Spring 3.2之后的版本已经包含了CGLIB,会根据需要选择合适的方式来使用。

编译时:在编译的时候把增强代码注入进去,通过AspjectJ的ajc编译器实现。实现上有两种方式,一种是直接使用ajc编译所有代码,还有一种是javac编译后再进行后处理。

加载时:在JVM加载类型的时候注入代码,也叫做LTW。通过启动程序的时候通过javaagent代理默认的类加载器实现。

使用Spring AOP实现事务的坑

新建一个模块:

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 "> <modelVersion>4.0.0</modelVersion> <groupId>me.josephzhu</groupId> <artifactId>spring101-aop</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>spring101-aop</name> <description></description> <parent> <groupId>me.josephzhu</groupId> <artifactId>spring101</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.7</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> </project>

在这里我们引入了jackson,以后我们会用来做JSON序列化。引入了mybatis启动器,以后我们会用mybstis做数据访问。引入了h2嵌入式数据库,方便本地测试使用。引入了web启动器,之后我们还会来测试一下对web项目的Controller进行注入。
先来定义一下我们的测试数据类:

package me.josephzhu.spring101aop; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.math.BigDecimal; @Data @NoArgsConstructor @AllArgsConstructor public class MyBean { private Long id; private String name; private Integer age; private BigDecimal balance; }

然后,我们在resources文件夹下创建schema.sql文件来初始化h2数据库:

CREATE TABLE PERSON( ID BIGINT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(255), AGE SMALLINT, BALANCE DECIMAL );

还可以在resources文件夹下创建data.sql来初始化数据:

INSERT INTO PERSON (NAME, AGE, BALANCE) VALUES ('zhuye', 35, 1000);

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzfgzw.html