SpingAOP笔记

代理模式:在不修改源代码的基础上新增业务逻辑
静态代理:代理一个对象
动态代理:代理多个对象
jdk自带的动态代理:代理和被代理对象必须实现相同的接口
cglib实现的动态代理:可以代理没有接口的类

AOP 简介
AOP(Aspect-Oriented Programming, 面向切面编程): 是一种新的方法论, 是对传统 OOP(Object-Oriented Programming, 面向对象编程) 的补充.
AOP 的主要编程对象是切面(aspect), 而切面模块化横切关注点.
在应用 AOP 编程时, 仍然需要定义公共功能, 但可以明确的定义这个功能在哪里, 以什么方式应用, 并且不必修改受影响的类. 这样一来横切关注点就被模块化到特殊的对象(切面)里.
AOP 的好处:每个事物逻辑位于一个位置, 代码不分散, 便于维护和升级业务模块更简洁, 只包含核心业务代码.

AOP术语

切面对象(Aspect): 横切关注点(跨越应用程序多个模块的功能)被模块化的特殊对象
通知(切面对象里面的具体方法)(Advice): 切面必须要完成的工作
目标(Target): 被通知的对象
代理对象(Proxy): 向目标对象应用通知之后创建的对象
连接点(Joinpoint): 程序执行的某个特定位置:如类某个方法调用前、调用后、方法抛出异常后等。连接点由两个信息确定:方法表示的程序执行点;相对点表示的方位。例如 ArithmethicCalculator#add() 方法执行前的连接点,执行点为 ArithmethicCalculator#add(); 方位为该方法执行前的位置
切点(pointcut): 每个类都拥有多个连接点:例如 ArithmethicCalculator 的所有方法实际上都是连接点,即连接点是程序类中客观存在的事务。AOP 通过切点定位到特定的连接点。类比:连接点相当于数据库中的记录,切点相当于查询条件。切点和连接点不是一对一的关系,一个切点匹配多个连接点,切点通过 org.springframework.aop.Pointcut 接口进行描述,它使用类和方法作为连接点的查询条件。

AOP开发步骤
1.导包
spring核心 + springAOP模块
2.开启AOP注解开发功能

<!-- 开启aop注解开发功能 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

3.编写切面对象

@Component
@Aspect
public class MyAspect {
	@Before("execution(* com.zl.service..*.*(..))")
	/*
	 * 前置通知:在方法执行之前执行
	 */
	public void before(JoinPoint jp) {
		System.out.println("前置通知"+jp.getSignature().getName()+":方法前执行的业务逻辑,执行时间为:"+new Date());
	}

4.切点表达式

execution(* com.zl.dao..*.*(..))

第一个*:代表任意修饰符任意返回值
第二个*:代表任意类
第三个*:任意方法
第一个…:代表包以及其子包
第二个…:任意参数

5.通知类型

