Spring基础——AOP面向切面编程
基础配置:
pom.xml导入依赖:

<dependencies> <!-- 核心容器(core container)--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>5.3.10</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>5.3.10</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.10</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>5.3.10</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>5.3.10</version> </dependency> <!-- AOP、aspects、spring-instrument 、messaging--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>5.3.10</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.9.7</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.7</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.3.10</version> </dependency> <!-- Data Access/Intergration--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.3.10</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.3.10</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>5.3.10</version> </dependency> <!-- web--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>5.3.10</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.10</version> </dependency> <!-- 日志相关jar包 (可选)--> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>compile</scope> </dependency> <!-- jdbcTemplate--> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.4</version> </dependency> <dependency> <groupId>commons-pool</groupId> <artifactId>commons-pool</artifactId> <version>1.6</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> </dependencies>
补充属性注入依赖:

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!-- ********IOC********--> <!-- id:对象名称,唯一标识 class:该对象具体属于哪个类,要用全类名 scope:范围。singleton单例,默认。prototype多例。request、session init-method:可以自己设置初始化方法 destroy-method:可以自己设置销毁方法 --> <!-- XML方式测试1:简单尝试用spring--> <!-- <bean id="userDao" class="com.swpu.dao.UserDaoImpl" scope="singleton"--> <!-- init-method="initUserDaoImpl" destroy-method="destroyUserDaoImpl"></bean>--> <!-- context:component-scan base-package:扫描注解所在的包--> <!-- 注解方式测试1:简单尝试用spring--> <!-- <context:component-scan base-package="com.swpu"></context:component-scan>--> <!-- 注解方式:构造注解方式同属性注解方式同--> <context:component-scan base-package="com.swpu"></context:component-scan> </beans>
容器获取和AOP注解扫描:
(最后两句注释掉,因为测试AOP要先验证整个结构的代码逻辑是否正常)

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <context:component-scan base-package="com.swpu"/> <!-- **********测试AOP XML方式***************--> <!-- 切入点简写方式(根据个人情况简写):* *..*.*Service.get*(..) public void com.swpu.service.BookService.getAllBooks() public:不写 void:* 即无论任何返回值类型都可以 com.swpu.service包:包名一般都是只有最后一个包不同,*..*\ BookService类:*Service 表示任何名称以Service结尾的类都可以 getAllBooks():get*(..) 表示指定类下的名称为get开头的所有方法都可以。参数为任意参数 --> <!-- ①自定义切面类对象--> <!-- <bean id="transationAspect" class="com.swpu.aspectJ.TransationAspect"/>--> <!-- <aop:config>--> <!-- ②将自定义切面类对象引入AOP的设置中--> <!-- <aop:aspect ref="transationAspect">--> <!-- ③使用自定义切面AOP(通知+切入点)通知:如何使用切面。切入点:在哪里使用切面--> <!--前置通知--> <!-- <aop:before method="startTrans" pointcut="execution(public void com.swpu.service.BookService.getAllBooks())"></aop:before>--> <!--后置通知--> <!-- <aop:after-returning method="commitTrans" pointcut="execution(* *..*.*Service.get*(..))"></aop:after-returning>--> <!-- 测试其他通知--> <!-- 最终通知:报错也执行 --> <!-- <aop:after method="commitTrans" pointcut="execution(* *..*.*Service.get*(..))"></aop:after>--> <!-- 异常通知:报错才执行 --> <!-- <aop:after-throwing method="commitTrans" pointcut="execution(* *..*.*Service.get*(..))"></aop:after-throwing>--> <!-- 环绕通知:之前+之后 在transationAspect类自定义环绕方法around--> <!-- <aop:around method="around" pointcut="execution(* *..*.*Service.get*(..))"></aop:around>--> <!-- </aop:aspect>--> <!-- </aop:config>--> <!-- **********测试AOP 注解方式***************--> <bean id="transationAspect" class="com.swpu.aspect.TransationAspect"></bean> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
测试AOP:
1.写好整个结构,保证代码逻辑正常
2.再写切面,测试切面
先简单定义Dao和DaoImpl:

public interface BookDao {
void findAllBooks();
}

@Repository
public class BookDaoImpl implements BookDao {
public void findAllBooks() {
System.out.println("已查找到所有书籍");
}
}
Service和ServiceImpl:

public interface BookService {
//在该方法的前后加上切面里的方法,开启事务和提交事务
//思路:将自定义TransationAspect切面类的两个方法穿插进getAllBooks的前后
//开启事务方法:自定义TransationAspect切面类的startTrans
public void getAllBooks();
//提交事务方法:自定义TransationAspect切面类的commitTrans
// 测试其他通知,会报错的方法
public void mistake();
}

@Service
public class BookServiceImpl implements BookService{
@Autowired
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
public void getAllBooks() {
bookDao.findAllBooks();
// mistake();//报错
}
//报错方法
public void mistake() {
System.out.println(1/0);
System.out.println("报错");
}
}
Test类:

public class BookTest {
@Test
public void testAOP(){
ApplicationContext ac = new ClassPathXmlApplicationContext("appContext.xml");
BookController bookController = (BookController)ac.getBean("bookController");
bookController.queryAllBooks();
}
}
如上为基本代码逻辑。
写控制/界面层+切面层(注解形式):

