Spring的学习(七):AOP
Spring的学习(七):AOP
yuhuan121 发表于4个月前
Spring的学习(七):AOP
  • 发表于 4个月前
  • 阅读 2
  • 收藏 0
  • 点赞 0
  • 评论 0

腾讯云 技术升级10大核心产品年终让利>>>   

1、定义

AOP(Aspect Orient Programming):面向切面编程,是OOP(Object Oriented Programming,面向对象编程)的一种补充,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。OOP将程序分解成各个层次的对象,从静态的角度来考虑程序结构;AOP是将程序的运行过程分为各个切面,从动态的角度考虑程序的运行过程。

2、为什么要用AOP呢?

先列几段代码: 定义一个接口

package org.crazyit.spring.aop.service;
public interface AritithmeticCalculator{
	int add(int i,int j);
	int sub(int i,int j);
	int mul(int i,int j);
	int div(int i,int j);
}

定义接口的实现类

package org.crazyit.spring.aop.service;

public class AritithmeticCalculatorImpl implements AritithmeticCalculator {

	@Override
	public int add(int i, int j) {
		System.out.println("加法开始["+i+","+j+"]");
		int result = i + j;
		System.out.println("加法结束"+result);
		return result;
	}

	@Override
	public int sub(int i, int j) {
		System.out.println("减法开始["+i+","+j+"]");
		int result = i - j;
		System.out.println("减法结束"+result);
		return result;
	}

	@Override
	public int mul(int i, int j) {
		System.out.println("乘法开始["+i+","+j+"]");
		int result = i * j;
		System.out.println("乘法结束"+result);
		return result;
	}

	@Override
	public int div(int i, int j) {
		System.out.println("除法开始["+i+","+j+"]");
		int result = i / j;
		System.out.println("除法结束"+result);
		return result;
	}
}

主程序

package org.crazyit.spring.aop.service;

public class Main {
	public static void main(String[] args){
		AritithmeticCalculator aritithmeticCalculator = new AritithmeticCalculatorImpl();
		int result = aritithmeticCalculator.add(1, 2);
		System.out.println("-->" + result);
		result = aritithmeticCalculator.div(5, 2);
		System.out.println("-->" + result);
	}
}

输出 输入图片说明 本例中每个方法开始结束之前都写了日志代码,且类似,每次都要写,很麻烦。而且,导致核心代码占得篇幅较小,造成了代码混乱且分散。越来越多的非业务需求(日志和验证等)加入后, 原有的业务方法急剧膨胀。 每个方法在处理核心逻辑的同时还必须兼顾其他多个关注点.。以日志需求为例, 只是为了满足这个单一需求, 就不得不在多个模块(方法)里多次重复相同的日志代码。如果日志需求发生变化, 必须修改所有模块。

AOP 的主要编程对象是切面(aspect), 而切面模块化横切关注点。 在应用 AOP 编程时,仍然需要定义公共功能, 但可以明确的定义这个功能在哪里, 以什么方式应用, 并且不必修改受影响的类。 这样一来横切关注点就被模块化到特殊的对象(切面)里。 AOP 的好处:

  • 每个事物逻辑位于一个位置, 代码不分散, 便于维护和升级
  • 业务模块更简洁, 只包含核心业务代码

AOP框架的特征:

  • 各步骤之间有良好的隔离性
  • 与源代码无关

可以使用AspectJ来实现AOP,它是基于Java语言的AOP框架。

3、基本概念

横切关注点:对哪些方法进行拦截,拦截后怎么处理;

切面(Aspect): 横切关注点被模块化的特殊对象;

目标(Target): 被通知的对象;

代理(Proxy): 向目标对象应用通知之后创建的对象;

连接点(Joinpoint):程序执行的某个特定位置:如类某个方法调用前、调用后、方法抛出异常后等。连接点由两个信息确定:方法表示的程序执行点;相对点表示的方位;

增强处理(Advice):AOP框架在特定的切入点执行的增强处理。这些处理的类型有“around”、“before"、”after“等类型;

切点(pointcut):可以插入增强处理的连接点;

织入(Weaving):将增强对象添加到目标对象中,并创建一个被增强的对象的过程;

AOP需要程序猿参与的只有三个部分:

  • 定义普通的业务组件;
  • 定义切入点,一个切入点可能横切好几个业务组件;
  • 定义增强处理

关于定义切入点和增强处理,可以用AspectJ来实现;具体可用两种方式:

  • 基于注解的“零配置“方式:使用@Aspect、@Pointcut等注解;
  • 基于XML配置文件的管理方式;

4、基于注解的“零配置“方式

在 Spring IOC 容器中启用 AspectJ 注解支持, 要在 Bean 配置文件中定义一个空的 XML 元素 <aop:aspectj-autoproxy>,当 Spring IOC 容器侦测到 它时, 会自动为与 AspectJ 切面匹配的 Bean 创建代理。

