文档章节

Spring学习笔记002 - AOP

Pickacat
 Pickacat
发布于 2017/01/16 18:03
字数 1381
阅读 11
收藏 0

一、AOP的几个概念

1、Aspect,表示切面功能

配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
	http://www.springframework.org/schema/aop
	http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">

	<!-- 启用AOP配置 -->
	<aop:aspectj-autoproxy />

</beans>

定义Aspect:在XML中定一个切面功能的bean,同时在对应的bean上添加@Aspect注解

<bean id="loggingAspect" class="com.xiaol.study.LoggingAspect">
</bean>
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class LoggingAspect{

}

 

2、Pointcut,用于定义哪些函数要执行切面功能

@Pointcut("execution(* com.xiaol.study.Caculator.*(..))")
private void arithmetic()

execution(* com.xiaol.study.Caculator.*(..))表达式用于匹配执行切面功能的方法。

arithmetic相当于是这个表达式的一个名称,可以在其他地方被引用。

Pointcut表达式解析:

designator(modifiers? return-type declaring-type? name(param) throws?)

designator:

    execution表示函数执行过程,

    within表示某个包或者类下执行的函数

modifiers:访问修饰符,public、private等

return-type:返回类型,可以使用通配符*

declaring-type:包名,类名

name:函数名

param:参数列表,()表示无参,(..)表示任意参数

throws:异常类型

其中末尾带有?的都是可选项,不写也可以。

 

3、Advice,表示执行函数的某个点,也就是被Pointcut匹配到的方法执行到哪个点时去执行切面功能

定义Advice:可以直接写Pointcut的名称,也可以写Pointcut表达式。

// Pointcut名称
@Before("com.xiaol.study.LoggingAspect.arithmetic()")
public void doLog(){

}

// Pointcut表达式
@Before("execution(* com.xiaol.study.Caculator.*(..))")
public void doLog(){

}

 

Advice类型:

    @Before,在函数执行前

    @AfterReturning,函数正常返回之后

    @AfterThrowing,函数抛出异常之后

    @After,函数返回之后(无论是否有异常)

    @Around,函数执行前后

 

Advice参数:除了Around使用ProceedingJoinPoint,其他都使用JoinPoint从中获得上下文信息。

@Before("com.xiaol.study.LoggingAspect.arithmetic()")
public void doLog(JoinPoint jp){
    System.out.println(jp.getSignature() + "," + jp.getArgs());
}

@Around("com.xiaol.study.LoggingAspect.arithmetic()")
public Object doLog(ProceedingJoinPoint pjp){
    System.out.println("start : " + pjp.toString());
    Object retVal = pjp.proceed();
    System.out.println("end : " + pjp.toString());
    return retVal;
}

 

Advice获取返回值:

@AfterReturning(
    pointcut="com.xiaol.study.LoggingAspect.arithmetic()",
    returning="retVal")
public void doLog(Object retVal){
    // do something
}

 

Advice获取异常类型:可以根据需要获取对应异常类型

@AfterReturning(
    pointcut="com.xiaol.study.LoggingAspect.arithmetic()",
    throwing="ex")
public void doLog(Execption ex){
    // do something
}

 

Advice获取函数参数:(a, ..)表示第一个参数变量名叫a,之后..表示任意个参数

@Before("com.xiaol.study.LoggingAspect.arithmetic() && args(a, ..)")
public void doLog(JoinPoint jp, int a){
    // do something
}

 

 

二、AOP例子 - 基于注解

1、编写需要添加(切面功能)日志功能的类TeacherService

package com.xiaol.aop;

public class TeacherService {

	public boolean saveTeacher(Teacher teacher) throws Exception {
		if (teacher.getTeacherID() < 0) {
			throw new Exception("教师编号异常");
		}
		return true;
	}

	public boolean deleteTeacher(int teacherID) {
		return true;
	}

	public boolean findTeacher(Teacher teacher) {
		return true;
	}

	public boolean modifyTeacher(Teacher teacher) {
		return true;
	}
}

 

2、实现(切面功能)日志功能类MyLoggingAspect

package com.xiaol.aop;

