善倾的知识体系构建之路Java 杂谈程序员

Spring的AOP

2018-09-21  本文已影响0人  善倾

面向切面编程是对于面向对象的一种补充,是一种很先进的思想,技术实现倒不是很高深,关于 Spring 的 AOP 需要掌握的有以下这些。

AOP 并不是 Spring 框架独有的,Spring 只是支持 AOP 编程的框架之一而已。不同的框架对 AOP 的支持各有特点,有些框架支持对方法及其参数做拦截,有些则只能对方法进行拦截。Spring 就是后者,它只支持对方法进行拦截的 AOP 。

_Spring的AOP.png

AOP概述

AOP 全称是 Aspect Oriented Programming ,中文含义面向切面编程。

AOP 的概念

网上官方说法:

Spring 的 AOP 指的就是在程序运行时,动态的将代码切入到指定位置上的一种编程思想。

自己的理解:

Spring 会通过配置文件是否进行了 AOP 相关的配置,来动态决定到底应该采用目标对象还是代理对象。代理对象是对原有目标对象的方法进行了增强,所以一旦采用了代理对象,就会出现和原有不一样的效果。

为什么要使用AOP

比如在 Spring 中,只要编写一个切面类,然后进行相关配置,Spring 就会去创建代理对象。如此就实现了在不修改原有代码的情况下,达到了和修改原有代码相同的效果。Spring 中的 AOP 通常都是用来进行权限校验、日志记录、性能监控、事务控制等功能的。

AOP 的底层实现原理

底层实现无非就是,在通过依赖注入给 Bean 对象的属性进行赋值的时候,根据配置来决定是注入原有目标对象还是代理对象。Spring 中生成代理对象使用的技术有两种,分别是 JDK 动态代理,和 CGLib 动态代理。

JDK 动态代理

要求目标类必须实现接口,才能采用这种方式产生代理对象。

CGLib 动态代理

针对没有实现接口的类产生代理,它是通过继承的方式实现的代理。

AOP的相关术语

下面以CustomerDao类为例,来讲解 AOP 相关术语。

//目标类
public class CustomerDao {
    public void save() {
        System.out.println("保存客户...");
    }
    public void find() {
        System.out.println("查询客户...");
    }
    public void update() {
        System.out.println("修改客户...");
    }
    public void delete() {织入
        System.out.println("删除客户...");
    }
}
//切面类,下面是两个方法就是通知
public class MyAspectXML {
    public void checkPri(JoinPoint jointPoint) {
        System.out.println("权限校验 "+jointPoint);
    }
    public void writeLog(Object result) {
        System.out.println("日志记录 "+result);
    }
}

前面已经提到,Spring 支持的是基于方法的 AOP ,也就是说它只能对方法进行增强。


_AOP相关术语.png

相关术语:

通知的类型

通知就是切面类中的一个个方法,通知的类型指的是它和切入点的组成关系。


_通知的类型.png

切入点表达式的写法

如何通过配置指定哪些类的哪些方法需要进行增强呢?就是通过切入点表达式来实现的。

切入点表达式的格式是:方法返回值+包名.类名.方法名(方法的参数),其中除了参数之外,其他任何一个位置都可以用通配符*表示。方法的参数用..表示。

实际使用范例如下:

<aop:pointcut expression="execution(* packageName.ProductDaoImpl.save(..))" id="pointcut1"/>

XML 配置AOP

配置 AOP 首先要明确几个角色,分别是切面类,目标类,切入点、通知。以上面的目标类和切面类为例,他们的配置如下

<aop:config>
    <!-- 配置切入点 -->
    <aop:pointcut expression="execution(* com.itheima.spring.demo3.ProductDaoImpl.save(..))" id="pointcut1"/>
    <aop:pointcut expression="execution(* com.itheima.spring.demo3.ProductDaoImpl.delete(..))" id="pointcut2"/>
    <aop:pointcut expression="execution(* com.itheima.spring.demo3.ProductDaoImpl.update(..))" id="pointcut3"/>
    <aop:pointcut expression="execution(* com.itheima.spring.demo3.ProductDaoImpl.find(..))" id="pointcut4"/>
    <!-- 配置切面类,此标签内可以配置多个切面 -->
    <aop:aspect ref="myAspect">
        <!-- 前置通知  -->
        <aop:before method="checkPri" pointcut-ref="pointcut1"/>
        <!-- 后置通知 -->
        <aop:after-returning method="writeLog" pointcut-ref="pointcut2" returning="result"/>
        <!-- 环绕通知 -->
        <aop:around method="around" pointcut-ref="pointcut3"/>
        <!-- 异常抛出通知 -->
        <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut4" throwing="ex"/>
        <!-- 最终通知 -->
        <aop:after method="after" pointcut-ref="pointcut4"/>
    </aop:aspect>
</aop:config>

AspectJ注解配置AOP

用 AspectJ 注解的方式配置 AOP ,其实主要是需要配置切面类和通知,还有切入点。

切面类的配置:

@Aspect//表明是切面类
public class MyAspectAnno {}

通知的配置:

@Before(value="execution(* com.itheima.spring.demo1.OrderDao.save(..))")
public void before() {
    System.out.println("save方法前置增强=====");
}//其他通知同理

切入点的配置:

@Pointcut(value="execution(* packageName.ProductDaoImpl.save(..))")
public void save() {
    System.out.println("保存订单...");
}
上一篇下一篇

猜你喜欢

热点阅读