Spring AOP之Advice

本文详细介绍了Spring AOP的不同实现方式,包括Spring1.x版本的动态代理方法、Spring2.x版本基于XML Schema配置和基于JDK5注解的AOP实现。文中通过示例代码演示了前置通知、后置通知及环绕通知的具体应用。

Spring AOP之Advice


   前置通知:即代码被执行之前被调用
   后置通知:即代码执行之后进行调用
   环绕通知:即代码执行前后进行调用

这两种方式的实现方式用到了动态代理的思想来完成的,

总结不想说废话:

首先是Spring1.x对Advice的支持:

 

public interface IHello {
	public void sayHello1() ;
	public void sayHello2() ;
	public void sayHello3() ;
	public void sayHello4() ;
}

 然后就是类的实现:

package com.spring.test;

public class Hello implements IHello{

	public void sayHello1() {
		System.out.println("111111111111");
	}

	public void sayHello2() {
		System.out.println("222222222222");
	}

	public void sayHello3() {
		System.out.println("333333333333");
	}

	public void sayHello4() {
		System.out.println("444444444444");
	}
}

 
然后是负责前置通知的类,要实现MethodBeforeAdvice接口:

 

 

 

public class AdviceBeforeHello implements MethodBeforeAdvice {
	@Override
	public void before(Method arg0, Object[] arg1, Object arg2)
			throws Throwable {
		System.out.println("验证用户。。。。");

	}
}

 然后是负责后置通知的类,要实现AfterReturningAdvice接口:

 

 

public class AdviceAfterHello implements AfterReturningAdvice{

	@Override
	public void afterReturning(Object arg0, Method arg1, Object[] arg2,
			Object arg3) throws Throwable {
		System.out.println("方法执行完毕");
		
	}

}

 

 

 

配置项:
<bean id="beforeHello" class="com.spring.advice.AdviceBeforeHello" />
	<bean id="afterHello" class="com.spring.advice.AdviceAfterHello"></bean>
	<bean id="hello" class="com.spring.test.Hello"></bean>
	<!-- 注册代理类 -->
	<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
		<property name="proxyInterfaces">
			<value>com.spring.test.IHello</value>
		</property>

		<!-- 目标对象,即Hello对象 -->
		<property name="target" ref="hello"></property>
		<!-- 应用的前置通知,拦截器名称 -->
		<property name="interceptorNames">
			<list>
				<value>beforeHello</value>
				<value>afterHello</value>

			</list>
		</property>
	</bean>

 

 

测试方法:

 

	ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
		IHello hello = (IHello) context.getBean("proxy");
		hello.sayHello1();
		hello.sayHello2();
		hello.sayHello3();
		hello.sayHello4();

 

 

结果:

 

下面是环绕通知:

public class AdviceAroundHello implements MethodInterceptor{

	@Override
	public Object invoke(MethodInvocation arg0) throws Throwable {
		Object object=null;
		System.out.println("验证用户");
		try {
			object=arg0.proceed();
		} finally{
			System.out.println("方法执行完毕");
		}
		
		return object;
	}


}

 然后配置beans.xml:

<bean id="aroundHello" class="com.spring.advice.AdviceAroundHello"></bean>
	 
	<bean id="hello" class="com.spring.test.Hello"></bean>
	<!-- 注册代理类 -->
	<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
		<property name="proxyInterfaces">
			<value>com.spring.test.IHello</value>
		</property>

		<!-- 目标对象,即Hello对象 -->
		<property name="target" ref="hello"></property>
		<!-- 应用的前置通知,拦截器名称 -->
		<property name="interceptorNames">
			<list>
				<value>aroundHello</value>
			</list>
		</property>
	</bean>

 

 以上是Spring1.x对AOP的支持,,Spring2.x除了支持Spring1.x外,还提供了两种实现AOP的方式:

1.基于XML的配置,使用基于Schema的XML配置来完成AOP而且Advice也不用再实现任何其他特定接口。

2.使用JDK5的注释来完成AOP的实现,只需要一个简单的标签就可以完成AOP的整个过程。

 

基于XML Schema的前置通知配置如下:

   编写通知的逻辑代码:

public class AdviceBeforeHello {
	public void beforeHello(){
		System.out.println("验证用户。。。。");

	}
}

 在beans.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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
	<!-- 注册接口实现类 -->
	<bean id="hello" class="com.spring.test.Hello"></bean>
	<aop:config>
	<!--  -->
		<aop:pointcut id="beforePointCut"
			expression="execution(* com.spring.test.IHello.*(..))" />
		<aop:aspect id="before" ref="beforeAdvice">
			<aop:before method="beforeHello" pointcut-ref="beforePointCut" />
		</aop:aspect>
	</aop:config>


	<bean id="beforeAdvice" class="com.spring.advice.AdviceBeforeHello"></bean>
</beans>

 其他不变。。。。

 

 

2.基于Annotation的前置通知:

