Spring AOP配置方式
程序员文章站
2022-08-09 19:24:48
AOP 面向切面编程,允许在 java 应用中的方法调用的前后做一些处理。 本文通过实例介绍两种主要的Spring AOP 配置方式:xml 方式配置,注解方式配置 XML 方式配置 1. 项目包类结构 2. App.java 启动类 代码 3. CustomerService.java 待切的类 ......
aop 面向切面编程,允许在 java 应用中的方法调用的前后做一些处理。
本文通过实例介绍两种主要的spring aop 配置方式:xml 方式配置,注解方式配置
xml 方式配置
1. 项目包类结构
2. app.java 启动类 代码
package wqz.spring.aop; import org.springframework.context.applicationcontext; import org.springframework.context.support.classpathxmlapplicationcontext; public class app { public static void main( string[] args ) { applicationcontext appcontext = new classpathxmlapplicationcontext( new string[]{"springaop.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) { } } }
3. customerservice.java 待切的类
package wqz.spring.aop; public class customerservice { private string name; private string url; public string getname() { return name; } public void setname(string name) { this.name = name; } public string geturl() { return url; } 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 url:"+this.url); } public void printthrowexception() { throw new illegalargumentexception(); } }
4. 切面处理类,有四种方式(before,after,around,exception,自行百度)
package wqz.spring.aop; import java.lang.reflect.method; import org.springframework.aop.afterreturningadvice; public class hijackaftermethod implements afterreturningadvice { public void afterreturning(object arg0, method arg1, object[] arg2, object arg3) throws throwable { system.out.println("after method hijack"); } }
package wqz.spring.aop; import java.util.arrays; import org.aopalliance.intercept.methodinterceptor; import org.aopalliance.intercept.methodinvocation; public class hijackaroundmethod implements methodinterceptor { public object invoke(methodinvocation methodinvocation) throws throwable { system.out.println("method name : " + methodinvocation.getmethod().getname()); system.out.println("method arguments : " + arrays.tostring(methodinvocation.getarguments())); // 相当于 methodbeforeadvice system.out.println("hijackaroundmethod : before method hijacked!"); try { // 调用原方法,即调用customerservice中的方法 object result = methodinvocation.proceed(); // 相当于 afterreturningadvice system.out.println("hijackaroundmethod : after method hijacked!"); return result; } catch (illegalargumentexception e) { // 相当于 throwsadvice system.out.println("hijackaroundmethod : throw exception hijacked!"); throw e; } } }
package wqz.spring.aop; import java.lang.reflect.method; import org.springframework.aop.methodbeforeadvice; public class hijackbeforemethod implements methodbeforeadvice{ public void before(method arg0, object[] arg1, object arg2) throws throwable { system.out.println("hijackbeforemethod : before method hijacked!"); } }
package wqz.spring.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!"); } }
5. spring-aop.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" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 被 监 督 对 象 创 建 --> <bean id="customerservice" class="wqz.spring.aop.customerservice"> <property name="name" value="zoey"/> <property name="url" value="http://shiyanlou.com"/> </bean> <!-- advices 4种 类 型 的 通 知 对应的类分别如下--> <bean id="hijackbeforemethodbean" class="wqz.spring.aop.hijackbeforemethod"/> <bean id="hijackaftermethodbean" class="wqz.spring.aop.hijackaftermethod"/> <bean id="hijackthrowexceptionbean" class="wqz.spring.aop.hijackthrowexception"/> <bean id="hijackaroundmethodbean" class="wqz.spring.aop.hijackaroundmethod" /> <!-- pointcut 根据名字或者正则 劫持 method --> <!-- 字符串匹配 创建 劫持bean --> <bean id="customerpointcut" class="org.springframework.aop.support.namematchmethodpointcut"> <!-- 定义劫持方法名 --> <property name="mappedname" value="printname" /> </bean> <!-- 字符串匹配创建一个默认的pointcut advisor bean 用于 给 pointcut 配置 advice劫持 对象--> <bean id="customeradvisor" class="org.springframework.aop.support.defaultpointcutadvisor"> <!-- 将 定义的 customerpointcut 劫持到的方法 交由 advice处理 --> <property name="pointcut" ref="customerpointcut" /> <property name="advice" ref="hijackaroundmethodbean" /> </bean> <!-- 正则表达式 创建劫持bean <bean id="customeradvisor" class="org.springframework.aop.support.regexpmethodpointcutadvisor"> <property name="patterns"> <list> <value>.*url.*</value> </list> </property> <property name="advice" ref="hijackaroundmethodbean" /> </bean> --> <!-- 创 建 代 理 对 象 --> <bean id="customerserviceproxy" class="org.springframework.aop.framework.proxyfactorybean"> <!-- 你 想 要 劫 持 的 对 象 --> <property name="target" ref="customerservice"/> <!-- 你想使用 哪个对象 劫持 target --> <property name="interceptornames"> <list> <value>customeradvisor</value> </list> </property> </bean> </beans>
6. 运行结果
十月 24, 2018 12:30:41 上午 org.springframework.context.support.classpathxmlapplicationcontext preparerefresh 信息: refreshing org.springframework.context.support.classpathxmlapplicationcontext@ef98ce0: startup date [wed oct 24 00:30:41 cst 2018]; root of context hierarchy 十月 24, 2018 12:30:41 上午 org.springframework.beans.factory.xml.xmlbeandefinitionreader loadbeandefinitions 信息: loading xml bean definitions from class path resource [springaop.xml] 十月 24, 2018 12:30:41 上午 org.springframework.beans.factory.support.defaultlistablebeanfactory preinstantiatesingletons 信息: pre-instantiating singletons in org.springframework.beans.factory.support.defaultlistablebeanfactory@6b308ce5: defining beans [customerservice,hijackbeforemethodbean,hijackaftermethodbean,hijackthrowexceptionbean,hijackaroundmethodbean,customerpointcut,customeradvisor,customerserviceproxy]; root of factory hierarchy ************************* method name : printname method arguments : [] hijackaroundmethod : before method hijacked! customer name:zoey hijackaroundmethod : after method hijacked! ************************* customer url:http://shiyanlou.com *************************
注解方式
1. 包结构
2. 相关类代码
package wqz.app; import org.springframework.context.support.classpathxmlapplicationcontext; import wqz.service.userserviceinterface; public class app { public static void main(string[] args) { classpathxmlapplicationcontext context = new classpathxmlapplicationcontext("root-context.xml"); userserviceinterface interface1 = context.getbean(userserviceinterface.class); interface1.sayhello(); context.close(); } }
package wqz.service; import org.springframework.stereotype.service; @service public class userservice implements userserviceinterface{ public userservice() { // todo auto-generated constructor stub system.out.println(this.getclass().getsimplename() + " constructor!!!!"); } public void sayhello(){ try { thread.sleep(1000); } catch (interruptedexception e) { // todo auto-generated catch block e.printstacktrace(); } system.out.println("========== hello ========="); } }
package wqz.service; public interface userserviceinterface { public void sayhello(); }
package wqz.spring.aop.annotion; import org.aspectj.lang.proceedingjoinpoint; import org.aspectj.lang.annotation.around; import org.aspectj.lang.annotation.aspect; import org.springframework.stereotype.service; @service @aspect public class timemonitor { @around("execution(* wqz.service.userservice.sayhello())") public void monitoraround(proceedingjoinpoint pjp)throws throwable{ system.out.println("method start time: " + system.currenttimemillis()); object re = pjp.proceed(); system.out.println("method end time: " + system.currenttimemillis()); } }
3. 运行结果
十月 24, 2018 12:56:00 上午 org.springframework.context.support.classpathxmlapplicationcontext preparerefresh 信息: refreshing org.springframework.context.support.classpathxmlapplicationcontext@a8e13ab: startup date [wed oct 24 00:56:00 cst 2018]; root of context hierarchy 十月 24, 2018 12:56:00 上午 org.springframework.beans.factory.xml.xmlbeandefinitionreader loadbeandefinitions 信息: loading xml bean definitions from class path resource [root-context.xml] 十月 24, 2018 12:56:01 上午 org.springframework.beans.factory.support.defaultlistablebeanfactory preinstantiatesingletons 信息: pre-instantiating singletons in org.springframework.beans.factory.support.defaultlistablebeanfactory@4be6d4a8: defining beans [org.springframework.aop.config.internalautoproxycreator,userservice,timemonitor,org.springframework.context.annotation.internalconfigurationannotationprocessor,org.springframework.context.annotation.internalautowiredannotationprocessor,org.springframework.context.annotation.internalrequiredannotationprocessor,org.springframework.context.annotation.internalcommonannotationprocessor,org.springframework.context.annotation.configurationclasspostprocessor.importawareprocessor]; root of factory hierarchy userservice constructor!!!! method start time: 1540313761817 ========== hello ========= method end time: 1540313762817 十月 24, 2018 12:56:02 上午 org.springframework.context.support.classpathxmlapplicationcontext doclose 信息: closing org.springframework.context.support.classpathxmlapplicationcontext@a8e13ab: startup date [wed oct 24 00:56:00 cst 2018]; root of context hierarchy 十月 24, 2018 12:56:02 上午 org.springframework.beans.factory.support.defaultlistablebeanfactory destroysingletons 信息: destroying singletons in org.springframework.beans.factory.support.defaultlistablebeanfactory@4be6d4a8: defining beans [org.springframework.aop.config.internalautoproxycreator,userservice,timemonitor,org.springframework.context.annotation.internalconfigurationannotationprocessor,org.springframework.context.annotation.internalautowiredannotationprocessor,org.springframework.context.annotation.internalrequiredannotationprocessor,org.springframework.context.annotation.internalcommonannotationprocessor,org.springframework.context.annotation.configurationclasspostprocessor.importawareprocessor]; root of factory hierarchy
注解解析:
timemonitir 类 的注解 :
@service和@aspect,第一个注解是使得timemonitor受spring托管并实例化。@aspect就是使得这个类具有aop功能(你可以这样理解)两个注解缺一不可;
@around表示包围一个函数,也就是可以在函数执行前做一些事情,也可以在函数执行后做一些事情
"execution(* wqz.service.userservice.sayhello())"使用表达式的方式指定了要对哪个函数进行包围
补充:
@around("within(@org.springframework.stereotype.service wqz.spring.*)")
,意思是匹配wqz.spring包下所有使用@service注解的类;
以下文档来自spring中文开发指南2.5文档,由满江红开源组织翻译:
spring aop 用户可能会经常使用
execution
切入点指示符。执行表达式的格式如下:execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
除了返回类型模式(上面代码片断中的ret-type-pattern),名字模式和参数模式以外, 所有的部分都是可选的。返回类型模式决定了方法的返回类型必须依次匹配一个连接点。 你会使用的最频繁的返回类型模式是
*
,它代表了匹配任意的返回类型。 一个全限定的类型名将只会匹配返回给定类型的方法。名字模式匹配的是方法名。 你可以使用*
通配符作为所有或者部分命名模式。 参数模式稍微有点复杂:()
匹配了一个不接受任何参数的方法, 而(..)
匹配了一个接受任意数量参数的方法(零或者更多)。 模式(*)
匹配了一个接受一个任何类型的参数的方法。 模式(*,string)
匹配了一个接受两个参数的方法,第一个可以是任意类型, 第二个则必须是string类型。更多的信息请参阅aspectj编程指南中的部分。下面给出一些通用切入点表达式的例子。
-
任意公共方法的执行:
execution(public * *(..))
-
任何一个名字以“set”开始的方法的执行:
execution(* set*(..))
-
accountservice
接口定义的任意方法的执行:execution(* com.xyz.service.accountservice.*(..))
-
在service包中定义的任意方法的执行:
execution(* com.xyz.service.*.*(..))
-
在service包或其子包中定义的任意方法的执行:
execution(* com.xyz.service..*.*(..))
-
在service包中的任意连接点(在spring aop中只是方法执行):
within(com.xyz.service.*)
-
在service包或其子包中的任意连接点(在spring aop中只是方法执行):
within(com.xyz.service..*)
-
实现了
accountservice
接口的代理对象的任意连接点 (在spring aop中只是方法执行):this(com.xyz.service.accountservice)
'this'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得代理对象在通知体内可用。 -
实现
accountservice
接口的目标对象的任意连接点 (在spring aop中只是方法执行):target(com.xyz.service.accountservice)
'target'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得目标对象在通知体内可用。 -
任何一个只接受一个参数,并且运行时所传入的参数是
serializable
接口的连接点(在spring aop中只是方法执行)args(java.io.serializable)
'args'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得方法参数在通知体内可用。请注意在例子中给出的切入点不同于execution(* *(java.io.serializable))
: args版本只有在动态运行时候传入参数是serializable时才匹配,而execution版本在方法签名中声明只有一个serializable
类型的参数时候匹配。 -
目标对象中有一个
@transactional
注解的任意连接点 (在spring aop中只是方法执行)@target(org.springframework.transaction.annotation.transactional)
'@target'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得注解对象在通知体内可用。 -
任何一个目标对象声明的类型有一个
@transactional
注解的连接点 (在spring aop中只是方法执行):@within(org.springframework.transaction.annotation.transactional)
'@within'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得注解对象在通知体内可用。 -
任何一个执行的方法有一个
@transactional
注解的连接点 (在spring aop中只是方法执行)@annotation(org.springframework.transaction.annotation.transactional)
'@annotation'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得注解对象在通知体内可用。 -
任何一个只接受一个参数,并且运行时所传入的参数类型具有
@classified
注解的连接点(在spring aop中只是方法执行)@args(com.xyz.security.classified)
'@args'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得注解对象在通知体内可用。 -
任何一个在名为'
tradeservice
'的spring bean之上的连接点 (在spring aop中只是方法执行):bean(tradeservice)
-
任何一个在名字匹配通配符表达式'
*service
'的spring bean之上的连接点 (在spring aop中只是方法执行):bean(*service)
****************************************************************
========= over ===========