Spring学习之第一个AOP程序

 IOC和AOP是Spring的两大基石,AOP(面向方面编程),也可称为面向切面编程,是一种编程范式,提供从另外一个角度来考虑程序结构从而完善面向对象编程(OOP)。java

  在进行 OOP 开发时,都是基于对组件(好比类)进行开发,而后对组件进行组合,OOP 最大问题就是没法解耦组件进行开发,好比咱们上边举例,而 AOP 就是为了克服这个问题而出现的,它来进行这种耦合的分离。AOP 为开发者提供一种进行横切关注点(好比日志关注点)分离并织入的机制,把横切关注点分离,而后经过某种技术织入到系统中,从而无耦合的完成了咱们的功能。正则表达式

一、AOP基本概念

  • 链接点( Jointpoint) : 表示须要在程序中插入横切关注点的扩展点,链接点多是类初始化、方法执行、 方法调用、字段调用或处理异常等等, Spring 只支持方法执行链接点, 在 AOP 中表示为“在哪里干” ;
  • 切入点( Pointcut) : 选择一组相关链接点的模式, 便可以认为链接点的集合,Spring 支持 perl5 正则表达式和 AspectJ 切入点模式, Spring 默认使用 AspectJ 语法, 在 AOP 中表示为“在哪里干的集合” ;
  • 通知( Advice) : 在链接点上执行的行为, 通知提供了在 AOP 中须要在切入点所选择的链接点处进行扩展示有行为的手段; 包括前置通知( before advice)、后置通知(after advice)、环绕通知( around advice), 在 Spring 中经过代理模式实现AOP,并经过拦截器模式以环绕链接点的拦截器链织入通知; 在 AOP 中表示为“干什么”;
  • 方面/切面( Aspect): 横切关注点的模块化,能够认为是通知、引入和切入点的组合; 在 Spring 中能够使用 Schema 和@AspectJ 方式进行组织实现; 在 AOP 中表示为“在哪干和干什么集合” ;
  • 引入( inter-type declaration) : 也称为内部类型声明, 为已有的类添加额外新的字段或方法, Spring 容许引入新的接口(必须对应一个实现)到全部被代理对象(目标对象) , 在 AOP 中表示为“干什么(引入什么) ” ;
  • 目标对象( Target Object) : 须要被织入横切关注点的对象,即该对象是切入点选择的对象,须要被通知的对象,从而也可称为“被通知对象”;因为 Spring AOP经过代理模式实现,从而这个对象永远是被代理对象, 在 AOP 中表示为“对谁干” ;
  • AOP 代理( AOP Proxy) : AOP 框架使用代理模式建立的对象,从而实如今链接点处插入通知(即应用切面) ,就是经过代理来对目标对象应用切面。在 Spring中, AOP 代理能够用 JDK 动态代理或 CGLIB 代理实现,而经过拦截器模型应用切面。
  • 织入( Weaving) : 织入是一个过程,是将切面应用到目标对象从而建立出 AOP代理对象的过程, 织入能够在编译期、类装载期、运行期进行。

 Spring有哪些通知类型呢?

  • 前置通知( Before Advice) :在切入点选择的链接点处的方法以前执行的通知,该通知不影响正常程序执行流程(除非该通知抛出异常,该异常将中断当前方法链的执行而返回)。
  • 后置通知( After Advice) : 在切入点选择的链接点处的方法以后执行的通知,包括以下类型的后置通知:
    • 后置返回通知( After returning Advice) :在切入点选择的链接点处的方法正常执行完毕时执行的通知, 必须是链接点处的方法没抛出任何异常正常返回时才调用后置通知。
    • 后置异常通知( After throwing Advice) : 在切入点选择的链接点处的方法抛出异常返回时执行的通知, 必须是链接点处的方法抛出任何异常返回时才调用异常通知。
    • 后置最终通知( After finally Advice) : 在切入点选择的链接点处的方法返回时执行的通知,无论抛没抛出异常都执行,相似于 Java 中的 finally 块。
  • 环绕通知( Around Advices): 环绕着在切入点选择的链接点处的方法所执行的通知,环绕通知能够在方法调用以前和以后自定义任何行为,而且能够决定是否执行链接点处的方法、替换返回值、抛出异常等等。

  在 AOP 中,经过切入点选择目标对象的链接点,而后在目标对象的相应链接点处织入通知,而切入点和通知就是切面(横切关注点),而在目标对象链接点处应用切面的实现方式是经过 AOP 代理对象,如图所示。spring

 二、AOP的HelloWorld程序

  AOP代理就是 AOP框架经过代理模式建立的对象,Spring使用 JDK动态代理或 CGLIB代理来实现, Spring 缺省使用 JDK 动态代理来实现,从而任何接口均可被代理,若是被代理的对象实现不是接口将默认使用 CGLIB 代理,不过 CGLIB 代理固然也可应用到接口。AOP 代理的目的就是将切面织入到目标对象。express

  新建工程,导入Spring中对应的包,最后引入的jar包以下所示(有些包spring的lib下没有,须要另外下载):编程

