spring总结6——springAOP

springAOP

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入门案例

AOP所需要的jar包

  1. spring核心
  2. springAOP模块

开启AOP注解开发功能

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

编写切面对象

​ 在切面对象上面声明@Aspect注解,用来表示该类为切面对象

在切面对象的对应方法上定义通知类型以及切点表达式

切点表达式

“execution( com.zl.dao…*.*(…))”*

​ 第一个*:代表任意修饰符任意返回值

​ 第二个*:代表任意类

​ 第三个*:任意方法

​ 第一个…:代表包以及其子包

​ 第二个…:任意参数

通知类型

前置通知

​ 前置通知:在方法执行之前执行的通知,前置通知使用 @Before 注解, 并将切入点表达式的值作为注解值.

	/*
	 * 切面对象:里面放置的是我们新增的业务逻辑
	 * @Before():前置通知
	 */
	@Before("!execution(* com.zl.dao..*.add*(..))")
	public void before(JoinPoint jp) {
		System.out.println(jp.getSignature().getName()+":方法之前执行..");
	}

后置通知

​ 后置通知是在连接点完成之后执行的, 即连接点返回结果或者抛出异常的时候, 下面的后置通知记录了方法的终止.

	/*
	 * 后置通知:不管方法有没有异常都会执行
	 */
	//@After("execution(* com.zl.dao..*.*(..))")
	public void after(JoinPoint jp) {
		System.out.println(jp.getSignature().getName()+":方法之后执行..");
	}

返回通知

​ 无论连接点是正常返回还是抛出异常, 后置通知都会执行. 如果只想在连接点返回的时候记录日志, 应使用返回通知代替后置通知.在通知中我们可以获取代理方法的返回值

	/*
	 * 返回通知:
	 * 	1.必须是方法正常执行完成后才会执行返回通知
	 * 	2.可以在通知中拿到目标方法的返回值
	 * 	3.如果方法没有返回值,name返回null
	 */
	//@AfterReturning(pointcut="execution(* com.zl.dao..*.*(..))",returning="s")
	public void afterReturn(JoinPoint jp,Object s) {
		System.out.println(jp.getSignature().getName()+":方法返回通知,该方法的返回值为:"+s);
	}

异常通知

只在连接点抛出异常时才执行异常通知,同时在通知中可以获取目标方法出现异常类型

/*
	 * 异常通知:
	 * 	1.可以在通知中拿到目标方法出现的异常类型
	 * 	2.异常通知必须方法出现异常的时候才会执行
	 */
	//@AfterThrowing(pointcut="execution(* com.zl.dao..*.*(..))",throwing="e")
	public void afterThrow(JoinPoint jp,Exception e) {
		System.out.println(jp.getSignature().getName()+":方法异常通知,该方法出现的异常类型为:"+e);
	}

环绕通知

​ 环绕通知是所有通知类型中功能最为强大的, 能够全面地控制连接点. 甚至可以控制是否执行连接点.

​ 对于环绕通知来说, 连接点的参数类型必须是 ProceedingJoinPoint . 它是 JoinPoint 的子接口, 允许控制何时执行, 是否执行连接点.

​ 在环绕通知中需要明确调用 ProceedingJoinPoint 的 proceed() 方法来执行被代理的方法. 如果忘记这样做就会导致通知被执行了, 但目标方法没有被执行.

​ 环绕通知的方法需要返回目标方法执行之后的结果, 即调用 joinPoint.proceed(); 的返回值, 否则会出现空指针异常.

	/*
	 * 环绕通知:
	 * 	1.可以认为是前置通知和后置通知的结合
	 * 	2.可以控制目标方法是否执行
	 * 	3.还可以修改目标方法的返回值
	 * 	4.如果没有执行proceed()方法那么只会执行环绕通知,而不会执行目标方法
	 */
	@Around("execution(* com.zl.dao..*.*(..))")
	public Object myAround(ProceedingJoinPoint jp) {
		Object o=null;
		System.out.println("环绕通知方法之前...");
		//执行目标方法
		try {
			o=jp.proceed();
			o=505;
		} catch (Throwable e) {
			e.printStackTrace();
		}
		System.out.println("通知方法返回值为:"+o);
		System.out.println("环绕通知方法之后...");
		return o;
	}

基于配置文件的AOP配置

​ 除了使用 AspectJ 注解声明切面, Spring 也支持在 Bean 配置文件中声明切面. 这种声明是通过 aop schema 中的 XML 元素完成的.

​ 正常情况下, 基于注解的声明要优先于基于 XML 的声明. 通过 AspectJ 注解, 切面可以与 AspectJ 兼容, 而基于 XML 的配置则是 Spring 专有的. 由于 AspectJ 得到越来越多的 AOP 框架支持, 所以以注解风格编写的切面将会有更多重用的机会.

声明切面

​ 当使用 XML 声明切面时, 需要在 根元素中导入 aop Schema

​ 在 Bean 配置文件中, 所有的 Spring AOP 配置都必须定义在 aop:config 元素内部. 对于每个切面而言, 都要创建一个 aop:aspect 元素来为具体的切面实现引用后端 Bean 实例.

切面 Bean 必须有一个标示符, 供 aop:aspect 元素引用

声明切点表达式

切入点使用 aop:pointcut 元素声明

切入点必须定义在 aop:aspect 元素下, 或者直接定义在 aop:config 元素下.

​ 定义在 aop:aspect 元素下: 只对当前切面有效

​ 定义在 aop:config 元素下: 对所有切面都有效

基于 XML 的 AOP 配置不允许在切入点表达式中用名称引用其他切入点.

声明通知

在 aop Schema 中, 每种通知类型都对应一个特定的 XML 元素.

通知元素需要使用 来引用切入点, 或用 直接嵌入切入点表达式. method 属性指定切面类中通知方法的名称.

案例列举

	<!-- 第一步:通过注解把切面对象放到IOC容器中 -->
	<!-- 第二步:配置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="afterReturn" pointcut-ref="myPointCut1" returning="s"/>
		</aop:aspect>
	</aop:config>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值