Spring中AOP开发

Aop思想

  • servlet技术中的filter过滤器技术
    在这里插入图片描述
  • struts2中的interceptor技术
    在这里插入图片描述
  • 动态代理
    在这里插入图片描述

spring-aop开发概念

spring封装了代理技术来体现aop思想.
spring可以对所有类进行代理.
spring为了能够对所有类进行代理.封装了两种代理技术

动态代理

局限性:被带代理对象必须实现至少一个接口.动态代理技术是基于接口的代理技术
没有实现接口那么无法被动态代理.

CGLib代理

属于继承代理.该技术生成的代理类是被代理类的子类. 几乎所有类都可以被CGLIb代理.处了被final修饰的类.

有关aop的名词解释

连接点(join point): 所有可以被增强(代理)的方法
切点(point cut):即将(需要)或已经被增强的方法
通知(advice):对切点需要增强的代码
目标对象(target):被代理的对象
代理对象(proxy):对目标对象的切点应用通知后生成的对象
织入(weaver)动词:将通知应用到切点的过程,或者说生成代理对象的过程
切面:(aspect|advisor)组合词:切点+通知 称之为切面

aop在spring中的配置

使用xml配置文件开发

  1. 导包

4+2包+spring-aop包+spring-aspects包 2个在spring辅助包中:aop联盟包+aspectj-weaver包

  1. 目标对象
    在这里插入图片描述
  2. 通知(对切点需要增强的代码,一个类)

前置通知 通知代码,在目标方法执行前调用
环绕通知 通知代码,在目标方法执行前和执行后都调用
后置通知 通知代码,在目标方法执行后调用. 切点方法抛出异常,通知不执行
后置通知 通知代码,在目标方法执行后调用. 切点方法抛出异常,通知仍然执行
异常通知 通知代码,在目标方法抛出异常后才会执行.

  1. 配置

1.导入aop约束,前缀为aop
2.注册目标对象,注册通知对象
3.在xml中配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" 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-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd ">
	 
	 <!-- 1.配置目标对象 -->
	 <bean name="userService" class="cn.xiaos.service.UserServiceImpl" ></bean>  
	 <!-- 2.配置通知对象 -->
	 <bean name="myAdvice" class="cn.xiaos.advice.MyAdvice" ></bean>  
	 <!-- 3.配置切面 切点+通知 -->
	 		<!-- 3.1 书写切点表达式,aspectJ切点表达式
	 				格式 : execution(表达式)
	 					public void cn.itcast.service.UserServiceImpl.save()
	 					void cn.itcast.service.UserServiceImpl.save()  同上
	 					* cn.itcast.service.UserServiceImpl.save() 方法返回值任意
	 					* cn.itcast.service.*ServiceImpl.save() 包中所有以ServiceImpl结尾的类
	 					* cn.itcast.service.*ServiceImpl.*() 方法名任意
	 					* cn.itcast.service.*ServiceImpl.*(..) 没有或多个任意参数
	 					* cn.itcast.service..*ServiceImpl.*(..) 当前包以及后代包
	 		 -->
	 <aop:config>
	 		<!-- 
	 		aop:pointcut : 配置切点(需要被增强的方法)
	 			 expression:表达式
	 			 id:为表达式指定名称,方便后续引用	
	 		 -->
	 		 <aop:pointcut expression="execution(* cn.xiaos.service.*ServiceImpl.*(..))" id="myPC"/>
	 		 <!-- 配置通知+切点 => 切面 
	 		 		ref:哪个对象是通知类
	 		 -->
	 		 <aop:aspect ref="myAdvice" >
	 		 	<!-- 前置通知  method=>方法名   pointcut-ref=>切点名称 -->
	 		 	<aop:before method="before" pointcut-ref="myPC" />
	 		 	<!-- 环绕通知 -->
	 		 	<aop:around method="around" pointcut-ref="myPC" />
	 		 	<!-- 后置通知 -->
	 		 	<aop:after-returning method="afterReturning" pointcut-ref="myPC" />
	 		 	<!-- 后置通知 -->
	 		 	<aop:after method="after" pointcut-ref="myPC" />
	 		 	<!-- 异常通知 -->
	 		 	<aop:after-throwing method="afterThrowing" pointcut-ref="myPC" />
	 		 </aop:aspect>
	 </aop:config>
	   
</beans>
	   

使用注解方式配置

1.导包(同上),2.目标文件编写(同上)3.注册目标对象,注册通知对象
3.开启aop注解配置事务开关
<aop:aspectj-autoproxy> </aop:aspectj-autoproxy>
4.在通知类中使用注解配置切面

package cn.xiaos.advice;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

// 5种通知
// 前置通知 通知代码,在目标方法执行前调用
// 环绕通知 通知代码,在目标方法执行前和执行后都调用
// 后置通知 通知代码,在目标方法执行后调用. 切点方法抛出异常,通知不执行
// 后置通知 通知代码,在目标方法执行后调用. 切点方法抛出异常,通知仍然执行
// 异常通知 通知代码,在目标方法抛出异常后才会执行.
//通知类
//@Aspect => 标识当前类用于配置切面
@Aspect 
public class MyAdvice {
	
	@Pointcut("execution(* cn.itcast.service.*ServiceImpl.*(..))")
	public void myPC(){}
	
	// 前置通知
	@Before("MyAdvice.myPC()")
	public void before() {
		System.out.println("我是前置通知!");
	}
	// 环绕通知
	@Around("MyAdvice.myPC()")
	public Object around(ProceedingJoinPoint pjp) throws Throwable {
		System.out.println("我是环绕通知前半部分,我在切点方法执行前执行!");
		// 手动调用切点方法执行
		Object obj = pjp.proceed(); // 执行切点方法
		System.out.println("我是环绕通知后半部分,我在切点方法执行后执行!");
		return obj;
	}
	// 后置通知 => 出现异常,就不执行
	@AfterReturning("MyAdvice.myPC()")
	public void afterReturning() {
		System.out.println("我是后置通知,出现异常不执行!");
	}
	// 后置通知 => 出现异常,仍然执行
	@After("MyAdvice.myPC()")
	public void after() {
		System.out.println("我是后置通知,出现异常仍然执行!");
	}
	// 异常通知
	@AfterThrowing("MyAdvice.myPC()")
	public void afterThrowing() {
		System.out.println("我是异常通知,抛出异常后执行!");
	}
}

猜你喜欢

转载自blog.csdn.net/weixin_41349389/article/details/82863816