Spring 专题
专题目录
您的位置:java > Spring专题 > Spring AOP通知实例 – Advice
Spring AOP通知实例 – Advice
作者:--    发布时间:2019-11-20
spring aop(面向方面编程)框架,用于在模块化方面的横切关注点。简单得说,它只是一个拦截器拦截一些过程,例如,当一个方法执行,spring aop 可以劫持一个执行的方法,在方法执行之前或之后添加额外的功能。
在spring aop中,有 4 种类型通知(advices)的支持:
  • 通知(advice)之前 - 该方法执行前运行
  • 通知(advice)返回之后 – 运行后,该方法返回一个结果
  • 通知(advice)抛出之后 – 运行方法抛出异常后,
  • 环绕通知 – 环绕方法执行运行,结合以上这三个通知。
下面的例子显示spring aop 通知如何工作。

简单的 spring 例子

创建一个简单的客户服务类及一个print方法作为演示。
package com.h3.customer.services;

public class customerservice {
	private string name;
	private string url;

	public void setname(string name) {
		this.name = name;
	}

	public void seturl(string url) {
		this.url = url;
	}

	public void printname() {
		system.out.println("customer name : " + this.name);
	}

	public void printurl() {
		system.out.println("customer website : " + this.url);
	}

	public void printthrowexception() {
		throw new illegalargumentexception();
	}

}

file : applicationcontext.xml – 一个bean配置文件

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"
	xsi:schemalocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

	<bean id="customerservice" class="com.h3.customer.services.customerservice">
		<property name="name" value="h3i mook kim" />
		<property name="url" value="http://www.h3.com" />
	</bean>

</beans>

执行它

package com.h3.common;

import org.springframework.context.applicationcontext;
import org.springframework.context.support.classpathxmlapplicationcontext;

import com.h3.customer.services.customerservice;

public class app {
	public static void main(string[] args) {
		applicationcontext appcontext = new classpathxmlapplicationcontext(
				new string[] { "spring-customer.xml" });

		customerservice cust = (customerservice) appcontext.getbean("customerservice");

		system.out.println("*************************");
		cust.printname();
		system.out.println("*************************");
		cust.printurl();
		system.out.println("*************************");
		try {
			cust.printthrowexception();
		} catch (exception e) {

		}

	}
}

输出

*************************
customer name : h3 mook kim
*************************
customer website : http://www.h3.com
*************************
一个简单的spring项目用来注入(di)bean和输出一些字符串。

spring aop 通知

现在,附加 spring aop 建议到上述的客户服务。

1. 之前通知

它会在方法执行之前执行。创建一个实现 methodbeforeadvice 接口的类。
package com.h3.aop;

import java.lang.reflect.method;
import org.springframework.aop.methodbeforeadvice;

public class hijackbeforemethod implements methodbeforeadvice
{
	@override
	public void before(method method, object[] args, object target)
		throws throwable {
	        system.out.println("hijackbeforemethod : before method hijacked!");
	}
}
在 bean 配置文件(applicationcontext.xml),创建一个 bean 的 hijackbeforemethod 类,并命名为“customerserviceproxy” 作为一个新的代理对象。
  • ‘target’ – 定义你想拦截的bean。
  • ‘interceptornames’ – 定义要应用这个代理/目标对象的类(通知)。
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"
	xsi:schemalocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

	<bean id="customerservice" class="com.h3.customer.services.customerservice">
		<property name="name" value="h3 mook kim" />
		<property name="url" value="http://www.h3.com" />
	</bean>

	<bean id="hijackbeforemethodbean" class="com.h3.aop.hijackbeforemethod" />

	<bean id="customerserviceproxy" 
                 class="org.springframework.aop.framework.proxyfactorybean">

		<property name="target" ref="customerservice" />

		<property name="interceptornames">
			<list>
				<value>hijackbeforemethodbean</value>
			</list>
		</property>
	</bean>
</beans>
再次运行它,现在得到新的 customerserviceproxy bean,而不是原来的customerservice bean。
package com.h3.common;

import org.springframework.context.applicationcontext;
import org.springframework.context.support.classpathxmlapplicationcontext;
import com.h3.customer.services.customerservice;

public class app {
	public static void main(string[] args) {
		applicationcontext appcontext = new classpathxmlapplicationcontext(
				new string[] { "spring-customer.xml" });

		customerservice cust = 
                                (customerservice) appcontext.getbean("customerserviceproxy");

		system.out.println("*************************");
		cust.printname();
		system.out.println("*************************");
		cust.printurl();
		system.out.println("*************************");
		try {
			cust.printthrowexception();
		} catch (exception e) {

		}

	}
}

输出结果

*************************
hijackbeforemethod : before method hijacked!
customer name : h3 mook kim
*************************
hijackbeforemethod : before method hijacked!
customer website : http://www.h3.com
*************************
hijackbeforemethod : before method hijacked!
它将运行 hijackbeforemethod 的 before() 方法,在每个 customerservice 的方法之前执行。

2.返回后通知

该方法返回一个结果之后它将执行。创建一个实现afterreturningadvice接口的类。
package com.h3.aop;

import java.lang.reflect.method;
import org.springframework.aop.afterreturningadvice;