(1)定义目标接口框架

package com.log;

public interface IHelloWorldService {
    public void sayHello();
}

(2)定义目标接口实现类ide

复制代码
package com.log;

public class HelloWorldService implements IHelloWorldService {
    @Override
    public void sayHello() {
        System.out.println("---hello world---");
    }
}
复制代码

(3)定义切面支持类模块化

复制代码
package com.log;

public class HelloWorldAspect {
    public void beforeAdvice() {
        System.out.println("---before advice---");
    }
    
    public void afterAdvice() {
        System.out.println("---after advice---");
    }
}
复制代码

(4)在XML中进行配置测试

复制代码
<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-2.0.xsd
            http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">

    <!-- 配置目标类 -->
    <bean id="helloWorldService" class="com.log.HelloWorldService"/>
    <!-- 配置切面 -->
    <bean id="aspect" class="com.log.HelloWorldAspect"/>
    <aop:config>
        <aop:pointcut id="pointcut" expression="execution(* com.log..*.*(..))"/>
        <!-- aop:aspect的ref引用切面支持类的方法 -->
        <aop:aspect ref="aspect">
            <aop:before pointcut-ref="pointcut"
                method="beforeAdvice"/>
            <aop:after pointcut-ref="pointcut"
                method="afterAdvice"/>
        </aop:aspect>
    </aop:config>
</beans>
复制代码

  切入点使用<aop:config>标签下的<aop:pointcut>配置, expression属性用于定义切入点模式,默认是AspectJ语法,“ execution(* cn.javass..*.*(..))”表示匹配cn.javass包及子包下的任何方法执行。关于expression属性如何配置请点击:expression配置spa

  切面使用<aop:config>标签下的<aop:aspect>标签配置,其中“ ref”用来引用切面支持类的方法。
  前置通知使用<aop:aspect>标签下的<aop:before>标签来定义, pointcut-ref属性用于引用切入点Bean, 而method用来引用切面通知实现类中的方法,该方法就是通知实现,即在目标类方法执行以前调用的方法。
  最终通知使用<aop:aspect>标签下的<aop:after >标签来定义,切入点除了使用pointcut-ref属性来引用已经存在的切入点,也能够使用pointcut属性来定义,如pointcut="execution(* cn.javass..*.*(..))", method属性一样是指定通知实现,即在目标类方法执行以后调用的方法。

(5)测试运行

复制代码
package com.log;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AopTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("aopBean.xml");
        IHelloWorldService hello = context.getBean("helloWorldService", IHelloWorldService.class);
        hello.sayHello();
        
        HelloWorldAspect advice = context.getBean("aspect", HelloWorldAspect.class);
        advice.beforeAdvice();
    }
}
复制代码

(6)输出结果

 

相关文章
相关标签/搜索