Spring AOP的一些总结

前言

其实从开始使用spring开始,对spring中的aop一直就有了解,但是每次使用过后都遗忘了。导致再次使用的时候,又得重新翻找资料,重新开始写demo,今天来个总结,搞定aop的基本实例。真正从源码基本进行学习还得等一段时间。

一些概念

网上已经有很多博客针对aop的一些概念有介绍,自己也能理解一二。从实用的角度来说,概念的介绍并不是这篇博客的重点,针对这些概念的介绍可以参考以下博客,个人觉得讲解的比较通俗的是这一篇:aop概念通俗版,讲解的稍微全面一点的是这一篇:aop相关概念

简单实例

这里还是弄一个简单实例吧。针对一些细节后续会进行总结

先创建一个maven项目,pom文件如下:

<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.learn</groupId>
	<artifactId>spring_aop</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<url>http://maven.apache.org</url>

	<properties>
		<spring.version>3.1.1.RELEASE</spring.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>1.6.12</version>
		</dependency>
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>1.6.12</version>
		</dependency>
		<dependency>
			<groupId>cglib</groupId>
			<artifactId>cglib</artifactId>
			<version>2.2</version>
		</dependency>
	</dependencies>
</project>

在spring的配置文件中加入如下配置:

<aop:aspectj-autoproxy />
<context:component-scan base-package="com.learn" />

编写一个简单的业务类

package com.learn.service;

import org.springframework.stereotype.Service;

@Service
public class PersonService {

	public void addPerson(String personName) {
		System.out.println("add person");
	}
	
	public boolean deletePerson(String personName) {
		System.out.println("delete person");
		return true;
	}
	
	public void editPerson(String personName) {
		System.out.println("edit person "+personName);
		throw new RuntimeException("edit person infomation error!");
	}
	
}

编写切面类

package com.learn.aspect;


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

@Component
@Aspect
public class SimpleAspect {
	
	@Pointcut("execution(* com.learn.service.*Service*.*(..))")
	public void pointCut() {
		
	}
	
	@Pointcut("execution(* com.learn.service.*Service*.edit*(..))")
	public void pointCutException() {
	}
	
	@After("pointCut()")
	public void after(JoinPoint joinPoint) {
		System.out.println("after aspect executed");
	}
	
	@Before("pointCut()")
	public void before(JoinPoint joinPoint) {
		System.out.println("before aspect executing");
	}
	
	@AfterReturning(pointcut="pointCut()",returning = "returnVal")
	public void afterReturning(JoinPoint joinPoint ,Object returnVal) {
		
		System.out.println("afterReturning executed,return result is "+returnVal);
	}

	@Around("pointCut()")
	public void around(ProceedingJoinPoint pjp) throws Throwable{
		System.out.println("around start..");
		try {
			pjp.proceed();
		} catch (Throwable ex) {
			System.out.println("error in around");
			throw ex;
		}
		System.out.println("around end");
	}
	
	@SuppressWarnings("rawtypes")
	@AfterThrowing(pointcut="pointCutException()",throwing="error")
	public void afterThrowing(JoinPoint jp,Throwable error) {
		Object[] args = jp.getArgs();
		System.out.println("目标函数中的参数信息:");
		for(Object o:args) {
			System.out.println(o.toString());
		}
		Object target = jp.getTarget();
		System.out.println("目标函数中的target信息:"+target.toString());
		Class class1 = jp.getClass();
		
		String kind = jp.getKind();
		System.out.println("切面的类型:"+kind);
		System.out.println("目标函数的类信息:"+class1.getName());
		System.out.println("切面捕获异常信息");
		System.out.println("error:"+error);
	}
}

切面类中的注解需要注意一下,@Component是将其交给spring管理,@Aspect是将其标记为切面,其实还有xml配置的方式实现,这里就不做详细探讨了,XML配置更加简单。

测试方法

package com.learn.func;

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

import com.learn.service.PersonService;

public class App {
	public static void main(String[] args) {
		try {
			ApplicationContext appContext = new ClassPathXmlApplicationContext("classpath:appContext.xml");
	    	PersonService personService = appContext.getBean(PersonService.class);
	    	String personName = "liman";
	    	personService.addPerson(personName);
	    	personService.deletePerson(personName);
	    	personService.editPerson(personName);
		} catch (Exception e) {
			System.out.println("异常信息:"+e.getMessage());
		}
	}
}

程序运行结果


补充

spring aop中重要的就是切入点表达式,切入点表达式是联系目标类方法和切面增强方法的桥梁。因此需要针对切入点表达式进行一些补充

execution(方法修饰符    方法返回值    方法所属类    匹配方法名    (方法的参数列表)    方法抛出的异常)

其中红色字体的不能省略,每个部分都支持通配符('*')来匹配

方法修饰符:public private protected。

参数列表中:'*'——表示一个任意类型的参数,".."——表示零个或多个任意类型的参数

(*,Integer)匹配一个接受两个参数的方法,第一个参数可以为任意类型,第二个必须为Integer类型。

execution只是切入点表达式的一种,还有within,this,target,args。

针对within,this,target和args的介绍,我建议还是参考官网文档吧,国内有些文档将这几种切入点表达式翻译的很怪。


如果出现一个增强类需要切入到多个目标类,可以进行切入点表达式的组合,||,&&等逻辑语法在切入点表达式中依旧适用

针对切面类中需要获取目标方法的相关信息,一般是通过JoinPoint这个参数来获取,同时在切面类中,为了调用目标类中的相关方法,可能需要用到反射。


最后说一句:这次的使用是基于在新网实习中,涉及到异常日志信息处理的问题来实现的,当时脑子里首先反应的就是利用AOP,经历过各种苛刻碰碰,勉强算是完成了功能,在后面迭代中进一步完善

猜你喜欢

转载自blog.csdn.net/liman65727/article/details/80541661