欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Spring AOP配置方式

程序员文章站 2022-04-15 11:22:54
AOP 面向切面编程,允许在 java 应用中的方法调用的前后做一些处理。 本文通过实例介绍两种主要的Spring AOP 配置方式:xml 方式配置,注解方式配置 XML 方式配置 1. 项目包类结构 2. App.java 启动类 代码 3. CustomerService.java 待切的类 ......

 


aop 面向切面编程,允许在 java 应用中的方法调用的前后做一些处理。

本文通过实例介绍两种主要的spring aop 配置方式:xml 方式配置,注解方式配置

xml 方式配置

1. 项目包类结构

Spring AOP配置方式

Spring AOP配置方式

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. 包结构

Spring AOP配置方式

Spring AOP配置方式

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 ===========