Spring AOP

面向切面编程

  面向切面编程(AOP)就和字面上的意思一样,Spring为我们提供的一把横向的刀,可以把所有bean需要的公共方法以切面的形式注入到指定的bean。这样做使得代码更加简洁,只需要写个切面方法然后通过xml或者注解进行配置即可,大大增加了代码的灵活性和可读性。

  1 AOP中的术语

    ⑴通知(advice):切面的工作称为通知,通知定义了切面是什么以及何时使用。

      Spring中的5中通知:

        Before:在方法被调用前调用通知;

        After:在方法调用之后调用通知,无论方法是否执行成功;

        After-returning:在方法成功执行之后调用通知;

        After-throwing:在方法抛出异常后调用通知;

        Around:通知包裹了被通知的方法,在被通知方法调用之前和调用之后执行之定义的行为;

    ⑵连接点(Joinpoint):是在应用执行过程中能够插入切面的一个点。

    ⑶切点(Poincut):切点的定义会匹配通知所要织入的一个或多个连接点。

    ⑷切面(Aspect):切面是通知和切点的结合。

    ⑸引入(Introduction):引入允许我们向现有的类添加新方法或属性。

    ⑹织入(Weaving):织入是将切面应用到目标对象来创建新的代理对象的过程。

  2 Spring中AOP的支持

    Spring中AOP代理由Spring的IOC容器负责生成、管理,其依赖关系也由IOC容器负责管理因此,AOP代理可以直接使用容器中的其它bean实例作为目标,这种关系可由IOC容器的依赖注入提供。Spring创建代理的规则为:

    1、默认使用Java动态代理来创建AOP代理,这样就可以为任何接口实例创建代理了

    2、当需要代理的类不是代理接口的时候,Spring会切换为使用CGLIB代理也可强制使用CGLIB

   AOP编程其实是很简单的事情,纵观AOP编程,程序员只需要参与三个部分:

    1、定义普通业务组件

    2、定义切入点,一个切入点可能横切多个业务组件

    3、定义增强处理,增强处理就是在AOP框架为普通业务组件织入的处理动作

    所以进行AOP编程的关键就是定义切入点和定义增强处理,一旦定义了合适的切入点和增强处理,AOP框架将自动生成AOP代理,即:代理对象的方法=增强处理+被代理对象的方法。

    使用aop时 需要在xml中引入aop标签:

<?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:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
            
</beans>

   3 Spring中AOP的使用

    xml中使用的AOP的标签说明:

      切点表达式:

        Spring使用的是AspectJ的切点表达式:

    

      在spring中execution()是我们编写切点定义主要使用的指示器,我们在此基础上使用其他指示器来限制匹配的切点。

      

<aop:config>
        <aop:aspect id="printTime"  ref="printTime">
            <aop:pointcut id="student" expression="execution(* com.my.study.Student.*(..))"/>
            <aop:before method="printTime" pointcut-ref="student"/>
            <aop:after method="printTime" pointcut-ref="student"/>
        </aop:aspect>
    </aop:config>

      Spring 中环绕通知的使用:

      在通知的方法参数中加入ProceedingJoinPoint

        

 public void printFunctionTime(ProceedingJoinPoint joinPoint){
        try {
            Date startTime = new Date();
            joinPoint.proceed();
            Date endTime = new Date();
            System.out.println("时间耗时"+(endTime.getTime()-startTime.getTime()));
        }catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

     在xml中配置:

    

 <aop:config>
        <aop:aspect id="printTime"  ref="printTime">
            <aop:pointcut id="student" expression="execution(* com.my.study.Student.study(..))"/>
            <aop:around method="printFunctionTime" pointcut-ref="student"/>
        </aop:aspect>
    </aop:config>

   4 注解切面

    使用注解切面,看下面代码:

      

package com.my.study;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

import java.util.Date;


@Aspect
public class AopPrintTime {
    /*切点表达式*/
    @Pointcut("execution(* com.my.study.Student.study(..))")
    public void studyAspect(){}

    /*前置切面  使用args标签传入参数*/
    @Before("studyAspect()&&args(studyObject)")
    /*后置切面  使用args标签传入参数*/
    @After("studyAspect()&&args(studyObject)")
    public void printTime(String studyObject){
        System.out.println(studyObject+"time is "+new Date().getTime());
    }

    @Around("studyAspect()&&args(studyObject)")
    public void printFunctionTime(ProceedingJoinPoint joinPoint,String studyObject){
        try {
            Date startTime = new Date();
            joinPoint.proceed();
            Date endTime = new Date();
            System.out.println(studyObject+"学习时间耗时"+(endTime.getTime()-startTime.getTime()));
        }catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }



}

   需要在xml中配置:

    

    <!--设置AOP自动扫描-->
    <aop:aspectj-autoproxy />
    <!--配置切面的bean-->
    <bean id="printTime" class="com.my.study.AopPrintTime"/>

   在pom.xml中配置:

 <!-- https://mvnrepository.com/artifact/aopalliance/aopalliance -->
        <dependency>
            <groupId>aopalliance</groupId>
            <artifactId>aopalliance</artifactId>
            <version>1.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.6.10</version>
        </dependency>

     ps:在学习中遇到了异常spring error at ::0 can't find referenced pointcut

      是aspectjweaver的版本问题 改成1.6.10即可

posted @ 2018-01-24 10:50  小小小怪兽  阅读(159)  评论(0)    收藏  举报