AOP基于xml方式配置

本文深入解析Spring框架中的AOP(面向切面编程)概念,包括其核心术语如连接点、切入点、通知、切面和织入,以及如何利用Spring的动态代理机制实现AOP,通过实例演示了如何配置切面、切入点表达式和不同类型的通知。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Spring的AOP

Spring通过动态代理模式的实现后,我们可以定义AOP其实就是用于通过规则设置来拦截方法,加入可以统一处理的代码。

关于代理的选择

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

AOP相关术语

Joinpoint(连接点):
所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点。
---就是根据规则,可以指定拦截的方法,我们将每一个被拦截的方法称为连接点。

Pointcut(切入点):

–所谓的切入点,就是拦截方法设置的规则

所谓切入点是指我们要对哪些Joinpoint进行拦截的定义。一连串方法。

Advice(通知/增强):

–就是可以设置在方法之前拦截或者方法执行之后拦截或者方法出异常后拦截,或者方法之前和之后都拦截。我们将这些拦截场景称为通知

所谓通知是指拦截到Joinpoint之后所要做的事情就是通知。

通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。

Aspect(切面):

–所谓的切面就是我们的拦截处理类。

是切入点和通知的结合。

Weaving(织入):

-把切面加入到对象,并创建出代理对象的过程。(该过程由Spring来完成)

在这里插入图片描述

配置AOP

第一步:创建一个Java项目

需求:编写一个切面类,在执行insert,update方法,分别在方法执行前、方法之后、异常出现后、最终方法执行前后调用编写统一处理的代码,

创建一个Java项目,加入Spring框架的基础支持包和aop依赖包

在这里插入图片描述

第二步:编写业务层类和接口

--UserServiceImpl
package cn.zj.spring.service.impl;

import cn.zj.spring.pojo.User;
import cn.zj.spring.service.UserService;

public class UserServiceImpl  {
	
	public void insert(User user) {
		System.out.println("执行dao的层 insert方法");
		//System.out.println(1/0);
	}
	
	public void updateByPrimaryKey(User user) {
		System.out.println("执行dao的层 update方法");
	}
	
}

第三步:编写模拟事务管理器类

package cn.zj.spring.utils;

import java.util.Arrays;

import org.aspectj.lang.JoinPoint;

/*
 * 此类模拟事务管理器(专门处理事务的类)
 * 
 * 提供,开启,提交,回滚,关闭事务相关操作的方法
 * 
 * 
 */
public class TransactionManagerHandler {

	public void begin(JoinPoint jp) {
		System.out.println("连接点:"+jp);
		System.out.println("args :"+Arrays.toString(jp.getArgs()));
		System.out.println("开启事务");
	}
	public void commit() {
		System.out.println("提交事务");
	}
	
	public void rollback(Throwable ex) {
		System.out.println("ex :"+ex.getMessage());
		System.out.println("回滚事务");
	}
	public void close() {
		System.out.println("释放资源");
	}
}

第四步:编写applicationContext.xml

<?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: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/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
	
	
	<!-- 配置模拟的事务管理器 -->
	<bean id="MyTxManager" class="cn.zj.spring.utils.TransactionManagerHandler"/>
	
	
	<!-- 被代理对象:真实对象 -->
	<bean id="userService" class="cn.zj.spring.service.impl.UserServiceImpl"/>
	
	<!--  
		开始AOP配置
	-->
	
	<!-- 开始AOP配置 -->
	<aop:config>
		<!-- 
			<aop:pointcut expression="" id=""/> 切入点标签
			id :唯一标示
			expression : 切入点的表达式
				AOP的切入点有专门切入点语法
		 -->
		 
		 <!-- where ? -->
		<aop:pointcut expression="execution(* cn.zj.spring.service..*.*(..))" id="pt"/>
		
		
		<!-- 
			配置切面 
			切面 = 切入点 +通知
			
			<aop:aspect ref="">
			ref :引入 要增强的功能类,当前就是模拟的事务管理器
		 -->
		<aop:aspect ref="MyTxManager">
			<!-- 
			<aop:before method="" pointcut-ref=""/>
			配置前置通知/增强
				method : 模拟事务管理器对应的方法名
				pointcut-ref : 切入点引用
			 -->
			<aop:before method="begin" pointcut-ref="pt"/>
			
			<!-- 后置通知 -->
			<aop:after-returning method="commit" pointcut-ref="pt"/>
			<!-- 异常通知 
			<aop:after-throwing method="rollback" throwing="" pointcut-ref="pt"/>
			throwing : 抛出的异常,异常可以抛给增强的方法中
					异常类型 Throwable
					值必须和对应方法中异常的参数名称相同
			-->
			<aop:after-throwing method="rollback" throwing="ex" pointcut-ref="pt"/>
			
			<!-- 最终通知,相当于finaly -->
			<aop:after method="close" pointcut-ref="pt"/>
			
		</aop:aspect>
		
		<!-- Weaving : 织入  运行过程中spring完成 -->
		
	</aop:config>
	
	

</beans>


第五步:测试代码

