Spring源码分析(十二) - Aop基础

AOP: 面向切面编程[底层就是动态代理]

指程序在运行期间动态的将某段代码切入到指定方法位置进行运行的编程方式

先建立Cap10MainConfigAop配置类

在POM.XML中导入spring-aspects依赖包

新建立一个业务逻辑类Calculator.java

package com.caojiulu.cap10.aop;

//业务逻辑类
public class Calculator {

	public int div(int i,int j){
		return i/j;
	}
}

在div()方法运行之前, 记录一下日志, 运行后也记录一下,运行出异常,也打印一下

但这样会有问题, 这种方式耦合了

新建一个日志切面类

package com.caojiulu.cap10.aop;

import java.util.Arrays;

import org.aopalliance.intercept.Joinpoint;
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;

//日志切面类
@Aspect
public class LogAspects {
	
	
	@Pointcut("execution (public int com.caojiulu.cap10.aop.Calculator.*(..))")
	public void pointCut(){
		
	}

	// 不想区分是哪个方法加*
	//@Before("execution public int com.caojiulu.cap10.aop.Calculator.div(int , int))")
	@Before("execution ( public  int com.caojiulu.cap10.aop.Calculator.*(..))")
	public void logStart(JoinPoint joinPoint){
		System.out.println(joinPoint.getSignature().getName()+"除法运行。。。参数列表是:{"+Arrays.asList(joinPoint.getArgs())+"}");
	}
	//after 方法无论是正常结束,还是异常结束,都会调用
	@After("execution ( public int com.caojiulu.cap10.aop.Calculator.div(int ,int ))")
	public void logEnd(JoinPoint joinPoint){
		System.out.println(joinPoint.getSignature().getName()+"除法结束。。。。");
	}
	@AfterReturning(value ="pointCut()",returning="result")
	public void logReturn(Object result){
		System.out.println("除法正常返回。。运行结果是:{"+result+"}");
	}
	@AfterThrowing(value="com.caojiulu.cap10.aop.LogAspects.pointCut()",throwing="exceptio")
	public void logException(Exception exceptio){
		System.out.println("除法异常。。异常信息是{"+exceptio+"}");
	}
	
	/*@Around("pointCut()")
	public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
		System.out.println("around:执行目标方法之前。。。");
		Object obj = proceedingJoinPoint.proceed();
		System.out.println("around:执行目标方法之后。。。");
		return obj;
	}*/
	
}

日志切面类的方法需要动态感知到div()方法运行到哪里了, 然后再执行, 如果除法开始, 就日志开始方法,

也叫通知方法, 分以下几种:

前置通知: logStart(),在目标方法(div)运行之前运行 (@Before)

后置通知:logEnd(), 在目标方法(div)运行结束之后运行,无论正常或异常结束 (@After)

返回通知:logReturn, 在目标方法(div)正常返回之后运行 (@AfterReturning)

异常通知:logException, 在目标方法(div)出现异常后运行(@AfterThrowing)

环绕通知:以上没写,动态代理, 手动执行目标方法运行joinPoint.procced(),最底层通知,手动指定执行目标方法(@Around), 执行之前相当于前置通知, 执行之后相当于返回通知

其实就是通过反射执行目标对象的连接点处的方法

给配置类中加@EnableAspectJAutoProxy[一定得加上,关键]

注意: 在spring以后会有很多@EnableXXXX, 表示开启某项功能, 取代XML配置

package com.caojiulu.cap10.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

import com.caojiulu.cap10.aop.Calculator;
import com.caojiulu.cap10.aop.LogAspects;

@Configuration
@EnableAspectJAutoProxy
public class Cap10MainConfigAop {
	@Bean
	public Calculator calculator(){
		return new Calculator();
	}
	@Bean
	public LogAspects logAspects(){
		return new LogAspects();
	}

}

测试类:

package com.caojiulu.cap10.config;

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.caojiulu.cap10.aop.Calculator;

public class Cap10Test {
	
	@Test
	public void test01(){
		AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap10MainConfigAop.class);
	
		Calculator calculator = app.getBean(Calculator.class);
	
		int div = calculator.div(4,2);
		System.out.println(div);
		app.close();
	}

}

运行结果:

div除法运行。。。参数列表是:{[4, 2]}
div除法结束。。。。
除法正常返回。。运行结果是:{2}
2

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值