import java.util.Arrays;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class MyLoggingAspect {

	/**
	 * 函数正常执行后输出日志
	 */
	@AfterReturning("execution(public boolean com.xiaol.aop.*.*(..))")
	private void normalLog(JoinPoint jp) {
		System.out.println("正常返回,函数签名[" + jp.getSignature() + "],参数值" + Arrays.toString(jp.getArgs()));
	}

	/**
	 * 函数执行异常时输出日志
	 */
	@AfterThrowing("execution(public boolean com.xiaol.aop.*.*(..))")
	private void exceptionLog(JoinPoint jp) {
		System.err.println("抛出异常,函数签名[" + jp.getSignature() + "],参数值" + Arrays.toString(jp.getArgs()));
	}

	/**
	 * 执行前后输出日志
	 * 
	 * @throws Throwable
	 */
	@Around("execution(public boolean com.xiaol.aop.*.*(..))")
	private Object beforeExecuteLog(ProceedingJoinPoint pjp) throws Throwable {

		System.out.println("函数执行前,函数签名[" + pjp.toString() + "],参数值" + Arrays.toString(pjp.getArgs()));

		Object retVal = pjp.proceed(pjp.getArgs());

		System.out.println("函数正常调用返回后,函数签名[" + pjp.toString() + "],返回值[" + retVal + "]");
		return retVal;
	}
}

 

3、定义bean

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
	http://www.springframework.org/schema/aop
	http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">

	<!-- 启用AOP配置 -->
	<aop:aspectj-autoproxy />

	<bean id="myLoggingAspect" class="com.xiaol.aop.MyLoggingAspect"></bean>
	
	<bean id="teacherService" class="com.xiaol.aop.TeacherService"></bean>
</beans>

 

4、编写测试类

package com.xiaol.aop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestAop {
	public static void main(String[] args) throws Exception {
		ApplicationContext context = new ClassPathXmlApplicationContext("application-context-unittest.xml");

		TeacherService teacherService = context.getBean("teacherService", TeacherService.class);
		Teacher teacher = new Teacher();
		teacher.setCourse("化学");
		teacher.setName("刘强");
		teacher.setTeacherID(-1);
		teacherService.deleteTeacher(3);
//		teacherService.modifyTeacher(teacher);
//		teacherService.findTeacher(teacher);
//		teacherService.saveTeacher(teacher);

		((ConfigurableApplicationContext) context).close();
	}
}

测试deleteTeacher方法,结果:

函数执行前,函数签名[execution(boolean com.xiaol.aop.TeacherService.deleteTeacher(int))],参数值[3]
函数正常调用返回后,函数签名[execution(boolean com.xiaol.aop.TeacherService.deleteTeacher(int))],返回值[true]
正常返回,函数签名[boolean com.xiaol.aop.TeacherService.deleteTeacher(int)],参数值[3]

测试saveTeacher方法,结果:

函数执行前,函数签名[execution(boolean com.xiaol.aop.TeacherService.saveTeacher(Teacher))],参数值[Teacher [teacherID=-1, name=刘强, course=化学]]
抛出异常,函数签名[boolean com.xiaol.aop.TeacherService.saveTeacher(Teacher)],参数值[Teacher [teacherID=-1, name=刘强, course=化学]]
Exception in thread "main" java.lang.Exception: 教师编号异常

 

三、AOP例子 - 基于XML配置

1、编写需要添加(切面功能)日志功能的类TeacherService,参见基于注解的编写

 

2、实现(切面功能)日志功能类MyLoggingAspect

package com.xiaol.aop;

import java.util.Arrays;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

public class MyLoggingAspect {

	/**
	 * 函数正常执行后输出日志
	 */
	private void normalLog(JoinPoint jp) {
		System.out.println("正常返回,函数签名[" + jp.getSignature() + "],参数值" + Arrays.toString(jp.getArgs()));
	}

	/**
	 * 函数执行异常时输出日志
	 */
	private void exceptionLog(JoinPoint jp) {
		System.err.println("抛出异常,函数签名[" + jp.getSignature() + "],参数值" + Arrays.toString(jp.getArgs()));
	}

	/**
	 * 执行前后输出日志
	 * 
	 * @throws Throwable
	 */
	private Object beforeExecuteLog(ProceedingJoinPoint pjp) throws Throwable {

		System.out.println("函数执行前,函数签名[" + pjp.toString() + "],参数值" + Arrays.toString(pjp.getArgs()));

		Object retVal = pjp.proceed(pjp.getArgs());

		System.out.println("函数正常调用返回后,函数签名[" + pjp.toString() + "],返回值[" + retVal + "]");
		return retVal;
	}
}

 

