zoukankan      html  css  js  c++  java
  • 【Spring开发】—— AOP之方法级拦截

    前言:

    前面介绍了Spring的核心模块以及相关的依赖注入等概念。这篇讲解一下spring的另一个重点,AOP面向切面编程。

      说道AOP不得不提到几个概念:

      切面:也就是我们自己的一些业务方法。

      通知:用于拦截时出发的操作。

      切点:具体拦截的某个业务点。

      这样说可能还是有点抽象,举个例子,下面是一个纸糊的多面体。

      每个面都是一个业务方法,我们通过刺穿每一个面,都可以进入到内部,这个面就是一个切面

      刺穿的时候会发出声响,这就是一种通知

      而具体从哪个面刺入,这就是一个切入点的选择了。

      这样说,应该能稍微了解一点。

      那么下面看一个简单的例子:

      为了便于理清关系,先放上一张相关的类图:

      首先定义个接口

    1 public interface IService {
    2  public void withAop();
    3  public void withoutAop();
    4 }

      有了接口,当然需要一个实现类

     1 public class TestAOP implements IService {
     2  private String name;
     3  public void withAop() {
     4   System.out.println("with AOP name:"+name);
     5  }
     6  public void withoutAop() {
     7   System.out.println("without AOP name:"+name);
     8  }
     9  public String getName() {
    10   return name;
    11  }
    12  public void setName(String name) {
    13   this.name = name;
    14  }
    15 }

      这个实现类实现了接口定义的两个方法,下面我们定义几种拦截方式,这些拦截方式通过拦截的位置或者时机不同而不同。

      通常有方法前拦截方法后拦截,以及异常拦截。通过在这些拦截中编写自己的业务处理,可以达到特定的需求。

      方法前拦截,需要实现MethodBeforeAdvice接口,并填写before方法。这样,当拦截到某个方法时,就会在方法执行前执行这个before()方法。

    1 public class BeforeAOPInterceptor implements MethodBeforeAdvice{
    2  public void before(Method method, Object[] args, Object instance)
    3    throws Throwable {
    4   System.out.println("before()"+method.getName());
    5  }
    6 }

      同理,方法后拦截,也是如此。需要实现AfterReturningAdvice接口。

    1 public class AfterAOPInterceptor implements AfterReturningAdvice{
    2  public void afterReturning(Object value, Method method, Object[] args,
    3    Object instance) throws Throwable {
    4   System.out.println("after()"+method.getName());
    5  }
    6 }

      以及异常拦截。

    1 public class ThrowsAOPInterceptor implements ThrowsAdvice{ 
    2  public void afterThrowing(Method method,Object[] args,Object instance,AccountException ex) throws Throwable{
    3   System.out.println("after()"+method.getName()+"throws exception:"+ex);
    4  }
    5  public void afterThrowing(NullPointerException ex) throws Throwable{
    6   System.out.println("throws exception:"+ex);
    7  }
    8 }

      接下来就需要配置一下spring的配置文件,把拦截器与切面方法关联起来。

      参考上面的图,可以看到配置文件中的层次关系。

     1 <?xml version="1.0" encoding="UTF-8"?> 
     2 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     3 xmlns="http://www.springframework.org/schema/beans" 
     4 xsi:schemaLocation="http://www.springframework.org/schema/beans 
     5 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> 
     6 <!-- 通过名字匹配 --> 
     7 <!-- 
     8   <bean id="before" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor"> 
     9     <property name="advice"> 
    10       <bean class="com.test.pointcut.beforeAOP"></bean> 
    11     </property> 
    12     <property name="mappedName" value="withoutAop"></property> 
    13   </bean> 
    14 --> 
    15 <!-- 通过正则表达式 匹配 --> 
    16   <bean id="before" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> 
    17     <property name="advice"> 
    18       <bean class="com.test.pointcut.BeforeAOPInterceptor"></bean> 
    19     </property> 
    20   <property name="patterns"> 
    21     <list> 
    22       <value>.*out.*</value> 
    23     </list> 
    24   </property> 
    25   </bean> 
    26   <bean id="after" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> 
    27     <property name="advice"> 
    28       <bean class="com.test.pointcut.AfterAOPInterceptor"></bean> 
    29     </property> 
    30     <property name="patterns"> 
    31       <list> 
    32         <value>.*out.*</value> 
    33       </list> 
    34     </property> 
    35   </bean> 
    36   <bean id="exception" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> 
    37     <property name="advice"> 
    38       <bean class="com.test.pointcut.ThrowsAOPInterceptor"></bean> 
    39     </property> 
    40     <property name="patterns"> 
    41       <list> 
    42         <value>.*out.*</value> 
    43       </list> 
    44     </property> 
    45   </bean> 
    46 <!-- --> 
    47   <bean id="aopService" class="org.springframework.aop.framework.ProxyFactoryBean"> 
    48     <property name="interceptorNames"> 
    49       <list> 
    50         <value>before</value> 
    51         <value>after</value> 
    52         <value>exception</value> 
    53       </list> 
    54     </property> 
    55     <property name="target"> 
    56       <bean class="com.test.pointcut.TestAOP"> 
    57         <property name="name" value="Hello"></property> 
    58       </bean> 
    59     </property> 
    60   </bean> 
    61 </beans>

      ProxyFactoryBean下有两个属性,一个想要拦截的目标类,一个是拦截器。而拦截器又包括两种,主要是因为定位方法的不同而分类。分别是:

      RegexpMethodPointcutAdvisor 通过正则表达式来定位业务方法。

      NameMatchMethodPointcutAdvisor 通过名字来定位业务方法。

      定位到了业务方法,还需要添加响应的拦截器,拦截器就是上面的三种。

      最后看一下测试的方法:

    public class TestMain {
     public static void main(String[] args) {
      XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("applicationContextAOP.xml"));
      IService hello = (IService)factory.getBean("aopService");
      hello.withAop();
      hello.withoutAop();
     }
    }

      我们上面通过正则表达式定位到所有包含out的方法,其实就是withoutAOP方法。这样当执行withoutAop方法时,会触发拦截器的操作。

      执行结果:

    2014-12-4 16:46:58 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
    信息: Loading XML bean definitions from class path resource [applicationContextAOP.xml]
    with AOP name:Hello
    before()withoutAop
    without AOP name:Hello
    after()withoutAop

      总结:

      这是通过定义切入点的方式来实现AOP,通过这种编程方式,可以针对业务方法进行包装或者监控

      举个例子,比如有个业务方法想要进行数据的查询,那么可以再这个查询前面获取JDBC连接池的连接,这样就对用户屏蔽掉了复杂的申请过程。而销毁就可以放在方法后拦截函数里。

      再比如,想要监控某个业务方法呗执行了多少次,那么就可以通过这样一种拦截方式,进行信息的统计,计数或者计时!

      妙处多多,还待完善!

      参考:《java web王者归来》《spring实战》《spring权威指南》

  • 相关阅读:
    javaScript 与JQuery 计算器练习
    git在java项目中配置.gitignore不生效的解决办法
    mysql8主从复制配置
    ES6的Promise实例
    常用正则表达式
    Redis在Windows环境下后台启动
    Redis数据操作命令 二
    Redis数据操作命令
    List集合学习笔记
    MyBatis学习链接
  • 原文地址:https://www.cnblogs.com/xing901022/p/4143696.html
Copyright © 2011-2022 走看看