Spring核心概念<二>:AOP面向切面编程
来源:互联网 发布:sopcast网络电视官网 编辑:程序博客网 时间:2024/06/06 23:58
Spring核心概念<二>:AOP面向切面编程
概述
AOP和OOP的区别:面向对象编程将程序分解为各个层次的对象,而面向切面编程将程序运行过程分解为各个切面。可以理解为oop是从静态角度考虑程序结构的,而aop是从动态角度考虑程序结构的。
AOP的来源:当有多个对象同时复用一段相同的代码段时,传统的使用方法调用的方式无法避免耦合,所以出现了aop实现不同调用方法与复用代码块之间的解耦合。Aop专门用于处理系统中分布于各个模块中的交叉关注点的问题,常常使用AOP来处理一些具有横切性质的系统级服务,如事务管理,安全检查,缓存,对象池管理等
AOP的目标:在不修改源代码的前提下,为系统多个组件的多个方法添加某种通用的功能。
AOP分类:静态aop(AspectJ),编译时增强/动态aop(Spring AOP)运行时增强
基本概念
aop代理:aop框架创建的对象,简单来说,代理就是对目标对象的增强。
织入(weaving):将增强处理添加到目标对象。根据使用框架的不同可以细分为运行时增强和编译时增强
AOP代理方法 = 增强处理 + 目标对象的方法
对于开发者来说,主要参与
定义普通业务组件
定义切入点,一个切入点可横切多个页面
定义增强处理
基于注解的“零配置”方式/xml配置方式
step1 启动Spring对@AspectJ的支持,需要在Spring配置文件中添加如下片段:
<?xml version="1.0" encoding="GBK"?><beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://www.springframework.org/schema/beans"xmlns:p="http://www.springframework.org/schema/p"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-4.0.xsd"><!-- 配置@AspectJ支持 --><aop:aspecj-autoproxy></beans>
step2 定义切面
@Aspectpublic class logPrint{……}
step3 增强处理
- 定义before增强处理:每次指向目标方法之前都会执行before增强处理方法
定义一个切面类
import org.aspectj.lang.annotation.*;import org.aspectj.lang.*;@Aspectpublic class AuthAspect{// 所有方法的执行作为切入点@Before("execution(* org.crazyit.app.service.impl.*.*(..))")public void authority(){ System.out.println("模拟执行权限检查");}}
定义一个普通方法
package org.crazyit.app.service.impl;import org.springframework.stereotype.Component;import org.crazyit.app.service.*;public class HelloImpl implements Hello{// 定义一个简单方法,模拟应用中的业务逻辑方法public void foo(){ System.out.println("执行Hello组件的foo()方法");}// 定义一个addUser()方法,模拟应用中的添加用户的方法public int addUser(String name , String pass){ System.out.println("执行Hello组件的addUser添加用户:" + name); return 20;}}
配置beans.xml
<?xml version="1.0" encoding="GBK"?><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-4.0.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.0.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-4.0.xsd"><!-- 指定自动搜索Bean组件、自动搜索切面类 --><context:component-scan base-package="org.crazyit.app.service ,org.crazyit.app.aspect"> <context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/></context:component-scan><!-- 启动@AspectJ支持 --><aop:aspectj-autoproxy/>
通过以上三个步骤,即:定义切面类,切入点和增强方法;定义普通组件;配置beans,就可以实现一个简单的before增强处理的aop配置
定义AfterReturning增强处理
定义AfterThrowing增强处理
After增强处理(注:与AfterReturning的区别在于,后者无论正常结束或者意外结束方法都会进行后处理)
-Aroud增强处理
可以看作是Before增强处理和AfterRerturning增强处理的总和,但是更强大,强大之处在于Around增强处理可以决定目标方法在什么时候处理,如何处理,甚至完全阻止目标方法的执行。它也可以改变目标方法的参数值和返回值
package org.crazyit.app.aspect;import org.aspectj.lang.annotation.*;import org.aspectj.lang.*;// 定义一个切面@Aspectpublic class TxAspect{// 匹配org.crazyit.app.service.impl包下所有类的、// 所有方法的执行作为切入点@Around("execution(* org.crazyit.app.service.impl.*.*(..))")public Object processTx(ProceedingJoinPoint jp) throws java.lang.Throwable{ System.out.println("执行目标方法之前,模拟开始事务..."); // 获取目标方法原始的调用参数 Object[] args = jp.getArgs(); if(args != null && args.length > 1) { // 修改目标方法的第一个参数 args[0] = "【增加的前缀】" + args[0]; } // 以改变后的参数去执行目标方法,并保存目标方法执行后的返回值 Object rvt = jp.proceed(args); System.out.println("执行目标方法之后,模拟结束事务..."); // 如果rvt的类型是Integer,将rvt改为它的平方 if(rvt != null && rvt instanceof Integer) rvt = (Integer)rvt * (Integer)rvt; return rvt; }}
如上所示,Spring的第一个参数一定是ProceedingJoinPoint jp,通过他可以取得目标对象[包括通过getArgs()取得参数,通过proceed()取得返回值];调用它的procees()方法,目标方法才会被执行 。
取得目标方法的参数 主要包括三个方法Object[] getArgs()/Signature getSignature()/Object getTarget() 分别表示取得目标对象的参数,取得目标对象的签名,取得被增强的目标对象
package org.crazyit.app.aspect;import org.aspectj.lang.annotation.*;import org.aspectj.lang.*;import java.util.Arrays;@Aspectpublic class FourAdviceTest{// 定义Around增强处理@Around("execution(* org.crazyit.app.service.impl.*.*(..))")public Object processTx(ProceedingJoinPoint jp) throws java.lang.Throwable{ System.out.println("Around增强:执行目标方法之前,模拟开始事务..."); // 访问执行目标方法的参数 Object[] args = jp.getArgs(); // 当执行目标方法的参数存在, // 且第一个参数是字符串参数 if (args != null && args.length > 0 && args[0].getClass() == String.class) { // 修改目标方法调用参数的第一个参数 args[0] = "【增加的前缀】" + args[0]; } //执行目标方法,并保存目标方法执行后的返回值 Object rvt = jp.proceed(args); System.out.println("Around增强:执行目标方法之后,模拟结束事务..."); // 如果rvt的类型是Integer,将rvt改为它的平方 if(rvt != null && rvt instanceof Integer) rvt = (Integer)rvt * (Integer)rvt; return rvt;}// 定义Before增强处理@Before("execution(* org.crazyit.app.service.impl.*.*(..))")public void authority(JoinPoint jp){ System.out.println("Before增强:模拟执行权限检查"); // 返回被织入增强处理的目标方法 System.out.println("Before增强:被织入增强处理的目标方法为:" + jp.getSignature().getName()); // 访问执行目标方法的参数 System.out.println("Before增强:目标方法的参数为:" + Arrays.toString(jp.getArgs())); // 访问被增强处理的目标对象 System.out.println("Before增强:被织入增强处理的目标对象为:" + jp.getTarget());}//定义AfterReturning增强处理@AfterReturning(pointcut="execution(* org.crazyit.app.service.impl.*.*(..))" , returning="rvt")public void log(JoinPoint jp , Object rvt){ System.out.println("AfterReturning增强:获取目标方法返回值:" + rvt); System.out.println("AfterReturning增强:模拟记录日志功能..."); // 返回被织入增强处理的目标方法 System.out.println("AfterReturning增强:被织入增强处理的目标方法为:" + jp.getSignature().getName()); // 访问执行目标方法的参数 System.out.println("AfterReturning增强:目标方法的参数为:" + Arrays.toString(jp.getArgs())); // 访问被增强处理的目标对象 System.out.println("AfterReturning增强:被织入增强处理的目标对象为:" + jp.getTarget());}// 定义After增强处理@After("execution(* org.crazyit.app.service.impl.*.*(..))")public void release(JoinPoint jp){ System.out.println("After增强:模拟方法结束后的释放资源..."); // 返回被织入增强处理的目标方法 System.out.println("After增强:被织入增强处理的目标方法为:" + jp.getSignature().getName()); // 访问执行目标方法的参数 System.out.println("After增强:目标方法的参数为:" + Arrays.toString(jp.getArgs())); // 访问被增强处理的目标对象 System.out.println("After增强:被织入增强处理的目标对象为:" + jp.getTarget()); }}
step4 指定不同切面类里增强处理的优先级
让切面实现org.springframework.core.Ordered接口,实现给该接口只需实现一个int getOrder()方法
直接时候Order注解来修饰一个切面类,指定一个int型的value属性最为优先级,该属性越小优先级越高
step5 定义切入点:切入点的定义包含两个部分 切入点表达式+包含任意名字和参数的方法签名
@PointCut("execution(* transfer(..))") private void anyOldTransfer(){}
上面定义了一个名为anyOlderTransfer的切入点,可以匹配任何以transfer结尾的方法
@AfterReturning(pointcut="anyOldTransfer()",returning="retval")public void writing(String msg,Object retval){...}
step6 切入点指示符
execution匹配执行方法连接点
within用于限定匹配特定类型的连接点
this用于限定aop代理必须是制定类型的实例
target用于限定目标对象必须是指定类型的实例
args用于对连接点参数类型进行限制
step7 组合切入点 :&& || ! 分别表示与或非
- Spring核心概念<二>:AOP面向切面编程
- 【Spring 核心】AOP 面向切面编程
- Spring核心AOP(面向切面编程)
- Spring核心AOP(面向切面编程)总结
- Spring核心机制(面向切面编程AOP)
- Spring核心机制(面向切面编程AOP)详解
- java Spring AOP 面向切面编程 概念辅助理解记忆
- spring面向切面编程(aop)
- Spring AOP 面向切面编程
- Spring AOP 面向切面编程
- Spring面向切面编程AOP
- Spring AOP(面向切面编程)
- Spring AOP面向切面编程
- Spring 面向切面编程AOP
- Spring面向切面编程AOP
- Spring AOP面向切面编程
- Spring AOP面向切面编程
- spring aop面向切面编程
- 设计模式汇总
- mybatis foreach多次遍历问题
- C
- Fetch / ajax 不能获取response中的所有headers的解决方法(适用nginx)
- 括号的匹配问题
- Spring核心概念<二>:AOP面向切面编程
- cvc-complex-type.2.3: Element 'web-app' cannot have character [children], because the type's content
- mybatis
- Android窗口管理分析(1):View如何绘制到屏幕上的主观理解
- OpenCV Error: Unspecifiederror 解决
- Linux 运维面试笔试
- 微信小程序---蓝牙连接开发总结
- c#数据类型
- FSM(状态机)、HFSM(分层状态机)、BT(行为树)的区别