切面类:

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class AdviceBeforeHello {
	@Before("execution(*  com.spring.test.IHello.*(..))")
	public void beforeHello(){
		System.out.println("验证用户。。。。");

	}
}

 beans.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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
	<!-- 注册接口实现类 -->
	<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
	<bean id="hello" class="com.spring.test.Hello"></bean>
	<bean id="beforeAdvice" class="com.spring.advice.AdviceBeforeHello"></bean>
</beans>

 

 基于XML和Annotation的后置通知和前置通知类似。下面是基于XML的环绕通知:

 

import org.aspectj.lang.ProceedingJoinPoint;

public class AdviceAroundHello {

	public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
		System.out.println("验证用户");
		//执行连接点的方法
		Object object = joinPoint.proceed();
		System.out.println("方法执行完毕");
		return object;
	}

}

 

 beans.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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
	<!-- 注册接口实现类 -->
	<bean id="hello" class="com.spring.test.Hello"></bean>
	<aop:config>
		<aop:pointcut id="aroundPointcut"
			expression="execution(*  com.spring.test.IHello.*(..))" />
		<aop:aspect id="around" ref="aroundAdvice">
			<aop:around method="around" pointcut-ref="aroundPointcut" />
		</aop:aspect>
	</aop:config>

	<bean id="aroundAdvice" class="com.spring.advice.AdviceAroundHello"></bean>
</beans>

 

 其他不变。

 

-------------------------------------------------------------------------------------------------------------------------------

基于Annotation的环绕通知:

package com.spring.advice;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class AdviceAroundHello {
	@Around("execution(*  com.spring.test.IHello.*(..))")
	public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
		System.out.println("验证用户");
		// 执行连接点的方法
		Object object = joinPoint.proceed();
		System.out.println("方法执行完毕");
		return object;
	}

}

 beans.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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
	<!-- 注册接口实现类 -->
	<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
	
	<bean id="hello" class="com.spring.test.Hello"></bean>
	<bean id="aroundAdvice" class="com.spring.advice.AdviceAroundHello"></bean>
</beans>

 

完成!!

 

 

 

 

