Spring的AOP特性

一、AOP简介

   AOP是Aspect-Oriented Programming的缩写,即面向切面编程。利用oop思想,可以很好的处理业务流程,但是不能把系统中某些特定的重复性行为封装到模块中。例如,在很多业务中都需要记录操作日志,结果我们不得不在业务流程中嵌入大量的日志记录代码。无论是对业务代码还是对日志记录代码来说,维护都是相当复杂的。由于系统中嵌入了这种大量的与业务无关的其他重复性代码,系统的复杂性、代码的重复性增加了。维护起来会更加复杂。

   AOP可以很好解决这个问题,AOP关注的是系统的“截面”,在适当的时候“拦截”程序的执行流程,把程序的预处理和后期处理交给某个拦截器来完成。比如,访问数据库时需要记录日志,如果使用AOP的编程思想,那么在处理业务流程时不必在去考虑记录日志,而是把它交给一个专门的例子记录模块去完成。这样,程序员就可以集中精力去处理业务流程,而不是在实现业务代码时嵌入日志记录代码,实现业务代码与非业务代码的分别维护。在AOP术语中,这称为关注点分离。AOP的常见应用有日志拦截、授权认证、数据库的事务拦截和数据审计等。

二、AOP优点

  当一个方法,对不同的用户的功能要求不满足时,那么需要在此方法的地方就可以出现变化;在这个变化点进行封转,留下一个可扩展的接口,便于后期的维护;

三、AOP专业名词

(1)通知(增强)Advice

  通知定义了切面是什么以及何时使用,应该应用在某个方法被调用之前?之后?还是抛出异常时?等等。

(2)连接点 Join point

  连接点是在应用执行过程中能够插入切面的一个点。这个点可以是调用方法时,抛出异常时,甚至修改一个字段时。切面代码可以利用这些点插入到应用的正常流程中,并添加新的行为。

(3)切点 Pointcut

  切点有助于缩小切面所通知的连接点的范围。如果说通知定义了切面的“什么”和“何时”的话,那么切点就定义了“何处”,切点会匹配通知所要织入的一个或多个连接点,一般常用正则表达式定义所匹配的类和方法名称来指定这些切点。

(4)切面 Aspect

  切面是通知和切点的结合。通知和切点定义了切面的全部内容——它是什么,在何时何处完成其功能。

(5)引入 Introduction

  引入允许我们向现有的类添加新方法或属性,从而无需修改这些现有类的情况下,让他们具有新的行为和状态。

(6)织入 Weaving

  在过去我常常把织入与引入的概念混淆,我是这样来辨别的,“引入”我把它看做是一个定义,也就是一个名词,而“织入”我把它看做是一个动作,一个动词,也就是切面在指定的连接点被织入到目标对象中。

四、注解方式实现AOP

  1、C包下在resources文件夹中创建application2.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:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:jee="http://www.springframework.org/schema/jee"

       xsi:schemaLocation="
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd
       ">
<context:component-scan base-package="com.zxc.C">
    <context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/>
</context:component-scan>
    <aop:aspectj-autoproxy/>
</beans>
<context:component-scan base-package="com.zxc.C">用来自动扫描com.zxc.C包中带有@component注解的bean类,然后将其加载到内存中。
<context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/>  这是aspect切面包的位置。
<aop:aspectj-autoproxy/>用来启用Spring对@Aspect切面配置的支持。

  2、在java类下创建Chinese类,如下:

  这个就是测试用的业务代码,@Componet代表这是个javabean,有xml配置后,自动扫描装载。

package com.zxc.C;
import org.springframework.stereotype.Component;
@Component
public class Chinese{
    public String say(String name){
        //int a=1/0;用来测试异常增强的
        System.out.println("主方法");
        System.out.println(name);
        return "返回值";
    }
}

  3、在java类下创建Test类,用来测试代码:

package com.zxc.C;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
    public static void main(String[] args) {
        ApplicationContext ctx=new ClassPathXmlApplicationContext("application2.xml");
        Chinese chinese=(Chinese)ctx.getBean("chinese");
        chinese.say("环绕增强测试");
    }
}

Application用来生成IoC容器,装载application2.xml配置文件,之后通过getBean方法来反射创建一个chinese的对象,在调用其核心业务方法say,say的内容是随意写的。

  4、在java类下创建切面类MyAspect类

  

package com.zxc.C;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
@Aspect
public class MyAspect {
    @Before("execution(* com.zxc.C.*.say*(..))")
    public void ok(){
        System.out.println("前置增强");
    }

    @After("execution(* com.zxc.C.*.say*(..))")
    public void ok1(){
        System.out.println("后置增强");
    }

    @AfterReturning(pointcut = "execution(* com.zxc.C.*.say*(..))",returning ="myreturn" )
    public void ok2(Object myreturn){
        System.out.println(myreturn+"返回增强");
    }

//    @AfterThrowing(pointcut ="execution(* com.zxc.C.*.say*(..))",throwing = "myerror")
//    public void ok3(Throwable myerror){
//        System.out.println(myerror+"返回增强");
//    }

    @Around("execution(* com.zxc.C.*.say*(..))")
    public void ok4(ProceedingJoinPoint pjp){
        try {
            System.out.println("环绕点前");
            Object[] objects=pjp.getArgs();
            objects[0]=objects[0]+"环绕增强方法";
            System.out.println(pjp.proceed(objects));
            System.out.println("环绕点后");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

}  

  a、增强类型有:前置增强Before、后置增强After、环绕增强Around、异常后增强AfterThrowing、返回增强AfterReturning:用在关注点方法前

    优先级:(可以加上@order(num)来标注优先级,数越小优先级越高,1最小)环绕前增强>前置增强>异常增强>返回增强>环绕后增强>后置增强

  b、其中环绕增强需要在方法形参上加上形参:ProceedingJoinPoint pjp表示可在切面分钟执行的连接点,在关注点方法中,加入pjp.proceed()方法,可以运行业务方法。

    而在异常增强中需要加上形参Throwable error,用来将业务代码中的错误传到关注点方法中。

  c、切点的书写规则:(在异常后增强和返回增强中都要加上pointcut)

AspectJ切点指示器

   d、在切面类上要记得加注解@Abstrct,表示这是个切面。

   e、jointpoint中的几个常用方法

原文地址:https://www.cnblogs.com/television/p/8724507.html