public class hijackaftermethod implements afterreturningadvice
{
	@override
	public void afterreturning(object returnvalue, method method,
		object[] args, object target) throws throwable {
	        system.out.println("hijackaftermethod : after method hijacked!");
	}
}
bean配置文件
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"
	xsi:schemalocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

	<bean id="customerservice" class="com.h3.customer.services.customerservice">
		<property name="name" value="yong mook kim" />
		<property name="url" value="http://www.h3.com" />
	</bean>

	<bean id="hijackaftermethodbean" class="com.h3.aop.hijackaftermethod" />

	<bean id="customerserviceproxy" 
                class="org.springframework.aop.framework.proxyfactorybean">

		<property name="target" ref="customerservice" />

		<property name="interceptornames">
			<list>
				<value>hijackaftermethodbean</value>
			</list>
		</property>
	</bean>
</beans>
再次运行,输出
*************************
customer name : h3 mook kim
hijackaftermethod : after method hijacked!
*************************
customer website : http://www.h3.com
hijackaftermethod : after method hijacked!
*************************
它将运行 hijackaftermethod 的 afterreturning()方法,在每次 customerservice 方法返回结果之后。

3.抛出后通知

它将在执行方法抛出一个异常后。创建一个实现throwsadvice接口的类,并创建一个afterthrowing方法拦截抛出:illegalargumentexception异常。
package com.h3.aop;

import org.springframework.aop.throwsadvice;

public class hijackthrowexception implements throwsadvice {
	public void afterthrowing(illegalargumentexception e) throws throwable {
		system.out.println("hijackthrowexception : throw exception hijacked!");
	}
}
bean配置文件
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"
	xsi:schemalocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

	<bean id="customerservice" class="com.h3.customer.services.customerservice">
		<property name="name" value="yong mook kim" />
		<property name="url" value="http://www.h3.com" />
	</bean>

	<bean id="hijackthrowexceptionbean" class="com.h3.aop.hijackthrowexception" />

	<bean id="customerserviceproxy" 
                 class="org.springframework.aop.framework.proxyfactorybean">

		<property name="target" ref="customerservice" />

		<property name="interceptornames">
			<list>
				<value>hijackthrowexceptionbean</value>
			</list>
		</property>
	</bean>
</beans>
再次运行,输出
*************************
customer name : h3 mook kim
*************************
customer website : http://www.h3.com
*************************
hijackthrowexception : throw exception hijacked!
它将运行 hijackthrowexception 的 afterthrowing()方法,如果 customerservice 的方法抛出异常。

4.环绕通知

它结合了上面的三个通知,在方法执行过程中执行。创建一个实现了methodinterceptor接口的类。必须调用“methodinvocation.proceed();” 继续在原来的方法执行,否则原来的方法将不会执行。

package com.h3.aop;

import java.util.arrays;

import org.aopalliance.intercept.methodinterceptor;
import org.aopalliance.intercept.methodinvocation;

public class hijackaroundmethod implements methodinterceptor {
	@override
	public object invoke(methodinvocation methodinvocation) throws throwable {

		system.out.println("method name : "
				+ methodinvocation.getmethod().getname());
		system.out.println("method arguments : "
				+ arrays.tostring(methodinvocation.getarguments()));

		// same with methodbeforeadvice
		system.out.println("hijackaroundmethod : before method hijacked!");

		try {
			// proceed to original method call
			object result = methodinvocation.proceed();

			// same with afterreturningadvice
			system.out.println("hijackaroundmethod : before after hijacked!");

			return result;

		} catch (illegalargumentexception e) {
			// same with throwsadvice
			system.out.println("hijackaroundmethod : throw exception hijacked!");
			throw e;
		}
	}
}
bean配置文件
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"
	xsi:schemalocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

	<bean id="customerservice" class="com.h3.customer.services.customerservice">
		<property name="name" value="yong mook kim" />
		<property name="url" value="http://www.h3.com" />
	</bean>

	<bean id="hijackaroundmethodbean" class="com.h3.aop.hijackaroundmethod" />

	<bean id="customerserviceproxy" 
                class="org.springframework.aop.framework.proxyfactorybean">

		<property name="target" ref="customerservice" />

		<property name="interceptornames">
			<list>
				<value>hijackaroundmethodbean</value>
			</list>
		</property>
	</bean>
</beans>
再次运行,输出
*************************
method name : printname
method arguments : []
hijackaroundmethod : before method hijacked!
customer name : h3 mook kim
hijackaroundmethod : before after hijacked!
*************************
method name : printurl
method arguments : []
hijackaroundmethod : before method hijacked!
customer website : http://www.h3.com 
hijackaroundmethod : before after hijacked!
*************************
method name : printthrowexception
method arguments : []
hijackaroundmethod : before method hijacked!
hijackaroundmethod : throw exception hijacked!

它将运行hijackaroundmethod 的 invoke()方法,在每一个 customerservice 方法执行后。

总结

大部分的 spring 开发者都只是实现了“环绕通知”,因为它可以对所有通知类型,但更好的做法应该是选择最合适的通知类型来满足要求。
切入点
在这个例子中,在一客户服务类中的所有方法都自动拦截(通知)。但在大多数情况下,可能需要使用切入点和advisor通过它的方法名拦截它的方法。

下载代码 – 

网站声明:
本站部分内容来自网络,如您发现本站内容
侵害到您的利益,请联系本站管理员处理。
联系站长
373515719@qq.com
关于本站:
编程参考手册