zoukankan      html  css  js  c++  java
  • Spring AOP配置方式


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

  • 相关阅读:
    How to Build Office Developer Tools Projects with TFS Team Build 2012
    查看hyper-v主机mac地址
    “Stamping” PDF Files Downloaded from SharePoint 2010
    PostgreSQL体系基本概念
    PostgreSQL 安装
    HDFS+MapReduce+Hive+HBase十分钟快速入门
    光照计算公式
    游戏中的碰撞
    数组
    扑克牌概率
  • 原文地址:https://www.cnblogs.com/yelao/p/9840601.html
Copyright © 2011-2022 走看看