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方法时都会触发。

你可能感兴趣的:(spring)