//前置通知
@Before(value = "execution(public void com.swpu.service.BookService.getAllBooks())")
//后置通知
@After(value = "execution(* *..*.*Service.get*(..))")

@Controller
public class BookController {
@Autowired
private BookService bookService;
public void setBookService(BookService bookService) {
this.bookService = bookService;
}
public void queryAllBooks(){
bookService.getAllBooks();
}
}

/**
* 自定义切面类:事务切面
* 注解形式:
*
* @Aspect:定义切面类
* @Before前置通知
* @AfterReturning后置通知
* @Around环绕通知
* @AfterThrowing异常通知
* @After最终通知
*/
@Aspect
public class TransationAspect {
//前置通知
@Before(value = "execution(* *..*.*Service.get*(..))")
public void startTrans() {
System.out.println("开启事务");
}
// @AfterReturning(value = "execution(* *..*.*Service.get*(..))")
// @AfterThrowing(value = "execution(* *..*.*Service.get*(..))")
//后置通知
@After(value = "execution(* *..*.*Service.get*(..))")
public void commitTrans() {
System.out.println("提交事务");
}
// 环绕通知方法
@Around(value = "execution(* *..*.*Service.get*(..))")
public void around(ProceedingJoinPoint point) throws Throwable {
System.out.println("开启日志");//假设的切面方法
point.proceed();//切入点的代理对象
System.out.println("提交日志");//假设的切面方法
}
}

<bean id="transationAspect" class="com.swpu.aspectJ.TransationAspect"></bean> <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
xml形式:
控制层同上,切面层取消方法头部注解,xml文件换用自定义AOP:

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <context:component-scan base-package="com.swpu"/> <!-- **********测试AOP XML方式***************--> <!-- 切入点简写方式(根据个人情况简写):* *..*.*Service.get*(..) public void com.swpu.service.BookService.getAllBooks() public:不写 void:* 即无论任何返回值类型都可以 com.swpu.service包:包名一般都是只有最后一个包不同,*..*\ BookService类:*Service 表示任何名称以Service结尾的类都可以 getAllBooks():get*(..) 表示指定类下的名称为get开头的所有方法都可以。参数为任意参数 --> <!-- ①自定义切面类对象--> <bean id="transationAspectXml" class="com.swpu.aspectJ.TransationAspeceXml"/> <aop:config> <!-- ②将自定义切面类对象引入AOP的设置中--> <aop:aspect ref="transationAspectXml"> <!-- ③使用自定义切面AOP(通知+切入点)通知:如何使用切面。切入点:在哪里使用切面--> <!-- 前置通知--> <aop:before method="startTrans" pointcut="execution(public void com.swpu.service.BookService.getAllBooks())"></aop:before> <!-- 后置通知--> <aop:after-returning method="commitTrans" pointcut="execution(* *..*.*Service.get*(..))"></aop:after-returning> <!-- 测试其他通知--> <!-- 最终通知:报错也执行 --> <aop:after method="commitTrans" pointcut="execution(* *..*.*Service.get*(..))"></aop:after> <!-- 异常通知:报错才执行 --> <aop:after-throwing method="commitTrans" pointcut="execution(* *..*.*Service.get*(..))"></aop:after-throwing> <!-- 环绕通知:之前+之后 在transationAspect类自定义环绕方法around--> <aop:around method="around" pointcut="execution(* *..*.*Service.get*(..))"></aop:around> </aop:aspect> </aop:config> <!-- **********测试AOP 注解方式***************--> <!-- <bean id="transationAspect" class="com.swpu.aspectJ.TransationAspect"></bean>--> <!-- <aop:aspectj-autoproxy></aop:aspectj-autoproxy>--> </beans>
其中methon爆红,直接more action内选择创建方法即可,结果如下:

package com.swpu.aspectJ;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
public class TransationAspeceXml {
public void startTrans(JoinPoint joinPoint) throws Throwable {
System.out.println("开启事务");
}
public void commitTrans(JoinPoint joinPoint) throws Throwable {
System.out.println("提交事务");
}
public void around(ProceedingJoinPoint point) throws Throwable {
System.out.println("开启日志");//假设的切面方法
point.proceed();//切入点的代理对象
System.out.println("提交日志");//假设的切面方法
}
}
格式参考:

<!-- ①自定义切面类对象--> <bean id="切面类" class="com.swpu.aspectJ.切面类"/> <aop:config> <!-- ②将自定义切面类对象引入AOP的设置中--> <aop:aspect ref="transationAspect"> <!-- ③使用自定义切面AOP(通知+切入点)通知:如何使用切面。切入点:在哪里使用切面--> <!-- 前置通知--> 切入点格式1 <aop:before(通知类型) method="测试方法" pointcut="execution(public void com.swpu.service.BookService.getAllBooks())"></aop:before> <!-- 后置通知--> 切入点格式2 <aop:after-returning(通知类型) method="测试方法" pointcut="execution(* *..*.*Service.get*(..))"></aop:after-returning> </aop:aspect> </aop:config>
学习博客:
【Over】
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!