package cn.zj.spring.test;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import cn.zj.spring.pojo.User;
import cn.zj.spring.service.UserService;
import cn.zj.spring.service.impl.UserServiceImpl;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class UserServiceTest {
	
	@Autowired
	private UserServiceImpl userService;

	@Test
	public void testInsert() {

		User user = new User(null, "钢铁侠", "gtx@qq.com");

		System.out.println(userService.getClass().getName());
		//有接口 : com.sun.proxy.$Proxy13
		//没有接口 :cn.zj.spring.service.impl.UserServiceImpl$$EnhancerBySpringCGLIB$$ea3c2726
		userService.insert(user);

	}

	@Test
	public void testUpdateByPrimaryKey() {
		User user = new User(2, "蜘蛛侠", "zhizhuxia@qq.com");

		userService.updateByPrimaryKey(user);

	}

	@Test
	public void testName() throws Exception {
		userService.toString();
	}

}

测试结果

在这里插入图片描述

AOP常用标签

<aop:config>
作用:
用于声明开始aop的配置
<aop:aspect>
作用:
用于配置切面。
属性:
id:给切面提供一个唯一标识。
ref:引用配置好的通知类bean的id。
<aop:pointcut>
作用:
用于配置切入点表达式
属性:
expression:用于定义切入点表达式。
id:用于给切入点表达式提供一个唯一标识。
<aop:before>
作用:
用于配置前置通知
属性:
method:指定通知中方法的名称。
pointct:定义切入点表达式
pointcut-ref:指定切入点表达式的引用
<aop:after-returning>
作用:
用于配置后置通知,如果出了异常就一定不会调用切面的方法
属性:
method:指定通知中方法的名称。
pointct:定义切入点表达式
pointcut-ref:指定切入点表达式的引用
<aop:after-throwing>
作用:
用于配置异常通知,只有出了异常才会调用切面对应的方法
属性:
method:指定通知中方法的名称。
pointct:定义切入点表达式
pointcut-ref:指定切入点表达式的引用
<aop:after>
作用:
用于配置最终通知,不管出不出异常,调用的切面的方法
属性:
method:指定通知中方法的名称。
pointct:定义切入点表达式
pointcut-ref:指定切入点表达式的引用
<aop:around>
作用:
用于配置环绕通知
属性:
method:指定通知中方法的名称。
pointct:定义切入点表达式
pointcut-ref:指定切入点表达式的引用

切入点表达式说明

匹配方法的执行(常用)
execution(表达式)
表达式语法:execution([修饰符] 返回值类型 包名.类名.方法名(参数))
写法说明:
全匹配方式:
public void cn.zj.service.impl.CustomerServiceImpl.saveCustomer()
访问修饰符可以省略
void com.zj.service.impl.CustomerServiceImpl.saveCustomer()
返回值可以使用*号,表示任意返回值
* com.zj.service.impl.CustomerServiceImpl.saveCustomer()
包名可以使用*号,表示任意包,但是有几级包,需要写几个*
* *.*.*.*.CustomerServiceImpl.saveCustomer()
使用..来表示当前包,及其子包
* com..CustomerServiceImpl.saveCustomer()
类名可以使用*号,表示任意类
* com..*.saveCustomer()
方法名可以使用*号,表示任意方法
* com..*.*()
参数列表可以使用*,表示参数可以是任意数据类型,但是必须有参数
* com..*.*(*)
参数列表可以使用..表示有无参数均可,有参数可以是任意类型
* com..*.*(..)
全通配方式:
* *..*.*(..)

环绕通知

TransactionManagerHandler

package cn.zj.spring.utils;

import org.aspectj.lang.ProceedingJoinPoint;

/*
 * 此类模拟事务管理器(专门处理事务的类)
 * 
 * 提供,开启,提交,回滚,关闭事务相关操作的方法
 * 
 * 
 */
public class TransactionManagerHandler {

	public void allInOne(ProceedingJoinPoint jp) {
		
		try {
			System.out.println("开启事务----------------");
			//执行真实对象的方法
			jp.proceed();
			
			System.out.println("提交事务-----------------");
		} catch (Throwable e) {
			System.out.println("回滚事务-------------------");
		}finally {
			System.out.println("释放资源------------------");
			
		}
		
	}
	
	
}

applicationContext.xml

<?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: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/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
	
	
	<!-- 配置模拟的事务管理器 -->
	<!-- what? -->
	<bean id="MyTxManager" class="cn.zj.spring.utils.TransactionManagerHandler"/>
	
	
	<!-- 被代理对象:真实对象 -->
	<bean id="userService" class="cn.zj.spring.service.impl.UserServiceImpl"/>
	
	
	
	<!--  
		开始AOP配置
		
		配置AOP遵循 WWW原则
		
		w :what ?干什么?
		w :where ? 地点?
		w :when ? 时机?
	-->
	
	<!-- 开始AOP配置 -->
	<aop:config>
		<!-- 
			<aop:pointcut expression="" id=""/>
			id :唯一标示
			expression : 切入点的表达式
				AOP的切入点有专门切入点语法
		 -->
		 
		 <!-- where ? -->
		<aop:pointcut expression="execution(* cn.zj.spring.service..*.*(..))" id="pt"/>
		
		
		<!-- 
			配置切面 
			切面 = 切入点 +通知
			
			<aop:aspect ref="">
			ref :引入 要增强的功能,当前就是模拟的事务管理器
		 -->
		<aop:aspect ref="MyTxManager">
			
			<!-- 环绕通知 -->
			<!-- <aop:around method="allInOne" pointcut="execution(* cn.zj.spring.service..*.*(..))"/> -->
			<aop:around method="allInOne" pointcut-ref="pt"/>
			
		</aop:aspect>
		
		<!-- Weaving : 织入  运行过程中spring完成 -->
	
	</aop:config>
	
	

</beans>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值