3、配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
	http://www.springframework.org/schema/aop
	http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">

	<!-- 当使用AOP的XML配置时aspectj-autoproxy不需要 -->
	<!-- <aop:aspectj-autoproxy /> -->

	<bean id="myLoggingAspect" class="com.xiaol.aop.MyLoggingAspect"></bean>

	<bean id="teacherService" class="com.xiaol.aop.TeacherService"></bean>

    <!-- 这是一个简单的配置,其他形式的配置可以参考Spring的文档 -->
	<aop:config>
		<aop:aspect id="loggingAspect" ref="myLoggingAspect">
			<aop:pointcut id="normal"
				expression="execution(public boolean com.xiaol.aop.*.*(..))" />
			<aop:before pointcut-ref="normal" method="normalLog" />
		</aop:aspect>
	</aop:config>
</beans>

 

4、测试类同注解

© 著作权归作者所有

Pickacat
粉丝 2
博文 16
码字总数 13601
作品 0
深圳
程序员
私信 提问
Spring Boot Banner自定义,让你的应用与众不同

点击上方 IT牧场 ,选择 置顶或者星标技术干货每日送达! TIPS 本文基于Spring Boot 2.1.4,理论支持Spring Boot所有版本。 相信玩过Spring Boot的童鞋一定在启动日志中见过类似如下的内容。...

IT牧场
05/08
0
0
工作4年多才学会怎么去读源码,可悲么?

最近慢慢的尝试去看spring的源码,学习spring,以前都是只会用就行了,但是越是到后面,发现只是懂怎么用还不够,在面试的时候也会经常被问到一些开源框架的源码问题,即使在网上各种百度,当...

麦克斯
01/07
19.5K
45
day33_Spring学习笔记_02

一、AOP 1.1、AOP介绍 1.1.1、什么是AOP? 在软件业,AOP为Aspect Oriented Programming的缩写,意为:,通过和实现程序功能的统一维护的一种技术。AOP是OOP(面向对象编程)的延续,是软件开...

黑泽明军
2018/08/03
0
0
大数据学习之大数据技术笔记—spring入门

篇一 spring介绍 spring.io 官网 快速开始 Aop 面向切面编程,可以任何位置,并且可以细致到方法上 连接框架与框架 Spring 就是 IOC AOP 思想 有效的组织中间层对象一般都是切入 service 层 ...

董黎明
2018/12/16
19
0
阿里Java岗一面被问到对Spring的理解,懵了?这些你又了解多少

还在机械地打代码?我们很多开发者在开发 Spring 的程序的时候,很多的情况下,都是被动的接受了前辈们为我们做好的 Spring 特性案例。这样以来,确实在很大的程度上减少了我们开发的成本,但...

java知识分子
06/12
43
0

没有更多内容

加载失败,请刷新页面

加载更多

x002-语言元素

变量命令规则 硬性规则: 变量名由字母(广义的Unicode字符,不包括特殊字符)、数字和下划线构成,数字不能开头。 大小写敏感(大写的a和小写的A是两个不同的变量)。 不要跟关键字(有特殊...

伟大源于勇敢的开始
今天
4
0
nginx反向代理配置

nginx配置文件位置/usr/local/nginx/conf/nginx.conf 配置文件修改: # cd /usr/local/nginx/conf # vim nginx.conf server {listen 80;server_name localhost;#charset k......

行者终成事
今天
5
0
OSChina 周日乱弹 —— 这是假的,和我之前的不一样

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 小小编辑推荐:《男孩》-梁博 / 陶孟童 / 肖和东 / 高誉容 《男孩》-梁博 / 陶孟童 / 肖和东 / 高誉容 手机党少年们想听歌,请使劲儿戳(这里...

小小编辑
今天
8
0
Rust学习笔记一 数据类型

写在前面 我也不是什么特别厉害的大牛,学历也很低,只是对一些新语言比较感兴趣,接触过的语言不算多也不算少,大部分也都浅尝辄止,所以理解上可能会有一些偏差。 自学了Java、Kotlin、Python、...

MusiCodeXY
今天
5
0
Java 脚本引擎入门

Java Script Engine Java 脚本引擎可以将脚本嵌入Java代码中,可以自定义和扩展Java应用程序,自JDK1.6被引入,基于Rhino引擎,JDK1.8后使用Nashorn引擎,支持ECMAScript 5,但后期还可能会换...

阿提说说
今天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部