zoukankan      html  css  js  c++  java
  • Spring之AOP

      什么是AOP?

      AOP即面向切面编程,比如某个项目有很多个模块,每个模块都为特定的业务领域提供服务,但是这些模块都需要一些辅助功能,例如安全和事务管理。

      和大多数技术一样,AOP有自己的术语。描述切面的常用术语有通知(advice)、切点(pointcut)、和连接点(join point)。

      通知(advice)定义了切面什么时候使用。除了描述切面要完成的工作,通知还解决了何时执行这个工作的问题。它应该应用于某个方法之前?之后?之前和之后?还是在方法发生异常时?

      Spring切面可以应用5种类型的通知:

        Before---在方法调用之前。

        After---在方法调用之后,无论是否发生异常。

        After-returning---在方法成功执行之后。

        After-throwing---在方法发生异常之后。

        Around---包裹被通知的方法,在方法调用之前和之后都执行。

      Spring提供了4种各具特色的AOP支持:

        基于代理的经典AOP

        @AspectJ注解驱动的切面

        纯POJO切面

        注入式AspectJ切面

      在Spring XML中声明切面

        <aop:advisor>    定义AOP通知器

        <aop:after>     定义AOP后置通知(不管方法是否执行成功)

        <aop:after-returning>定义AOP after-returning通知

        <aop:after-throwing>定义AOP after-throwing通知

        <aop:around>    定义AOP环绕通知

        <aop:aspect>    定义切面

        <aop:aspect-autoproxy>启动@Aspect注解驱动的切面

        <aop:before>    定义AOP前置通知

        <aop:config>    顶层的AOP配置元素,大多数的<aop:*>都需要包含在<aop:config>中

        <aop:declare-parents>为被通知的对象引入额外的接口,并透明的实现

        <aop:pointcut>   定义切点

    定义一个主人类Person

    复制代码
    package com.lmy.spring;
    
    import org.springframework.stereotype.Component;
    
    @Component("xiaoming")
    public class Person{
      //表演之前喂食
     public void beforePlay(){
        System.out.println("喂食");
     }
      //表演之后鼓掌
     public void afterPlay(){
      System.out.println("鼓掌");
     }  
    
     
    }
    复制代码

    宠物狗类Dog

    复制代码
    package com.lmy.spring;
    
    import org.springframework.stereotype.Component;
    
    @Component("kala")
    public class Dog{
     public void play(){
      System.out.println("做算术");
     }
    }
    复制代码

    宠物在表演之前主人应该先喂食,通过注解@Component把两个类定义成Spring Bean。

    然后在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"
            xmlns:context="http://www.springframework.org/schema/context"
            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/context
                http://www.springframework.org/schema/context/spring-context-3.0.xsd
                http://www.springframework.org/schema/aop
                http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
                
                >
                <context:component-scan base-package="com.lmy.spring"></context:component-scan>
            <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
        <aop:config>
         <aop:aspect ref="person">
             <aop:pointcut expression="execution(* com.lmy.spring.Dog.play(..))" id="dog" />
    <aop:before method="beforePlay" pointcut-ref="dog" />
    <aop:after method="afterPlay" pointcut-ref="dog" />
    
         </aop:aspect>
      </aop:config>
    </beans>
    复制代码

    编写代码测试结果

        @Test
        public void test1(){
            ApplicationContext  ctx = new ClassPathXmlApplicationContext("spring.xml");
            Dog kala = (Dog)ctx.getBean("kala");
            kala.play();
        }

    输出:

        喂食
        做算术
        鼓掌

    两个类的代码从表面上没有任何关联的地方,但是通过AOP通知,在Dog类的Bean对象kala调用play方法时,会被Spring拦截,aop:before定义了匹配的切点方法之前执行的前置方法,aop:after定义了在切点匹配的方法结束之后执行的方法。

    上面的例子虽然实现了表演前喂食和表演后鼓掌的功能,但是Person根本不知道是给谁喂食和鼓掌,所以代码还需要改进一下。

    Dog在play的时候传一个名字进去

        public void play(String name) {
            System.out.println(name+"在做算术");
            
        }

    修改Person类的两个方法,都加上参数String name

    复制代码
        // 表演之前喂食
        public void beforePlay(String name) {
            System.out.println("给"+dog.getName()+"喂食");
            
        }
    
        // 表演之后鼓掌
        public void afterPlay(String name) {
            System.out.println("给"+dog.getName()+"鼓掌");
        }
    复制代码

    现在要做的就是在匹配的切点方法之前和之后执行的方法添加参数。

    修改XML配置

    复制代码
        <aop:config>
            <aop:aspect ref="xiaoming">
                <aop:pointcut expression="execution(* com.lmy.spring.Dog.play(com.lmy.spring.Dog)) and args(kala)"
                    id="dog" />
                <aop:before method="beforePlay" pointcut-ref="dog" arg-names="kala" />
                <aop:after method="afterPlay" pointcut-ref="dog" arg-names="kala" />
            </aop:aspect>
        </aop:config>
    复制代码

    然后调用

        @Test
        public void test1(){
            ApplicationContext  ctx = new ClassPathXmlApplicationContext("spring.xml");
            Dog pf = (Dog)ctx.getBean("kala");
            pf.play("kala");
        }

    这样就会输入带名字的信息了。

    PS:为了简单,所以没有使用接口,严格来说应该有Animal接口,Dog实现该接口,切点的配置就应该配置成

    <aop:pointcut expression="execution(* com.lmy.spring.Animal.play(String)) and args(kala)"
    id="animal" />

    所有实现了Animal接口的类当调用play方法时都会触发。

  • 相关阅读:
    Record of coding:Codeforces 1093E
    【刷题记录】网络流24题等
    【模板归纳】网络流及费用流
    【刷题记录】BZOJ2154 crash的数字表格 莫比乌斯反演
    【刷题记录】SDOI2017数字表格
    算法总结 给定范围内最大公约数为某一定值的数对个数的算法
    刷题记录【BZOJ2440 完全平方数】数论、组合数学、莫比乌斯函数
    刷题记录 【HAOI2007】理想的正方形 二维st表
    刷题记录【ZJOJ2005午餐】,贪心+DP或者
    刷题记录【ZJOI2007棋盘制作】二维DP,悬线法。。。
  • 原文地址:https://www.cnblogs.com/bluedy1229/p/3604547.html
Copyright © 2011-2022 走看看