AOP简介

AOP:面向切面编程。于oop一样是一种软件的编程思想。
在日常的软件开发中,比如一个方法处理在处理核心的业务逻辑时,可能还要考虑到日志,事物,安全认证等方面,如果我们把这些代码都杂糅到一个方法里面,或者方法调用方法,会显得代码过于臃肿,不利于复用。有人说我们可以利用继承和委托来解决这个问题,但是继承会导致一个脆弱的体系。而aop更能优雅的解决问题。我们将最核心的方法只需要实现自己的功能就行,其余的日志和事物,缓存都可以移到切面上来。这样最核心的业务功能就可以被轻易的复用了。

AOP

连接点 join point|即被拦截的点,可能是字段或方法调用触发了通知,spring只支持方法粒度的连接点,如果要更细粒度请使用aspect

切点 pointcut 可以定义多个连接点,一般用通配符配置多个连接点。

通知 Advice 连接点被拦截后执行的操作,spring有5中通知。

before 前置通知

在目标方法调用前执行通知功能

after 后置通知

在目标方法调用后执行通知功能,

after-returning 返回通知

在目标方法执行后,获得返回结果执行相关操作

after-throwing 异常通知

在目标方法报出异常时执行通知功能

around 环绕通知

包裹被通知的方法,可以自定义实现上述的所有通知的功能

切面 Aspect 由切点和通知组成

引入 introduction允许我们向现有的类添加新的方法和属性,在不改变核心类的基础上

织入 Weaving创建把切面应用到目标对象的代理对象的过程。spring的AOP底层实现依赖于jdk的动态代理和cglib,如果有目标类有接口则应用jdk代理,而至用cglib

具体实现

通过一个例子来使用aop,上课铃响,老师走进房间讲课,班长会叫同学们起立,叫老师好,然后老师开始讲课,讲课的过程相当于核心业务方法,其他的都可以移到切面上来。

核心业务类,其被拦截的方法叫做连接点

@Component
public class Lecture {

    public String teacher(String teacherName) throws Exception{
        System.out.println(teacherName +"老师:正在上课");
        //if(1==1)
        //throw new Exception("");
        return "明天补课";
    }

}

定义通知类

@Component
public class LectureAdvice {

    public void beforeLecture(){
        System.out.println("上课了,同学们起立");
    }

    public void afterLecture(){
        System.out.println("下课,同学们请起立");
    }

    public void throwLecture(){
        System.out.println("老师临时有事,这节课先该自习");
    }

    public void returnLecture(Object result){
        System.out.println("这节课的重点"+result);
    }
    public void lecture(ProceedingJoinPoint jp) throws Throwable{
        System.out.println("上课了,同学们起立");
        jp.proceed();
        System.out.println("下课,同学们请起立");
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<!-- 查找最新的schemaLocation 访问 http://www.springframework.org/schema/ -->
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:amq="http://activemq.apache.org/schema/core"
    xmlns:aop="http://www.springframework.org/schema/aop"
     xmlns:tx="http://www.springframework.org/schema/tx"
    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/mvc   
        http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd   
        http://www.springframework.org/schema/tx   
        http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">  

        <!--aop通知类,或连接点必须是一个bean-->
        <context:component-scan base-package="com.aop"/>

        <aop:config>
            <!--定义切面-->
            <aop:aspect ref="lectureAdvice">
                <!--定义切点-->
                <aop:pointcut expression="execution(* com.aop.Lecture.teacher(..))" id="teacher" />
                <!--通知-->
                <aop:before method="beforeLecture" pointcut-ref="teacher"/>
                <aop:after method="afterLecture" pointcut-ref="teacher"/>
                <aop:after-returning method="returnLecture" pointcut-ref="teacher" returning="result"/>
                <aop:after-throwing method="throwLecture" pointcut-ref="teacher"/>
            </aop:aspect>
        </aop:config>
</beans>
aop支持Aspect切点表达式

args()

为连接点指定匹配参数

@args

注解驱动功能同上

within()

限制连接点匹配类型

@within

同上注解驱动

execution()

匹配连接点方法,支持通配符

execution()

匹配连接点方法,支持通配符

更多详情看官方文档 https://docs.spring.io/spring/docs/2.5.x/reference/aop.html
表达式还支持&& ,|| ,!逻辑表达式 或者and ,or ,not

expression="execution(* com.aop.*.teacher(..)) and args(name)"`

基于注解驱动

//启用Aspect创建代理类
@Aspect
@Component
public class LectureAdvice {

    @Pointcut("execution(* com.aop.Lecture.teacher(java.lang.String)) && "+"args(teacherName))" )
    public void teacher(String teacherName){};

    @Before("teacher(teacherName)")
    public void beforeLecture(String teacherName){
        System.out.println("上课了,同学们起立");
    }

    @After("teacher(teacherName)")
    public void afterLecture(String teacherName){
        System.out.println("下课,同学们请起立");
    }

    @AfterThrowing("teacher(teacherName)")
    public void throwLecture(String teacherName){
        System.out.println("老师临时有事,这节课先该自习");
    }

    @AfterReturning(pointcut="teacher(teacherName)",returning="result")
    public void returnLecture(String teacherName,Object result){
        System.out.println("这节课的重点"+result);
    }

    public void lecture(ProceedingJoinPoint jp) throws Throwable{
        System.out.println("上课了,同学们起立");
        jp.proceed();
        System.out.println("下课,同学们请起立");
    }
}

xml配置

<context:component-scan base-package="com.aop"/>

        <!--启动自动代理功能  -->
        <aop:aspectj-autoproxy />