4.1、定义切面类

使用@Aspect标注一个Java类,这个类会作为切面类;当spring容器检测到某个类使用了此标注后,不会对该类进行增强处理。

//使用@Aspect定义一个切面类
@Aspect
public class LogAspect{
    ...
}

4.2、定义before增强处理

@Before一般用于一个切面类里,用于修饰一个方法,该方法作为Before增强处理。@Before一般有个value值,指定一个切入点表达式,用于指定该增强处理被用于那些切入点。

4.3、定义AfterReturning增强处理

AfterReturning增强处理将在目标方法正常完成后织入 @AfterReturning有两个属性:

  • point/value:指定该切入点对应的切入点表达式;
  • returning:指定一个形参名,表示Advice方法中可以定义同名的形参名,用于访问目标方法的返回值。在Advice方法中还要指定形参名对应的类型,限定目标方法必须返回指定的类型或无返回值。

4.4、定义AfterThrowing增强处理

用于处理程序中未处理的异常

@AfterThrowing也有两个属性

  • point/value:指定该切入点对应的切入点表达式;
  • throwing:指定一个形参名,表示Advice方法中可以定义同名的形参名,用于访问目标方法抛出的异常。在Advice方法中还要指定形参名对应的类型,限定目标方法必须抛出指定的异常。

4.5、定义After增强处理

和AfterReturning不同的是,AfterReturning只有在目标方法完成之后才会被织入;After不管目标方法怎样结束,都会被织入,包括成功完成和异常终止两种情况。用于处理程序中正常返回和异常返回两种情况。

@After也需要一个value属性,值可以是一个已有的切入点还可以是切入点表达式;

4.6、定义Around增强处理

功能较强大:既可以在执行目标方法之前织入增强动作,也可以在执行之后,也可以阻止目标方法的执行;可以改变目标方法的参数值,也可以改变它的返回值。

也需要一个value属性,值可以是一个已有的切入点还可以是切入点表达式;

4.7、定义切入点

两个部分

  • 切入点表达式:指定该切入点和哪些方法匹配;通常用@Pointcut标注
  • 切入点签名:包含名字和任意参数

例:@Pointcut("execution(* transfer(..))") 匹配任何名为transfer的方法的执行

4.8、切入点指示符

4.8.1、execution

用于匹配执行方法的连接点

格式:

execution(a? b c? d(e) f)
  • a:指定方法的修饰符,支持通配符,可省略;
  • b:指定方法的返回值类型,支持通配符,可以用* 代表所有类型
  • c:指定方法所属的类,支持通配符,可省略;
  • d:指定匹配指定的方法名,可用*代表全部;
  • e:方法的形参,支持两个通配符*和.. 前面代表所有,后面代表0个或多个
  • f:指定方法声明抛出的异常,可省略;

4.8.2、with

用于限定匹配特定类型的连接点;

4.8.3、this

用于限定AOP代理必须是指定类型的实例,匹配该对象的所有连接点;

4.8.4、target

用于限定目标对象必须是指定类型的实例,匹配该对象的所有连接点;

4.8.5、args

用于限定连接点的参数类型;

4.8.6、Bean

用于限定匹配特定Bean实例内的连接点,只能使用方法执行作为连接点;

4.8、组合切入点表达式

用三个逻辑运算符 && 、||、!

5、基于XML配置文件的管理方式

没有使用JDK1.5以上版本就要用这种

5.1、配置切面

用<aop:aspect.../>元素,有三个属性:

  • id :该切面的标识名
  • ref:用于将此属性所引用的普通Bean转换为切面Bean;
  • order:指定切面Bean的优先级,值越小优先级越高;

5.2、配置增强处理

<aop:before.../>、<aop:after.../>、<aop:after-returning.../>、<aop:after-throwing.../>、<aop:around.../> 有以下属性:

  • pointcut:指定一个切入点表达式;
  • pointcut-ref:指定一个已经确定存在的切入点名称;和上面一个属性两者使用其一;
  • method:指定一个方法名;
  • throwing:只对<aop:after-throwing.../>有效,指定一个形参名,AfterThrowing增强处理方法可以通过该形参访问目标方法抛出的异常;
  • returning:只对<aop:after-returning.../>有效,指定一个形参名,AfterReturning增强处理方法可以通过该形参访问目标方法的返回值;

5.3、配置切入点

用<aop:pointcut../>元素定义切入点,当它作为<aop:config../>元素的子元素时,表明该切入点可被多个切面共享;当它作为<aop:aspect../>元素的子元素时,表明该切入点只能在该切入点有效;

属性:

  • id:切入点的标识名;
  • expression:指定该切入点关联的切入点表达式;
共有 人打赏支持
粉丝 0
博文 36
码字总数 38704
×
yuhuan121
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: