Spring学习笔记03:AOP(Aspect Oriented Programming),面向切面编程

本文深入解析了面向切面编程(AOP)的概念,包括其基于动态代理的实现方式,以及在Spring框架中的具体应用。通过实例详细介绍了AOP的术语如切入点、通知、切面等,并演示了五种通知类型的使用方法。

一、什么是AOP?

这是一种编程思想,而不是某种特定的技术。它的作用主要是将重复的代码抽取出来,然后再织入到程序中。最好理解的例子就是Javaweb中的过滤器filter,就是有这种面向切面编程的思想。

二、AOP是基于什么实现的呢?

aop基于动态代理(spring优先选择JDK的Proxy代理,但是spring不要我们去实现动态代理,我们只需要进行一定的配置即可)
Proxy: 被代理的对象必须实现接口
Cglib: 被代理的对象不能被final修饰,基于继承

三、AOP的专用的术语

切入点:最终增强的方法
通知/增强:代理中增强的代码
切面:通知+切入点,通知应用到哪个切入点
目标:被代理对象
织入:将切面的代码应用到目标对象的过程
代理:增强被代理对象生成一个增强的代理对象

四、AOP有五种通知类型:

前置通知before,在方法前执行通知
最终通知after,无论方法是否执行成功,该通知都会执行,有点finally的感觉
成功通知afterReturning ,方法执行成功才执行
异常通知afterThrowing,方法执行出现异常执行
环绕通知around,可以自定义通知执行位置

五、举个例子理解上面的名词:

1.先导包:
 <!-- spring的aop支持 -->
  <dependency>
		<groupId>org.aspectj</groupId>
		<artifactId>aspectjweaver</artifactId>
		<version>1.8.10</version>
</dependency>
<dependency>
	<groupId>org.aspectj</groupId>
	<artifactId>aspectjrt</artifactId>
	<version>1.8.10</version>
</dependency>
  <!-- spring上下文支持 -->
  <dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-context</artifactId>
	<version>5.0.8.RELEASE</version>
</dependency>
<!-- spring整合junit测试 -->
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-test</artifactId>
	<version>5.0.8.RELEASE</version>
	<scope>test</scope>
</dependency>
<!-- junit测试支持 -->
<dependency>
     <groupId>junit</groupId>
     <artifactId>junit</artifactId>
     <version>4.12</version>
     <scope>test</scope>
 </dependency>

2.创建通知对象的目标对象

AccountService接口

public interface AccountService {
	public void save()
}

AccountServiceImpl 实现AccountService接口

public class AccountServiceImpl implements AccountService {

	@Override
	public void save() {
		System.out.println("save操作");
		//int a = 1/0;
	
}

3.创建通知对象

public class MyAdvice {
	//前置通知,在目标方法执行前先执行
	public void before() {
		System.out.println("前置通知");
	}
	//最终通知,无论目标方法是否成功执行,最终都会执行该通知
	public void after() {
		System.out.println("后置通知");
	}
	//成功通知,目标方法成功执行后才执行该通知
	public void afterReturning() {
		System.out.println("成功通知");
	}
	//异常通知,目标方法执行出现异常才执行该通知
	public void afterThrowing() {
		System.out.println("异常通知");
	}
	//环绕通知,手动调用目标方法,可以设置通知的位置
	public void around(ProceedingJoinPoint pjp) throws Throwable {
		System.out.println("环绕通知前");
		pjp.proceed();//调用目标方法
		System.out.println("环绕通知后");
	}
}

注意,环绕通知红框中是固定用法
环绕通知

4.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/aop
	http://www.springframework.org/schema/aop/spring-aop.xsd
	http://www.springframework.org/schema/context 
	http://www.springframework.org/schema/context/spring-context.xsd">
	
	<!-- 配置通知的目标对象 -->
	<bean name="accountService" class="com.spring_demo.ioc.service.AccountServiceImpl"></bean>
	<!-- 配置通知对象 -->
	<bean name="advice" class="com.spring_demo.aop.MyAdvice"></bean>
	<!-- 配置aop -->	
	<aop:config>
		<!-- 配置切点 -->
		<aop:pointcut expression="execution (public * com.spring_demo.ioc.service.*ServiceImpl.*(..))" id="pc"/>
		<!--配置切面 -->
		<aop:aspect ref="advice">
			<aop:before method="before" pointcut-ref="pc"/>
			<aop:after method="after" pointcut-ref="pc"/>
			<aop:after-returning method="afterReturning" pointcut-ref="pc"/>
			<aop:after-throwing method="afterThrowing" pointcut-ref="pc"/>
			<aop:around method="around" pointcut-ref="pc"/>
		</aop:aspect>
	</aop:config>
	<!-- 开启注解 -->
	<context:annotation-config></context:annotation-config>
</beans>

*通配符,该通配符主要用于匹配单个单词,或者是以某个词为前缀或后缀的单词
…通配符,该通配符表示0个或多个项
切点表达式:public * com.spring_demo.ioc.service.*ServiceImpl.*(..)
表达式表示在包com.spring_demo.ioc.service下以ServiceImpl结尾的类的所有公共方法,无论返回值是什么?方法名是什么?方法参数是什么?都是切点
第一个"*“表示无论方法是什么返回值类型都是切点,你可以自定义未void/int等等(则表示只有返回值类型跟你配置一样时才是切点)
第二个”*“表示以ServiceImpl结尾的类
第三个”*"表示无论方法名是什么
最后(..)表示无法方法参数是什么
切点

5.进行测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-aop.xml")
public class TestAOP {
	@Resource(name="accountService")
	AccountService accountService;
	@Test
	public void test1() {
		accountService.save();
	}
}

下面是加载class中的配置文件applicationContext-aop.xml
在这里插入图片描述
测试结果:
测试结果
修改AccountServiceImpl的代码,增加异常代码int a=1/0;

public class AccountServiceImpl implements AccountService {

	@Override
	public void save() {
		System.out.println("save操作");
		int a = 1/0;
}

再次测试,发现异常通知执行,成功通知没有执行:
测试结果2

最后总结:

切入点:上面测试中的切入点就是AccountServiceImpl中的save方法
通知/增强:通知对象MyAdvice中的五种通知
切面:通知+切入点
目标:被代理对象指AccountServiceImpl
织入:将切面的代码应用到目标对象的过程
代理:下面注入的是AccountServiceImpl的增强对象在这里插入图片描述
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值