Spring之AOP

本文详细介绍了AOP(面向切面编程)的概念及其实现方式,包括使用Spring框架的schema-based和AspectJ方式,以及注解方式来实现AOP。通过具体的代码示例,展示了如何在程序中添加前置、后置、异常和环绕通知。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

AOP(Aspect Oriented Programming):面向切面编程

即在程序原有纵向执行流程中,针对某一个或某一些方法添加通知,形成横切面过程就叫做面向切面编程。
建立一个maven项目,导入jar包依赖:

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<version>4.3.21.RELEASE</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>4.3.21.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>1.9.2</version>
		</dependency>

		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>1.9.2</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>4.3.7.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
			<version>4.3.7.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>4.3.7.RELEASE</version>
		</dependency>

Spring提供了AOP的两种实现方式(schema-based和AspectJ)。
首先定义一个人的行为类,里面有eat方法。

package com.guo.aop;

public class Behavior {
	
	private String name;
	
	public void setName(String name) {
		this.name = name;
	}
	
	public void eat() {
		System.out.println(name+"吃饭");
	}
	
	public void eat(String food) {
		if(food.contains("砒霜")) {
			throw new RuntimeException("饭里面有砒霜");
		}
		System.out.println(name+"吃"+food);
	}
}

src/main/resources下的spring.xml文件

<?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:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:jpa="http://www.springframework.org/schema/data/jpa"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring-beans.xsd
	http://www.springframework.org/schema/context
	http://www.springframework.org/schema/context/spring-context.xsd
	http://www.springframework.org/schema/aop
	http://www.springframework.org/schema/aop/spring-aop.xsd
	http://www.springframework.org/schema/data/jpa
	http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
	http://www.springframework.org/schema/tx 
	http://www.springframework.org/schema/tx/spring-tx.xsd">
	...
</beans>

在这里插入图片描述

1、schema-based(每个通知都需要实现接口或类)

package com.guo.aop.advice;

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

//前置通知
public class BeforeAdvisor implements MethodBeforeAdvice {

	@Override
	public void before(Method method, Object[] args, Object target) throws Throwable {
		System.out.println("饭前洗手");
	}
}
package com.guo.aop.advice;

import java.lang.reflect.Method;

import org.springframework.aop.AfterReturningAdvice;
//后置通知
public class AfterAdvisor implements AfterReturningAdvice {

	@Override
	public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
		System.out.println("饭后来根中华");
	}
}
package com.guo.aop.advice;

import java.lang.reflect.Method;
import java.rmi.RemoteException;

import javax.servlet.ServletException;

import org.springframework.aop.ThrowsAdvice;

//只有当异常发生时才触发
//如果切面中的异常被try catch捕获,则不会触发
public class ExceptionAdvisor implements ThrowsAdvice {//ThrowsAdvice是个空接口,实现与否无所谓

	public void exceptionOccur(Exception e) {
		System.out.println("发生异常:"+e.getMessage());
	}
	public void afterThrowing(RemoteException ex) throws Throwable {
		System.out.println("发生异常:"+ex.getMessage());
	}
	public void afterThrowing(Method m,Object[] args, Object target,ServletException ex) throws Throwable {
		System.out.println("发生异常:"+ex.getMessage());
	}
}
package com.guo.aop.advice;

import java.lang.reflect.Method;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
//环绕通知
public class ArroundAdvisor implements MethodInterceptor {
	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		System.out.println("吃饭前玩手机");
		Object o = invocation.proceed();
		System.out.println("吃完饭睡觉");
		return o;
	}
}

