Spring学习(谷粒学院spring4课程)第六节 AOP

一:采用AOP的原因

代码混乱:越来越多的非业务需求(日志和验证等)加入后, 原有的业务方法急剧膨胀.  每个方法在处理核心逻辑的同时还必须兼顾其他多个关注点.

代码分散: 以日志需求为例, 只是为了满足这个单一需求, 就不得不在多个模块(方法)里多次重复相同的日志代码. 如果日志需求发生变化, 必须修改所有模块.

二:基于aspectj注解声明切面

实例:定义一个bean,为其添加日志

(1)定义一个bean

import org.springframework.stereotype.Component;

@Component
public class Student {
private String name;
public void setName(String name) {
	this.name = name;
}
public int study(int i,int j) {
	// TODO Auto-generated method stub
System.out.println("good study");
return i/j;
}
}

(2)创建切面及通知

package com.wh.spring.impl;

import java.util.Arrays;
import java.util.List;

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.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
//把这个类声明为一个切面,需要把该类放入到IOC容器中,再声明为一个切面
//使用@Order指定切面的优先级,数值越小,优先级越高
@Aspect
@Order(1)
@Component
public class LoggingAspect {
	
	//定义一个方法,用于声明切入点表达式,一般该方法不需要填入其他代码
	//使用@Pointcut声明切入点表达式
	//其他通知引用方法名引入该切入点
	@Pointcut("execution(* com.wh.spring.aop.Student.*(..))")
	public void declareJointPointExpression() {
		
	}
    //声明该方法是一个前置通知
	//spring..表示com.wh.spring包及其子包
	@Before("declareJointPointExpression()")
	public void beforeMethord(JoinPoint joinPoint) {
		String methordName=joinPoint.getSignature().getName();
		List<Object> args=Arrays.asList(joinPoint.getArgs());
		System.out.println("the methord before "+methordName+" "+args);
	}
	//后置通知:在目标方法执行后(无论是否发生异常),执行的通知
	//后置通知中不能访问目标方法的执行结果
	@After("declareJointPointExpression()")
	public void afterMethord(JoinPoint joinPoint) {
		String methordName=joinPoint.getSignature().getName();
		System.out.println("The methord "+methordName+" ends");
		
	}
	
	//返回通知,方法正常结束后执行的代码
	//返回通知是可以访问到方法的返回值
	@AfterReturning(value="declareJointPointExpression()",
			returning="result")
	public void afterReturning(JoinPoint joinPoint,Object result) {
		String methordName=joinPoint.getSignature().getName();
		System.out.println("The methord "+methordName+" ends with "+result);
	}
	
	
	//在目标方法出现异常时会执行该代码,可以访问到异常对象,且可以指定在出现指定异常时才执行通知代码
	//指定ex的类型
	@AfterThrowing(value="declareJointPointExpression()",
			throwing="ex")
	public void afterThrowing(JoinPoint joinPoint,Exception ex) {
		String methordName=joinPoint.getSignature().getName();
		System.out.println("The methord "+methordName+" throw "+ex);
	}
	
	
	//环绕通知需要携带ProceedingJoinPoint类型的参数
	//环绕通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行目标方法,且环绕通知必须有返回值
	//返回值即为目标方法的返回值
	//不常用环绕通知
	@Around("declareJointPointExpression()")
	public Object aroundMethord(ProceedingJoinPoint pjd) {
		System.out.println("aroundMethord");
		Object result=null;
		String methordName=pjd.getSignature().getName();
		//执行目标方法 
		try {
			//前置通知
			System.out.println(methordName+" begins with "+Arrays.asList(pjd.getArgs()));
			result=pjd.proceed();			
			//返回通知
			System.out.println(methordName+" ends with "+result);
			
		} catch (Throwable e) {
			// 异常通知
			System.out.println("发生异常:"+e);
		}
       // 后置通知
		System.out.println("the methord "+methordName+" ends with around");
		return 100;
	}
	
}

(3)使aspectj注解起作用,自动为匹配的类生成代理对象

在spring配置文件中加入

<!-- 使aspectj注解起作用,自动为匹配的类生成代理对象 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

三:基于配置文件的AOP

(1)配置切面bean

<!-- 配置切面的bean-->
<bean id="loggingAspect" class="com.wh.spring.xml.LoggingAspect"></bean>

(2)配置切点,切面及通知

<aop:config>
<!-- 配置切点表达式 -->
<aop:pointcut expression="execution(* com.wh.spring.xml.Student.*(..))" id="pointcut"/>
<!-- 配置切面及通知 -->
<aop:aspect ref="loggingAspect" order="0">
<aop:before method="beforeMethord" pointcut-ref="pointcut"/>
<aop:after method="afterMethord" pointcut-ref="pointcut"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="ex"/>
<aop:after-returning method="afterReturning" pointcut-ref="pointcut" returning="result"/>
<aop:around method="aroundMethord" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>

四:其他

(1)切面的顺序由@Order(1)或order="0"指定,数字越小,优先级越高

(2)切点的重用

//定义一个方法,用于声明切入点表达式,一般该方法不需要填入其他代码
	//使用@Pointcut声明切入点表达式
	//其他通知引用方法名引入该切入点
	@Pointcut("execution(* com.wh.spring.aop.Student.*(..))")
	public void declareJointPointExpression() {
		
	}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值