zoukankan      html  css  js  c++  java
  • Spring 使用介绍(五)—— AOP(一)

    一、简单使用:Hello World实例

    1、定义目标类

    public interface Hello {
        void sayHello();
    }
    public class HelloImpl implements Hello {
        @Override
        public void sayHello() {
            System.out.println("hello matt!");
        }
    }

    2、定义切面支持类

    public class HelloAspect {
        public void beforeAdvice() {
            System.out.println("****beforeAdvice");
        }
    
        public void afterFinnallyAdvice() {
            System.out.println("****afterFinnallyAdvice");
        }
    }

    3、配置切面

    <?xml version="1.0" encoding="UTF-8"?>  
    <beans  
        xmlns="http://www.springframework.org/schema/beans"  
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
        xmlns:aop="http://www.springframework.org/schema/aop"
        xsi:schemaLocation="  
        http://www.springframework.org/schema/beans        
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/aop  
        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">  
        
        <!-- 目标类 --> 
        <bean id="hello" class="cn.matt.aop.HelloImpl"></bean>
        
        <!-- 切面支持类 --> 
        <bean id="helloAspect" class="cn.matt.aop.HelloAspect"></bean>
    
        <aop:config>  
            <!-- 切点 --> 
            <aop:pointcut id="pointcut" expression="execution(* cn.matt.aop..*.*(..))"/>  
            <!-- 切面 -->
            <aop:aspect ref="helloAspect">  
                <aop:before pointcut-ref="pointcut" method="beforeAdvice"/>  
                <aop:after pointcut="execution(* cn.matt.aop..*.*(..))" method="afterFinnallyAdvice"/>  
            </aop:aspect>  
        </aop:config>  
    </beans>

    4、测试

    @Test
    public void testSayHello() {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
        Hello hello = context.getBean(Hello.class);
        hello.sayHello();
    }

    输出:

    ****beforeAdvice
    hello matt!
    ****afterFinnallyAdvice

    二、AOP XML配置

    AOP定义必须放在<aop:config>标签下,该标签下可以有<aop:pointcut>、<aop:advisor>、<aop:aspect>标签,配置顺序不可变

    AOP配置步骤:

    1)声明切面支持bean(通过<bean>标签实例化支持类)

    2)声明切面,引用切面支持bean(切面由<aop:aspect>标签指定,ref属性用来引用切面支持Bean)

    3)声明切入点,有两种方式(注意:切入点也是bean)

      i)使用<aop:pointcut>声明一个切入点Bean,该切入点可被多个切面共享

    <aop:config>  
      <aop:pointcut id="pointcut" expression="execution(* cn.javass..*.*(..))"/>  
      <aop:aspect ref="aspectSupportBean">  
         <aop:before pointcut-ref="pointcut" method="before"/>  
      </aop:aspect>  
    </aop:config>

      ii)匿名切入点Bean,通过pointcut属性指定

    <aop:config>  
      <aop:aspect ref="aspectSupportBean">  
          <aop:after pointcut="execution(* cn.javass..*.*(..))" method="afterFinallyAdvice"/>  
       </aop:aspect>  
    </aop:config> 

    4)声明通知,有五种:

      i)前置通知  方法调用前调用

      ii)后置返回通知  方法调用后且正常返回时调用

      iii)后置异常通知  方法调用后且抛出异常时调用

      iv)后置最终通知  方法调用后始终调用

      v)环绕通知  可控制方法的执行过程,如决定方法是否执行,什么时候执行,执行时替换方法参数,执行后替换返回值等

    注意:当method属性需要指定支持类的某个重载方法时,需要指定参数列表

    具体实例如下:

    目标接口及实现

    public interface Hello {
        void sayBefore(String str);
        String sayAfterReturning(String str);
        void sayAfterThrowing();
        void sayAfterFinnally();
        void sayAround(String str);
    }
    public class HelloImpl implements Hello {
        @Override
        public void sayBefore(String str) {
            System.out.println("sayBefore " + str);
        }
    
        @Override
        public String sayAfterReturning(String str) {
            System.out.println("sayAfterReturning " + str);
            return "returning";
        }
    
        @Override
        public void sayAfterThrowing() {
            System.out.println("sayAfterThrowing");
            throw new RuntimeException("test exception!");
        }
    
        @Override
        public void sayAfterFinnally() {
            System.out.println("sayAfterFinnally");
        }
    
        @Override
        public void sayAround(String str) {
            System.out.println("sayAround " + str);
        }
    }

    AOP支持类

    public class HelloAspect {
        public void beforeAdvice(String param) {  
            System.out.println("****beforeAdvice " + param);
        } 
    
        public void afterReturningAdvice(String retVal) {
            System.out.println("****afterFinnallyAdvice " + retVal);
        }
        
        public void afterThrowingAdvice(Exception ex) {
            System.out.println("****afterThrowingAdvice " + ex.getMessage());
        }
        
        public void afterFinnallyAdvice() {
            System.out.println("****afterFinnallyAdvice ");
        }
        
        public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {  
            System.out.println("===========around before advice");  
            Object retVal = pjp.proceed(new Object[] {"replace"});  
            System.out.println("===========around after advice");  
            return retVal;  
        }  
    }

    AOP配置

        <!-- 目标类实例化 --> 
        <bean id="aopHello" class="cn.matt.aop.HelloImpl"></bean>
        
        <!-- aop支持类实例化 --> 
        <bean id="helloAspect" class="cn.matt.aop.HelloAspect"></bean>
        
        <!-- aop配置 --> 
        <aop:config>  
            <aop:aspect ref="helloAspect">  
                <!-- 前置通知(简单) --> 
                <aop:before pointcut="execution(* cn.matt.aop..*.sayHello(..))" 
                                     method="beforeAdvice"/> 
                <!-- 前置通知(复杂) --> 
                <aop:before pointcut="execution(* cn.matt.aop..*.sayBefore(..)) and args(param)" 
                                     method="beforeAdvice(java.lang.String)"   
                                     arg-names="param"/> 
                <!-- 后置返回通知 -->
                <aop:after-returning pointcut="execution(* cn.matt.aop..*.sayAfterReturning(..))"  
                                  method="afterReturningAdvice"  
                                  arg-names="retVal"    
                                  returning="retVal"/> 
                <!-- 后置异常通知 -->
                <aop:after-throwing pointcut="execution(* cn.matt.aop..*.sayAfterThrowing(..))"  
                                  method="afterThrowingAdvice"  
                                  arg-names="exception"  
                                  throwing="exception"/>
                <!-- 后置最终通知 -->
                <aop:after pointcut="execution(* cn.matt.aop..*.sayAfterFinnally(..))"  
                                   method="afterFinnallyAdvice"/> 
                 <!-- 环绕通知 -->
                <aop:around pointcut="execution(* cn.matt.aop..*.sayAround(..))"  
                                     method="aroundAdvice"/>  
            </aop:aspect>  
        </aop:config> 

    测试

    public class HelloTest {
        
        private static Hello hello;
        
        static {
            ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
            hello = context.getBean(Hello.class);
        }
        
        @Test
        public void testSayBefore() {
            hello.sayBefore("opjuy");
        }
        
        @Test
        public void testSayAfterReturning() {
            hello.sayAfterReturning("opjuy");
        }
        
        @Test(expected = RuntimeException.class)
        public void testSayAfterThrowing() {
            hello.sayAfterThrowing();
        }
        
        @Test
        public void testSayAfterFinnally() {
            hello.sayAfterFinnally();
        }
        
        @Test
        public void testSayAround() {
            hello.sayAround("around");
        }
    }

    三、AOP注解配置

    使用@AspectJ风格的注解配置,首先须添加如下配置: 

    <aop:aspectj-autoproxy />  

    具体使用步骤如下:

    1)使用@Aspect将切面支持类声明为切面,并实例化bean

    @Aspect()  
    public class Aspect{  
        ……  
    }  
    <bean id="aspect" class="……Aspect"/>  

    2)使用@Pointcut+方法(方法必须是返回void类型)声明切入点

    @Pointcut(value="切入点表达式", argNames = "参数名列表")  
    public void pointcutName(……) {}

    3)声明通知

    @Before(value = "切入点表达式或命名切入点", argNames = "参数列表参数名") 
    @AfterReturning(value="切入点表达式或命名切入点",  pointcut="切入点表达式或命名切入点",  argNames="参数列表参数名",  returning="返回值对应参数名") 
    @AfterThrowing (value="切入点表达式或命名切入点",  pointcut="切入点表达式或命名切入点",  argNames="参数列表参数名",  throwing="异常对应参数名")  
    @After (value="切入点表达式或命名切入点",  argNames="参数列表参数名") 
    @Around (value="切入点表达式或命名切入点",  argNames="参数列表参数名")  

    注意:

    i)value和pointcut均可指定切入点表达式或命名切入点,如两者同时指定,则pointcut覆盖value

    ii)使用命名切入点时,须指定切入点名及其参数,若无参数,括号也不可省略,如:

      错误:@Before(value = "pointcut1")

      正确:@Before(value = "pointcut1()")

      正确:@Before(value = "pointcut2(param)", argNames = "param")

    具体实例如下:

    目标接口及实现,同xml配置实例

    AOP支持类

    @Aspect
    public class HelloAspect {
        
        // 切点1
        @Pointcut(value = "execution(* cn.matt.aop..*.sayHello(..))")
        public void pointcut1() {}
        
        // 切点2
        @Pointcut(value = "execution(* cn.matt.aop..*.sayBefore(..)) && args(param)", argNames = "param")
        public void pointcut2(String param) {}
        
        // 前置通知(简单)
        @Before(value = "pointcut1()")
        public void beforeAdvice() {
            System.out.println("****beforeAdvice");
        }
        
        // 前置通知(复杂)
        @Before(value = "pointcut2(param)", argNames = "param")
        public void beforeAdvice(String param) {  
            System.out.println("****beforeAdvice " + param);
        } 
    
        // 后置返回通知
        @AfterReturning(value = "execution(* cn.matt.aop..*.sayAfterReturning(..))", argNames = "retVal", returning = "retVal")
        public void afterReturningAdvice(String retVal) {
            System.out.println("****afterFinnallyAdvice " + retVal);
        }
        
        // 后置异常通知
        @AfterThrowing(value = "execution(* cn.matt.aop..*.sayAfterThrowing(..))", argNames = "ex", throwing = "ex")
        public void afterThrowingAdvice(Exception ex) {
            System.out.println("****afterThrowingAdvice " + ex.getMessage());
        }
        
        // 后置最终通知
        @After(value = "execution(* cn.matt.aop..*.sayAfterFinnally(..))")
        public void afterFinnallyAdvice() {
            System.out.println("****afterFinnallyAdvice ");
        }
        
        // 环绕通知
        @Around(value = "execution(* cn.matt.aop..*.sayAround(..))")
        public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {  
            System.out.println("===========around before advice");  
            Object retVal = pjp.proceed(new Object[] {"replace"});  
            System.out.println("===========around after advice");  
            return retVal;  
        }  
    }

    AOP配置

        <!-- 目标类实例化 --> 
        <bean id="aopHello" class="cn.matt.aop.HelloImpl"></bean>
        
        <!-- aop支持类实例化 --> 
        <bean id="helloAspect" class="cn.matt.aop.HelloAspect"></bean>
        
        <!-- 开启aop注解支持 --> 
        <aop:aspectj-autoproxy/> 

    测试,同xml配置实例

    参考:

    第六章  AOP 之 6.1 AOP基础 ——跟我学spring3

    第六章  AOP 之 6.2 AOP的HelloWorld ——跟我学spring3

    第六章  AOP 之 6.3 基于Schema的AOP ——跟我学spring3

    第六章  AOP 之 6.4 基于@AspectJ的AOP ——跟我学spring3

  • 相关阅读:
    H5版俄罗斯方块(5)---需求演进和产品迭代
    vim 常用 NERDTree 快捷键
    C和C++中include 搜索路径的一般形式以及gcc搜索头文件的路径
    MySQL复制协议
    深入解析MySQL replication协议
    Install CodeBlocks in CentOS 7
    Impala 源码分析-FE
    Elasticsearch 6.x 的分页查询数据
    1、树莓派3B开箱+安装系统
    Python创建ES索引
  • 原文地址:https://www.cnblogs.com/MattCheng/p/8926732.html
Copyright © 2011-2022 走看看