Spring之AOP

本文详细介绍了Spring框架中AOP(面向切面编程)的概念,包括连接点、目标、通知、代理和适配器等核心概念。通过具体的代码示例,讲解了前置通知、后置通知、环绕通知、异常通知和过滤通知的实现方式,并展示了如何在Spring XML配置文件中进行配置。

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

1. AOP关键性概念

连接点(Joinpoint):程序执行过程中明确的点,如方法的调用,或者异常的抛出.
目标(Target):被通知(被代理)的对象
通知(Advice):在某个特定的连接点上执行的动作,同时Advice也是程序代码的具体实现,例如一个实现日志记录的代码(通知有些书上也称为处理)
代理(Proxy):将通知应用到目标对象后创建的对象(代理=目标+通知),请注意:只有代理对象才有AOP功能,而AOP的代码是写在通知的方法里面的
适配器(Advisor):适配器=通知(Advice)+切入点(Pointcut) 连接点带条件的通知

2.AOP的核心店(通知)

名称实现接口案例解释
前置通知实现org.springframework.aop.MethodBeforeAdvice接口买书、评论前加系统日志
后置通知实现org.springframework.aop.AfterReturningAdvice接口买书返利(存在bug)
环绕通知org.aopalliance.intercept.MethodInterceptor类似拦截器,会包括切入点,目标类前后都会执行代码。
异常通知org.springframework.aop.ThrowsAdvice出现异常执行系统提示,然后进行处理。价格异常为例
过滤通知(适配器)org.springframework.aop.support.RegexpMethodPointcutAdvisor处理买书返利的bug

3.通知代码块演示与结果

3.1 前置通知

package com.tanle.aop.advice;

import java.lang.reflect.Method;
import java.util.Arrays;
/**
 * 买书、评论前加系统日志
 * @author tanle
 * 2020年8月5日09:34:32
 *
 */
public class MyMethodBeforeAdvice implements org.springframework.aop.MethodBeforeAdvice {

	@Override
	public void before(Method method, Object[] args, Object target) throws Throwable {
		String clzName=target.getClass().getName();
		String methodName=method.getName();
		String params=Arrays.toString(args);
		System.out.println("【买书、评论前加系统日志】"+clzName+"."+methodName+"("+params+")");

	}

}

3.2 后置通知

package com.tanle.aop.advice;

import java.lang.reflect.Method;
import java.util.Arrays;

import org.springframework.aop.AfterReturningAdvice;
/**
 * 买书返利(后置通知 存在bug)
 * @author tanle
 *
 */
public class MyAfterReturningAdvice implements AfterReturningAdvice{

	@Override
	public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
		String clzName=target.getClass().getName();
		String methodName=method.getName();
		String params=Arrays.toString(args);
		System.out.println("【买书返利的后置通知】"+clzName+"."+methodName+"("+params+")"+"\t 目标对象方法调用后的返回值"+returnValue);
		
	}

}

3.3 环绕通知

package com.tanle.aop.advice;

import java.util.Arrays;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class MyMethodInterceptor implements MethodInterceptor {
	/**
	 * 环绕通知
	 */
	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		String clzName=invocation.getThis().getClass().getName();
		String methodName=invocation.getMethod().getName();
		String params=Arrays.toString(invocation.getArguments());
		System.out.println("【环绕通知】"+clzName+"."+methodName+"("+params+")");
		Object returnValue = invocation.proceed();
		System.out.println("\t 目标对象方法调用后的返回值"+returnValue);
		return returnValue;
	}

}

3.4 异常通知

package com.tanle.aop.advice;

import org.springframework.aop.ThrowsAdvice;

import com.tanle.aop.biz.impl.PriceException;
/**
 * 异常通知
 * @author tanle
 * 2020年8月5日10:46:02
 *	
 */
public class MyThrowsAdvice implements ThrowsAdvice {
	public void afterThrowing( PriceException ex ) {
		System.out.println("价格输入有误,购买失败,请重新输入!!!");
	}
}

3.5 过滤通知(适配器)

过滤通知不需要写类(直接在xml里面配置)

3.6 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:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">	
	<!-- 地址类 -->
	<bean id="address" class="com.tanle.entity.Address" scope="singleton">
		<property name="city">
			<value>长沙</value>
		</property>
	</bean>
	
	<!-- ****************AOP************************** -->
	<!-- 目标对象 -->
	<bean id="bookBiz" class="com.tanle.aop.biz.impl.BookBizImpl">
	</bean>
	<!-- 通知 -->
	<bean id="myBefore" class="com.tanle.aop.advice.MyMethodBeforeAdvice"></bean>
	<bean id="myAfter" class="com.tanle.aop.advice.MyAfterReturningAdvice"></bean>
	<bean id="myInterceptor" class="com.tanle.aop.advice.MyMethodInterceptor"></bean>
	<bean id="myThrows" class="com.tanle.aop.advice.MyThrowsAdvice"></bean>
	<!-- 过滤通知不需要写类 -->
	<bean id="myAfter2" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
		<property name="advice" ref="myAfter"></property>
		<property name="pattern" value=".*buy"></property>
	</bean> 
	<!-- 有代理工厂来组装目标对象及通知 -->
	<bean id="bookProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
		<property name="target" ref="bookBiz"></property>
		<property name="proxyInterfaces">
			<list>
				<value>com.tanle.aop.IBookBiz</value>
			</list>
		</property>
		<property name="interceptorNames">
			<list>
				<value>myBefore</value>
				<!-- <value>myAfter</value> -->
				<value>myAfter2</value>
				<value>myInterceptor</value>
				<value>myThrows</value>
			</list>
		</property>
	</bean>
</beans>

3.7 工具类

BookBizImpl

package com.tanle.aop.biz.impl;

import com.tanle.aop.IBookBiz;

public class BookBizImpl implements IBookBiz {

	public BookBizImpl() {
		super();
	}

	public boolean buy(String userName, String bookName, Double price) {
		// 通过控制台的输出方式模拟购书
		if (null == price || price <= 0) {
		 	throw new PriceException("book price exception");
		}
		System.out.println(userName + " buy " + bookName + ", spend " + price);
		return true;
	}

	public void comment(String userName, String comments) {
		// 通过控制台的输出方式模拟发表书评
		System.out.println(userName + " say:" + comments);
	}

}

PriceException

package com.tanle.aop.biz.impl;

public class PriceException extends RuntimeException {

	public PriceException() {
		super();
	}

	public PriceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
		super(message, cause, enableSuppression, writableStackTrace);
	}

	public PriceException(String message, Throwable cause) {
		super(message, cause);
	}

	public PriceException(String message) {
		super(message);
	}

	public PriceException(Throwable cause) {
		super(cause);
	}
	
}

IBookBiz 接口

package com.tanle.aop;

public interface IBookBiz {
	// 购书
	public boolean buy(String userName, String bookName, Double price);

	// 发表书评
	public void comment(String userName, String comments);
}

3.7 测试类

package com.tanle.test;

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

import com.tanle.aop.IBookBiz;

public class AopTest {
	public static void main(String[] args) {
		
		ApplicationContext applicationContext=new ClassPathXmlApplicationContext("/spring.xml");
		IBookBiz bean = (IBookBiz) applicationContext.getBean("bookProxy");
		boolean buy = bean.buy("铁子", "铁蛋", 66d);
		bean.comment("铁子", "真的铁了");
	}
}

测试结果
在这里插入图片描述
异常通知测试(将金额改为负数)
在这里插入图片描述

4. 总结

1.AOP即面向切面编程
2.谢谢观看!有不足欢迎指出!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值