AOP配置:

	<bean id="pb" class="com.guo.aop.Behavior" scope="prototype">
		<property name="name" value="张三" />
	</bean>
	
	<bean id="before" class="com.guo.aop.advice.BeforeAdvisor" /><!-- 前置通知 -->
	<bean id="after" class="com.guo.aop.advice.AfterAdvisor" /><!-- 后置通知 -->
	<bean id="exception" class="com.guo.aop.advice.ExceptionAdvisor" /><!-- 异常通知 -->
	<bean id="arround" class="com.guo.aop.advice.ArroundAdvisor" /><!-- 环绕通知 -->
	<aop:config>
		<aop:pointcut expression="execution(* com.guo.aop.Behavior.eat(..))" id="eat" />
		<aop:advisor advice-ref="before" pointcut-ref="eat" />
		<aop:advisor advice-ref="after" pointcut-ref="eat" />
		<aop:advisor advice-ref="exception" pointcut-ref="eat" />
		<aop:advisor advice-ref="arround" pointcut-ref="eat" />
	</aop:config>

2、AspectJ(每个通知不需要实现接口或类)

首先定义一个切面类:

package com.guo.aop;

import org.aspectj.lang.ProceedingJoinPoint;

public class Aop {
	public void washHands() {
		System.out.println("洗手");
	}
	public void smoke() {
		System.out.println("饭后一根烟,赛过活神仙");
	}
	public void exceptionOccur(Exception e) {
		System.out.println("异常发生了:"+e.getMessage());
	}
	public void eatOver() {
		System.out.println("饭吃完了");
	}
	public Object playPhone(ProceedingJoinPoint p) throws Throwable {
		System.out.println("饭前玩手机");
		Object o = p.proceed();
		System.out.println("饭后玩手机");
		return o;
	}
}

AOP配置:

	<bean id="aop" class="com.guo.aop.Aop" />
	<aop:config>
		<aop:pointcut expression="execution(* com.guo.aop.Behavior.eat(..))"
			id="pointcut" />
		<aop:aspect ref="aop">
			<aop:before method="washHands" pointcut-ref="pointcut" />
			<aop:after method="smoke" pointcut-ref="pointcut" /><!-- 是否出现异常都执行 -->
			<aop:after-returning method="eatOver" pointcut-ref="pointcut" /><!-- 只有当切点正确执行时执行 -->
			<aop:around method="playPhone" pointcut-ref="pointcut" />
			<aop:after-throwing method="exceptionOccur" throwing="e" pointcut-ref="pointcut" />
		</aop:aspect>
			<!--注意:<aop:after/> <aop:after-returing/> <aop:after-throwing/>执行顺序和配置顺序有关 -->
	</aop:config>

3、注解方式

在xml文件中添加注解扫描

<context:component-scan base-package="com.guo.aop" /><!-- 告诉Spring哪些包下有注解 -->

切面类

@Aspect // 表明该类是一个切面类
@Component
public class Aop {
	
	@Before("com.guo.aop.Behavior.eat(..)&&args(o)")
	public void washHands(Object o) {
		System.out.println("洗手"+o);
	}
	
	@After("com.guo.aop.Behavior.eat(..)")
	public void smoke() {
		System.out.println("饭后一根烟,赛过活神仙");
	}
	
	@AfterThrowing(pointcut="com.guo.aop.Behavior.eat(..)",throwing="e")
	public void exceptionOccur(Exception e) {
		System.out.println("异常发生了:"+e.getMessage());
	}
	
	@AfterReturning(pointcut="com.guo.aop.Behavior.eat(..)",returning="result")
	public void eatOver(Object result) {
		System.out.println("饭吃完了"+result);
	}
	
	@Around("com.guo.aop.Behavior.eat(..)")
	public Object playPhone(ProceedingJoinPoint p) throws Throwable {
		System.out.println("饭前玩手机");
		Object o = p.proceed();
		System.out.println("饭后玩手机");
		return o;
	}

}

Behavior.java

@Component//默认是类名首字母小写,相当于bean标签,也可以@Component(自定义名称)
public class Behavior {
	
	@Resource
	private String name;
	
	public void setName(String name) {
		this.name = name;
	}
	
	@Pointcut("execution(* com.guo.aop.Behavior.eat(..))")
	public void eat() {
		System.out.println(name+"吃饭");
	}
	@Pointcut("execution(* com.guo.aop.Behavior.eat(..))")
	public void eat(String food) {
		if(food.contains("砒霜")) {
			throw new RuntimeException("饭里面有砒霜");
		}
		System.out.println(name+"吃"+food);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值