	@Before("execution(* com.zl.service..*.*(..))")
	/*
	 * 前置通知:在方法执行之前执行
	 */
	public void before(JoinPoint jp) {
		System.out.println("前置通知"+jp.getSignature().getName()+":方法前执行的业务逻辑,执行时间为:"+new Date());
	}
	/*
	 * 后置通知(最终通知):
	 * 	1. 不管方法有没有正确执行,后置通知都会执行(类似于finally)
	 */
	@After("execution(* com.zl.service..*.*(..))")
	public void after(JoinPoint jp) {
		System.out.println("后置通知"+jp.getSignature().getName()+":方法执行完成,执行完成的时间为:"+new Date());
	}
	/*
	 * 返回通知:
	 * 	1. 只有方法正确执行完成以后才会执行返回通知
	 * 	2. 可以在通知中拿到方法的返回值,如果方法没有返回值那么在通知中获取的值为null,可以通过获取的返回值进行先一步操作
	 */
	@AfterReturning(pointcut="execution(* com.zl.service..*.*(..))",returning="obj")
	public void afterRrturn(JoinPoint jp,Object obj) {
		if(obj!=null) {
			int flag=(int)obj;
			if(flag>0) {
				System.out.println("修改成功...");
			}else {
				System.out.println("修改失败..。");
			}
		}
		System.out.println("返回通知"+jp.getSignature().getName()+":方法执行完成,执行完成的时间为:"+new Date());
	}
	/*
	 * 异常通知:
	 * 	1. 只有方法有异常的时候才会触发异常通知,并且在通知中可以获取异常类型
	 */
	@AfterThrowing(pointcut="execution(* com.zl.service..*.*(..))",throwing="e")
	public void AfterThrowing(JoinPoint jp,Exception e) {
		if(e instanceof ArithmeticException) {
			System.out.println("这是算数异常,做.......");
		}else if(e instanceof ClassCastException) {
			System.out.println("这是类型转换异常,做.......");
		}
		System.out.println("异常通知"+jp.getSignature().getName()+":方法抛出异常,抛出异常的时间为:"+new Date());
	}
	/*
	 * 环绕通知:
	 * 	1. 可以拿到方法返回值,并且可以更改方法返回值
	 * 	2. 可以控制目标方法是否继续执行
	 * 	3. 相当于以上通知的合集
	 * 	4. proceed()该方法不调用最终的效果是环绕通知执行了但是目标方法没有执行
	 */
	@Around("execution(* com.zl.service..*.*(..))")
	public Object around(ProceedingJoinPoint  pjp) {
		Object obj=null;
		try {
			System.out.println("环绕通知方法前....");
			//相当于执行目标方法
			obj=pjp.proceed();
			obj=100;
			System.out.println("环绕通知中获取的方法返回值为:"+obj);
			System.out.println("环绕通知方法后....");
		} catch (Throwable e) {
			e.printStackTrace();
		}
		return obj;
	}

切点表达式的逻辑运算符

@before("execution(* com.zl.service.impl.UserServiceImpl.add*()) || execution(* com.zl.service.impl.UserServiceImpl.delete*())")

基于配置文件的AOP配置

1.声明切面
当使用 XML 声明切面时, 需要在 根元素中导入 aop Schema
在 Bean 配置文件中, 所有的 Spring AOP 配置都必须定义在 aop:config 元素内部. 对于每个切面而言, 都要创建一个 aop:aspect 元素来为具体的切面实现引用后端 Bean 实例.
切面 Bean 必须有一个标示符, 供 aop:aspect 元素引用

2.声明切点表达式
切入点使用 aop:pointcut 元素声明
切入点必须定义在 aop:aspect 元素下, 或者直接定义在 aop:config 元素下.
定义在 aop:aspect 元素下: 只对当前切面有效
定义在 aop:config 元素下: 对所有切面都有效
基于 XML 的 AOP 配置不允许在切入点表达式中用名称引用其他切入点.

3.声明通知
在 aop Schema 中, 每种通知类型都对应一个特定的 XML 元素.
通知元素需要使用 来引用切入点, 或用 直接嵌入切入点表达式. method 属性指定切面类中通知方法的名称.

案例:

<!-- 第一步:通过注解把切面对象放到IOC容器中 -->
@Component
public class MyAspect {
	....
	}
<!-- 第二步:配置AOP相关的配置 -->
<aop:config>
<!-- 配置切面表达式 -->
	<aop:pointcut expression="execution(* com.zl.dao..*.*(..))" id="myPointCut1"/>
	<aop:pointcut expression="!execution(* com.zl.dao..*.add*(..))" id="myPointCut2"/>
<!-- 配置好的切面表达式作用在切面对象的那个通知上面 -->
	<aop:aspect ref="myProxy">
		<aop:after method="after" pointcut-ref="myPointCut1"/>
		<aop:before method="before" pointcut-ref="myPointCut1"/>
		<aop:after-returning method="afterReturning" pointcut-ref="myPointcut1" returning="obj"/>
		<aop:after-throwing method="afterThrowing" pointcut-ref="myPointcut1" throwing="e"/>
		<aop:around method="around" pointcut-ref="myPointcut1"/>
	</aop:aspect>
</aop:config>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值