<think>我们正在讨论SpringAOP中的Advice接口继承结构。根据引用内容,特别是引用[2]和[3],我们可以知道SpringAOP中定义了一些Advice接口,并且有对应的拦截器实现。在SpringAOP中,Advice是通知,也就是在连接点(Joinpoint)执行的动作。常见的通知类型有:前置通知(Beforeadvice)、后置通知(Afterreturningadvice)、异常通知(Afterthrowingadvice)、最终通知(After(finally)advice)和环绕通知(Aroundadvice)。根据引用[2]中的代码片段,我们可以看到:-MethodBeforeAdviceInterceptor实现了MethodInterceptor接口,同时它也是一个BeforeAdvice(前置通知)。-AfterReturningAdviceInterceptor实现了MethodInterceptor接口,同时它也是一个AfterAdvice(后置通知)。但是,我们需要注意的是,在SpringAOP中,Advice接口本身是一个标记接口(可能没有方法),而具体的通知类型有各自的子接口。根据SpringAOP的文档和引用资料,我们可以整理出Advice接口的继承结构如下:1.Advice:顶级标记接口,没有任何方法。2.BeforeAdvice:标记接口,表示前置通知。它的子接口是MethodBeforeAdvice(方法执行前通知)。3.AfterAdvice:标记接口,表示后置通知。它的子接口有:-AfterReturningAdvice:方法正常返回后执行的通知。-ThrowsAdvice:方法抛出异常后执行的通知。4.另外,还有Around通知,它是通过AOP联盟的MethodInterceptor接口实现的。MethodInterceptor不是继承自Advice,但它也是通知的一种,因为它可以在方法调用前后执行自定义行为。此外,Spring还提供了After通知(无论方法正常结束还是异常结束都会执行),对应的接口是AfterAdvice?实际上,在Spring中,最终通知(After(finally)advice)是通过实现AfterAdvice接口的?但根据Spring文档,最终通知通常使用AfterReturningAdvice和ThrowsAdvice的组合,或者使用更通用的环绕通知来实现。实际上,Spring5.2.9中有一个AfterAdvice接口,但它的具体实现类通常不是直接实现AfterAdvice,而是通过实现MethodInterceptor来达到环绕的效果。但是,从引用[2]中我们看到了AfterReturningAdviceInterceptor,它实现了AfterReturningAdvice(继承自AfterAdvice)。而ThrowsAdvice是一个标记接口,需要自己实现方法(方法名必须是afterThrowing,参数可以是Exception或者特定的异常类型)。因此,我们可以画出如下继承结构图(使用mermaid语法):```mermaidclassDiagramAdvice<|--BeforeAdviceAdvice<|--AfterAdviceAdvice<|--Interceptor:间接关联(环绕通知)BeforeAdvice<|--MethodBeforeAdviceAfterAdvice<|--AfterReturningAdviceAfterAdvice<|--ThrowsAdviceclassAdvice{<<marker>>}classBeforeAdvice{<<marker>>}classMethodBeforeAdvice{voidbefore(Methodmethod,Object[]args,Objecttarget)throwsThrowable}classAfterAdvice{<<marker>>}classAfterReturningAdvice{voidafterReturning(ObjectreturnValue,Methodmethod,Object[]args,Objecttarget)throwsThrowable}classThrowsAdvice{//无方法,但是实现类必须包含一个或多个afterThrowing方法}classInterceptor{//注意:这里Interceptor并不是直接继承Advice,而是AOP联盟的接口}classMethodInterceptor{Objectinvoke(MethodInvocationinvocation)throwsThrowable}Note"环绕通知通过实现MethodInterceptor接口完成"asN1MethodInterceptor..N1```注意:环绕通知(Aroundadvice)是通过实现AOP联盟的`org.aopalliance.intercept.MethodInterceptor`接口来实现的,该接口并不是直接继承SpringAdvice接口,但是Spring将其视为一种通知类型。另外,在Spring中,最终通知(Afterfinallyadvice)并没有一个直接的接口,通常也是通过实现MethodInterceptor来编写,或者使用AspectJ的@After注解。由于用户要求图解,我们可以用文字描述这个结构,并附上mermaid代码。但请注意,在纯文本环境中,我们无法显示图形,所以这里提供mermaid代码,用户可以在支持mermaid的工具中查看。总结一下:-Advice是顶级标记接口。-前置通知:MethodBeforeAdvice(继承自BeforeAdvice)。-后置通知:AfterReturningAdvice(继承自AfterAdvice)和ThrowsAdvice(也是继承自AfterAdvice)。-环绕通知:通过实现MethodInterceptor接口(属于AOP联盟,不是直接继承Advice)。另外,Spring还提供了IntroductionAdvisor(引入通知)和IntroductionInfo(引入信息)用于引入新的接口,但这不属于我们讨论的Advice类型。因此,我们可以这样回答用户:</think>### Spring AOP Advice 接口继承结构图解 在 Spring AOP 中,`Advice` 接口是所有通知类型的顶层接口,它定义了横切逻辑的执行时机。以下是完整的继承结构图解(基于 Spring 5.2.9): ```mermaid classDiagram direction BT class Advice { <<标记接口>> } class BeforeAdvice { <<标记接口>> } class AfterAdvice { <<标记接口>> } class MethodBeforeAdvice { +before(Method, Object[], Object) void } class AfterReturningAdvice { +afterReturning(Object, Method, Object[], Object) void } class ThrowsAdvice { +afterThrowing([Exception类型]) void } class MethodInterceptor { <<AOP联盟接口>> +invoke(MethodInvocation) Object } Advice <|-- BeforeAdvice Advice <|-- AfterAdvice BeforeAdvice <|-- MethodBeforeAdvice AfterAdvice <|-- AfterReturningAdvice AfterAdvice <|-- ThrowsAdvice MethodInterceptor ..> Advice : 实现类关联 ``` #### 核心接口说明: 1. **`Advice`** 顶级标记接口,所有通知类型的父接口,无具体方法定义[^3]。 2. **`BeforeAdvice`** 前置通知标记接口,子接口定义方法执行前的增强逻辑[^2]。 3. **`MethodBeforeAdvice`** 具体前置通知接口,实现 `before()` 方法: ```java void before(Method method, Object[] args, Object target) throws Throwable; ``` 4. **`AfterAdvice`** 后置通知标记接口,子接口定义方法执行后的增强逻辑[^4]。 5. **`AfterReturningAdvice`** 返回后通知接口,实现 `afterReturning()` 方法: ```java void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable; ``` 6. **`ThrowsAdvice`** 异常通知接口,通过方法签名匹配异常类型(无统一方法): ```java void afterThrowing(Method method, Object[] args, Object target, Exception ex); ``` 7. **`MethodInterceptor`(AOP联盟接口)** 实现环绕通知的核心接口,通过 `invoke()` 控制整个调用流程[^3]: ```java Object invoke(MethodInvocation invocation) throws Throwable; ``` #### 执行流程示例: ```mermaid sequenceDiagram participant Client participant Proxy participant MethodInterceptor participant Target Client->>Proxy: 调用方法 Proxy->>MethodInterceptor: invoke() MethodInterceptor->>MethodBeforeAdvice: before() MethodBeforeAdvice-->>MethodInterceptor: MethodInterceptor->>Target: 执行原方法 Target-->>MethodInterceptor: 返回结果 MethodInterceptor->>AfterReturningAdvice: afterReturning() AfterReturningAdvice-->>MethodInterceptor: MethodInterceptor-->>Proxy: 返回结果 Proxy-->>Client: 返回结果 ``` #### 关键特性: 1. **通知组合** 多个 `Advice` 通过责任链模式组合,形成拦截器链(如前置+后置通知)[^2]。 2. **代理机制** `Advice` 通过动态代理织入目标对象,生成代理对象:`代理 = 目标对象 + 通知`[^4]。 3. **异常处理** `ThrowsAdvice` 可针对不同异常类型定义多个处理方法。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值