Spring框架之AOP面向切面编程

AOP面向切面编程
AOP(Aspect-Oriented Programming,面向切面编程):是一种新的方法论,是对传统OOP(Object-Oriented Programming,面向对象编程)的补充。
AOP编程时,仍然需要定义公共功能,但可以明确的定义这个功能在哪里,以什么方式应用,并且不必修改受影响的类。这样一来横切关注点就被模块化到特殊的对象(切面)里(aspect).
AOP的好处:
每个事物逻辑位于一个位置,代码不分散,便于维护和升级
业务模块更简洁,只包含核心业务代码
横切关注点:
会出现如下的问题:
1.代码混乱:越来越多的非业务需求(日志和验证等)加入后,原有的业务方法几句膨胀。每个方法在处理核心逻辑的同时还必须兼顾其他多个关注点
2.代码分散:以日志需求为例,只是为了满足这个单一需求,就不得不在多个模块(方法)里多次重复相同的日志代码。如果日志需求发生变化,必须修改所有模块。
其中可以同过使用动态代理解决问题:
代理设计模式的原理:使用一个代理将对象包装起来,然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。

AOP面向切面编程的使用:
用Aspect注解声明切面
切面:带有@Aspect注解的java类
通知:是标注有以下5种注解的简单的java方法
@Before:前置通知,在方法执行之前执行
@After:后置通知,在方法执行之后执行
@AfterRunning:返回通知,在方法返回结果之后执行
@AfterThrowing:异常通知,在方法抛出异常之后
@Around:环绕通知,围绕着方法执行
AOP的流程:
1.导入包(四个)
2.在XML中配置文件(AOP的命名空间)、扫描包、自动代理(使@Aspect注解发挥作用)
3.在切面类上加@Aspect注解
4.java方法上加5种注解(其中的一种)
利用方法签名编写Aspect切入点表达式:

例如:
加减乘除方法的AOP应用实例:
在applicationContext-aop.xml中配置信息
	<!-- 自动扫描 -->
	<context:component-scan base-package="com.jredu.aop">
	</context:component-scan>
	<!-- AOP的自动代理:使aspect注解发挥作用 -->
	<aop:aspectj-autoproxy>
	</aop:aspectj-autoproxy>
算法接口:
package com.jredu.aop.service;

public interface ArithmeticCalculator {
	double add(double a,double b);
	double sub(double a,double b);
	double mul(double a,double b);
	double div(double a,double b);
}
算法接口的实现类:
package com.jredu.aop.service.impl;
import org.springframework.stereotype.Component;
import com.jredu.aop.service.ArithmeticCalculator;

@Component("arith")
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
	@Override
	public double add(double a, double b) {
		// TODO Auto-generated method stub
		System.out.println("=====================");
		return a+b;
	}
	@Override
	public double sub(double a, double b) {
		// TODO Auto-generated method stub
		return a-b;
	}
	@Override
	public double mul(double a, double b) {
		// TODO Auto-generated method stub
		return a*b;
	}
	@Override
	public double div(double a, double b) {
		// TODO Auto-generated method stub
		return a/b;
	}
}
切面(5中实现方式)
package com.jredu.aop.aspect;

import org.aspectj.lang.JoinPoint;
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.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * 切面
 * @author Administrator
 *
 */
@Aspect
@Component
@Order(1)//优先级:数值越小优先级越高
public class LogAspect {	
	/**
	 * 切面的方法:匹配com.jredu.aop.service的所有接口或类,当中至少包含一个double类型参数的sub方法
	 * @param point
	 */
	@Before("execution(public double com.jredu.aop.service.*.*(double,..))")
	public void test(JoinPoint point){
		String methodName=point.getSignature().getName();
		double a = (double) point.getArgs()[0];
		System.out.println("有一个double类型参数的方法:"+methodName+"的double类型参数a="+a);
	}	
	/**
	 * 当目标方法执行之前调用的切面方法
	 * @param point
	 */
	//前置日志
	@Before("execution(public double com.jredu.aop.service.*.*(double,double))")
	public void beforelog(JoinPoint point){
		//方法名字
		String methodName = point.getSignature().getName();
		//参数列表
		double a = (double) point.getArgs()[0];
		double b = (double) point.getArgs()[1];
		System.out.println("before----方法:"+methodName+"的参数a="+a+",b="+b);
	}
	
	//后置日志
	@After("execution(public double com.jredu.aop.service.*.*(double,double))")
	public void afterlog(JoinPoint point){
		//方法名字
		String methodName=point.getSignature().getName();
		//返回结果
		System.out.println("after----方法:"+methodName);		
	}
	
	/**
	 * 当方法执行完毕并返回结果之后的切面方法
	 */
	@AfterReturning(pointcut="execution(* com.jredu.aop.service.*.*(..))",returning="obj")
	public void afterReturning(JoinPoint point,Object obj){
		//方法名
		String method=point.getSignature().getName();
		System.out.println("after return ----- method:"+method+",return:"+obj);
	}
	
	/**
	 * 当目标方法抛出异常时会执行的方法
	 * @param point
	 * @param ex
	 */
	@AfterThrowing(pointcut="execution(* com.jredu.aop.service.*.*(..))",throwing="ex")
	public void afterThrowing(JoinPoint point,Exception ex){
		String method = point.getSignature().getName();
		System.out.println("after throw ----- method:"+method+",return:"+ex.getLocalizedMessage());
	}
	
	/**
	 * 当目标方法执行前和执行后会执行该方法(环绕方法)
	 * @param point
	 * @throws Throwable 
	 */
	@Around("execution(* com.jredu.aop.service.*.*(..))")
	public double around(ProceedingJoinPoint point) throws Throwable{
		//执行目标方法前
		String method = point.getSignature().getName();
		System.out.println("before method:"+method);		
		double d= (double) point.proceed();
		//执行目标方法后,返回结果前
		System.out.println("返回值是:"+d);
		//调用proceed方法,可以分割前后
		System.out.println("after method:"+method);		
		return d;//最后确定要返回的值
	}
}
测试类:
package com.jredu.aop.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.jredu.aop.service.ArithmeticCalculator;

public class AopTest {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext-aop.xml");
		ArithmeticCalculator calculator = (ArithmeticCalculator) app.getBean("arith");
		calculator.add(5,15);
		calculator.sub(5,15);
		calculator.mul(5,15);
		calculator.div(5,15);		
	}
}
指定切面的优先级:Order
在同一个连接点上应用不止一个切面时,除非明确指定,否则它们的优先级是不确定的。
切面的优先级可以通过实现Ordered接口或利用@Order注解指定。
实现Ordered接口,getOrder()方法 返回值越小,优先级越高。
若使用@Order注解,序号出现在注解中

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值