Spring AOP

3 篇文章 0 订阅

欢迎访问:我的个人网站

AOP

AOP:面向切面编程,扩展一个方法的功能,不通过修改源代码的层面实现,它采用横向抽取机制,取消了传统的纵向继承体系,少了很多重复性的代码,为一些列的方法提供一个统一的增强(事务,安全,缓存,性能监测等),在AOP之前,如果要对方法进行增强,有以下两种方式,分别是:直接在方法内部进行实现以及采用纵向抽取机制。这两种方法都各有弊端,第一种方法会修改源代码并且会增加大量的重复性代码,而第二种方式虽然减少了代码的重复,但是如果父类中方法发生了变化,所有进行增强的子类全部需要更改方法名。

DDDDDDDDDDDDDDDD  AOP之前的方法增强示意图 DDDDDDDDDDDDDDDDDDDDDDD

Spring的AOP实现是在上面第二种方式的基础进行的,它采用的横向抽取机制,针对有接口的情况,AOP的底层实现为动态代理。而对没有接口的类,AOP在实现的时候,会先创建被增强类的一个子类作为代理类,在子类中调用父类的方法进行增强。这种代理叫做cjlib动态代理

AOP中的相关名称

  • JoinPoint(连接点): 类中可以被增强的方法。 每个方法可以理解为一个点,Spring可以选择拦截这些点,并在执行到这些点之前或之后对其进行增强。另外在Spring中,只支持方法类型的连接点。
  • PointCut(切入点): 表示Spring实际拦截的点,意味着Spring要对该方法进行增强。
  • Advice(通知/增强): 表示在拦截到方法之后,对这个方法所添加的逻辑,比如拦截方法,为其增加日志功能,那么日志功能就是就是一个增强。增强有几种不同的类型:
    • 前置增强: 在切入点执行之前进行的增强操作。
    • 后置增强: 在切入点执行之后进行的操作。
    • 异常增强: 在切入点执行时发生异常时进行的操作。
    • 环绕增强: 在切入点执行之前执行(如果同时存在前置增强,在前置增强执行之后在执行)在切入点执行之后也执行。
    • 最终增强: 在后置增强执行之后执行。
  • Aspect(切面): 将增强与切入点联合起来的过程就是切面。
  • Introduction(引介): 在运行期动态的为类添加属性或方法。
  • Target(目标对象): 被增强的对象。
  • Proxy(代理): 在正常完成一次切面操作之后,就会产生一个结果代理类,此时这个类中的方法就是增强过的。

Spring进行AOP操作

在使用Spring进行AOP操作之前,需要明白,Spring建议使用一个专门的切面编程框架AspectJ 来进行AOP操作。所以我们需要导入Spring自身的spring-aop.jar, spring-aspects.jar 以及AspectJ相关的包。AspectJ本身并不是Spring的一部分。使用Spring+AspectJ进行AOP操作主要可以使用以下两种形式实现:

  • 基于AspectJ+配置文件实现。
  • 基于AspectJ+注解实现。

配置文件实现AOP操作

针对配置文件而言,因为要进行AOP操作,约束也还是要进行一定的更新,加入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: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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

</bean>

在配置文件中,同样需要使用一种表达式execution来选择切入点进行增强,使用execution函数进行切入点的配置:

execution(访问权限修饰符 被增强方法的全路径);
//对位于com.bestbigkk.domain包下的Person类中的run()方法进行增强,run(..)表示如果内部存在参数也将匹配
execution(* com.bestbigkk.domain.Person.run(..));

//对所有public修饰的方法进行增强
execution(public *.*(..));

//对所有方法增强
execution(* *.*(..));

//对所有以save开头的方法进行增强
execution(* save*(..));

进行AOP操作

(1)配置被增强的类Person以及增强类PersonEnhance

@Component  
@Scope(value = "prototype")  
public class Person {  
    public void run(){  
        System.out.println("running...");  
  }  
    public void eat(){  
        System.out.println("eating...");  
  }  
    public void sleep(){  
        System.out.println("sleeping...");  
  }  
    public void study(){  
        System.out.println("studying....");  
  }  
}

@Component
@Scope(value = "prototype" )
public class PersonEnhance {
    public void beforeEnhance(){
        System.out.println("前置增强!");
    }
    public void afterEnhance(){
        System.out.println("后置增强!");
    }
    public void roundEnhance(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕增强,之前执行!");
        proceedingJoinPoint.proceed();
        System.out.println("环绕增强,之后执行!");
    }
    public void exceptionEnhance(){
        System.out.println("异常增强!");
    }
    public void finalEnhance(){
        System.out.println("最终增强!");
    }
}

(2)在配置文件中配置AOP操作,

  1. 首先配置切入点,使用execution表达式指明对哪个类的那个方法进行增强,并对这个切入点明明,后续会使用。
  2. 配置切面,需要使用属性ref指定增强类,值为注册的Bean的名称
  3. 在切面中使用不同标签指定要进行何种类型的增强,指定增强类中的方法与切入点。
<aop:config>  
 <!--1.配置切入点, id为切入点的名称-->
 <aop:pointcut id="adviceA" expression="execution(* com.bestbigkk.domain.Person.*(..))"> </aop:pointcut>  
 
 <!--2. 配置切面-->
 <aop:aspect ref="personEnhance">
      <!--3. 指定增强类型-->
      <aop:before method="beforeEnhance" pointcut-ref="adviceA"/>
      <aop:around method="roundEnhance" pointcut-ref="adviceA"/>
 </aop:aspect>
</aop:config>

3.调用:

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("config.xml");  
Person person = (Person) context.getBean("person");  
person.run();

//输出, 在执行被增强类的run方法之前,执行了增强类中的beforEnhance方法。
前置增强!
环绕增强,之前执行!
running...
环绕增强,之后执行!

注解实现AOP操作

1.首先创建增强类以及被增强类,并进行配置。
2.在配置文件中开启AOP自动代理:

<aop:aspectj-autoproxy/>

3.使用注解:
在被增强的类上面使用**@Aspect** 注解。 指定这个类是一个增强类,然后再具体的方法上面再次使用注解,确定要使用的增强方式:

  • @Before:前置增强
  • @AfterReturning : 后置增强
  • @Around: 环绕增强
  • @AfterThrowing: 异常增强
  • @After: 最终增强,不管是否异常都会执行

每个注解都需要为一个属性value配置值,值为execution表达式,指定被增强的类。

示例,建立增强类:

@Aspect
@Component
@Scope(value = "prototype" )
public class PersonEnhance {
    @Before(value = "execution(* com.bestbigkk.domain.Person.eat())")
    public void beforeEnhance(){
        System.out.println("前置增强!");
    }

    @Around(value = "execution(* com.bestbigkk.domain.Person.run(..))")
    public void roundEnhance(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕增强,之前执行!");
        proceedingJoinPoint.proceed();
        System.out.println("环绕增强,之后执行!");
    }
}

建立被增强类:

@Component
@Scope(value = "prototype")
public class Person {
    public void run(){
        System.out.println("running...");
    }
    public void eat(){
        System.out.println("eating...");
    }
}

调用:

   public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("config.xml");
        Person person = (Person) context.getBean("person");
        person.run();
        person.eat();
    }

//输出
环绕增强,之前执行!
running...
环绕增强,之后执行!
前置增强!
eating...
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值