Spring AOP的使用及源码解读 (一)

前言

AOP[底层是动态代理]为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。(百度百科的解释)
其实按通俗话理解就是对我们的方法进行增强。也就是在我们执行方法的前,后,结束返回等情况增加相应的通知(在Java中的表现就是相应的控制台打印)

1.创建相关AOP的应用实例(如何用?)

我们编写相关spring AOP的实例的时候,首先要编写一个业务类如Calculator(这个类就是我们要进行切面增强的类),还有一个相关的切面类如LogAspects (这个类主要是对我们业务类的方法进行增强)和一个最重要的配置类如Cap10MainConfig(对相关bean注入的一个声明)

(1)记得在编写前导入相应的依赖(在Maven工程中的pom.xml下)

 <!-- 使用AOP需要导入 -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aspects</artifactId>
			<version>5.0.6.RELEASE</version>
	  </dependency>

(2)编写业务类(Calculator.class)

package com.enjoy.cap10.aop;
public class Calculator {
	
	//业务逻辑方法
	public int div(int i, int j) {
		System.out.println("---------");
		return i/j;
	}
}

(3)编写一个切面类 (LogAspects.class)

这个类主要是对我们的业务类进行增强(简单的说就是在我们执行Calculator 类下的div()方法时,在它执行前,执行后,执行正常返回等情况下对于我们开发人员进行相关的通知,也就是相关的控制台打印提醒)

package com.enjoy.cap10.aop;

import java.util.Arrays;

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.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

//日志切面类
@Aspect
public class LogAspects {
    //对我们所要增强类的路径进行声明
	@Pointcut("execution(public int com.enjoy.cap10.aop.Calculator.*(..))")
	public void pointCut() {};
	
	//@before代表在目标方法执行前切入,并指定在哪个方法切入
	@Before("pointCut()")
	public void logStart(JoinPoint joinPoint) {
		System.out.println(joinPoint.getSignature().getName()+"除法运行...参数列表是:{"+Arrays.asList(joinPoint.getArgs())+"}");
	}
	@After("pointCut()")
	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 = "pointCut()",throwing="exception")
	public void logException(Exception exception) {
		System.out.println("运行异常....异常信息是:{"+exception+"}");
	}

	@Around("pointCut()")
	public Object Around(ProceedingJoinPoint procedingJoinPoint) {
		Object obj = null;
		System.out.println("@Around:执行方法之前");
		try {
			obj = procedingJoinPoint.proceed();
		} catch (Throwable e) {
			e.printStackTrace();
		}
		System.out.println("@Around:执行方法之后");
		return obj;
		
	}

}

解释说明: AOP通知方法
注:div是自己定义的一个普通方法
[1]前置通知:logStart( ),在目标方法( div )运行之前运行(@Before)
[2]后置通知: logEnd( ),在目标方法( div )运行结束之后运行,无论正常或异常结束(@After)
[3]返回通知:loginReturn, 在目标方法(div)正常返回之后运行(@AfterReturning)
[4]异常通知: loginException 在目标方法(div)出现异常后运行( @AfterThrowing)
[5]环绕通知:动态代理,需要手动执行joinPoint.procced(), (@Around)
(其实就是执行我们的目标方法div( ) ) 执行之前相当于前置通知,执行之后相当于后置通知

(4)编写主配置类(Cap10MainConfig.class)

package com.enjoy.cap10.config;

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

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

/**
 * 日志切面类的方法需要动态感知 div( )这个方法的运行
 * 通知方法:
 *    前置通知: logStart();在我们执行div()除法之前运行 (@Before)
 *    后置通知: logEnd();在我们目标方法div()运行结束之后,不管有没有异常(@After)
 *    返回通知: logReturn();在我们的目标方法div()正常返回后运行(@AfterReturning)
 *    异常通知:logException();在我们的目标方法div()出现异常后运行(@AfterThrowing)
 *    环绕通知: 动态代理,需要手动执行joinPoint.procced(), (@Around)
 *    (其实就是执行我们的目标方法div(),) 执行之前相当于前置通知,执行之后相当于后置通知
 *
 */
@Configuration   //向Spring声明这是一个注解类
@EnableAspectJAutoProxy   //开启切面事务
public class Cap10MainConfig {
@Bean    //想关bean的注入
	public Calculator calculator() {
	   return new Calculator();
	}
	@Bean
	public LogAspects logAspects() {
	     return new LogAspects();
	}
}

(5)最后我们简单的编写一个测试类

import org.junit.Test;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.enjoy.cap10.aop.Calculator;
import com.enjoy.cap10.config.Cap10MainConfig;


public class Cap10Test {
@Test
public void test01() {
	      //进行相应配置类的读取
		AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap10MainConfig.class);
		      //获取相应bean实例的获取		
		Calculator c = app.getBean(Calculator.class);
		int result = c.div(4, 2);
		System.out.println(result);
		app.close();
		
	}
}

运行结果:(从截图我们可以看出在执行div()这个方法的前后,控制台多了一些相关语句的打印,这也就是我们使用AOP最常用的方式—对我们进行相关方法的日志通知)
在这里插入图片描述

发布了41 篇原创文章 · 获赞 2 · 访问量 1992

猜你喜欢

转载自blog.csdn.net/TheWindOfSon/article/details/104202681