技术干货Java知识点大全程序员

Spring AOP就是这么简单啦

2018-05-24  本文已影响268人  Java3y

前言

只有光头才能变强

上一篇已经讲解了Spring IOC知识点一网打尽!,这篇主要是讲解Spring的AOP模块~

之前我已经写过一篇关于AOP的文章了,那篇把比较重要的知识点都讲解过了一篇啦:Spring【AOP模块】就这么简单,很荣幸被开源中国推荐过~~

这篇文章主要是补充和强化一些比较重要的知识点,并会把上面的两本书关于AOP的知识点整理出来并画成一个思维导图来全面了解Spring AOP的知识点!

那么接下来就开始吧,如果有错的地方希望能多多包涵,并不吝在评论区指正!

一、Spring AOP全面认知

结合《Spring 实战 (第4版)》和《精通Spring4.x 企业应用开发实战》两本书的AOP章节将其知识点整理起来~

1.1AOP概述

AOP称为面向切面编程,那我们怎么理解面向切面编程??

我们可以先看看下面这段代码:

image

我们学Java面向对象的时候,如果代码重复了怎么办啊??可以分成下面几个步骤:

抽取成类的方式我们称之为:纵向抽取

但是,我们现在的办法不行:即使抽取成类还是会出现重复的代码,因为这些逻辑(开始、结束、提交事务)依附在我们业务类的方法逻辑中

image

现在纵向抽取的方式不行了,AOP的理念:就是将分散在各个业务逻辑代码中相同的代码通过横向切割的方式抽取到一个独立的模块中!

image

上面的图也很清晰了,将重复性的逻辑代码横切出来其实很容易(我们简单可认为就是封装成一个类就好了),但我们要将这些被我们横切出来的逻辑代码融合到业务逻辑中,来完成和之前(没抽取前)一样的功能!这就是AOP首要解决的问题了!

1.2Spring AOP原理

被我们横切出来的逻辑代码融合到业务逻辑中,来完成和之前(没抽取前)一样的功能

没有学Spring AOP之前,我们就可以使用代理来完成。

其实Spring AOP的底层原理就是动态代理

来源《精通Spring4.x 企业应用开发实战》一段话:

Spring AOP使用纯Java实现,它不需要专门的编译过程,也不需要特殊的类装载器,它在运行期通过代理方式向目标类织入增强代码。在Spring中可以无缝地将Spring AOP、IoC和AspectJ整合在一起。

来源《Spring 实战 (第4版)》一句话:

Spring AOP构建在动态代理基础之上,因此,Spring对AOP的支持局限于方法拦截

在Java中动态代理有两种方式:

image

JDK动态代理是需要实现某个接口了,而我们类未必全部会有接口,于是CGLib代理就有了~~

那么JDK代理和CGLib代理我们该用哪个呢??在《精通Spring4.x 企业应用开发实战》给出了建议:

原因:

看到这里我们就应该知道什么是Spring AOP(面向切面编程)了:将相同逻辑的重复代码横向抽取出来,使用动态代理技术将这些重复代码织入到目标对象方法中,实现和原来一样的功能

1.3AOP的实现者

AOP除了有Spring AOP实现外,还有著名的AOP实现者:AspectJ,也有可能大家没听说过的实现者:JBoss AOP~~

我们下面来说说AspectJ扩展一下知识面:

AspectJ是语言级别的AOP实现,扩展了Java语言,定义了AOP语法,能够在编译期提供横切代码的织入,所以它有专门的编译器用来生成遵守Java字节码规范的Class文件。

而Spring借鉴了AspectJ很多非常有用的做法,融合了AspectJ实现AOP的功能。但Spring AOP本质上底层还是动态代理,所以Spring AOP是不需要有专门的编辑器的~

1.4AOP的术语

嗯,AOP搞了好几个术语出来~~两本书都有讲解这些术语,我会尽量让大家看得明白的:

连接点(Join point):

切点(Poincut):

增强/通知(Advice):

织入(Weaving):

引入/引介(Introduction):

切面(Aspect):

在《Spring 实战 (第4版)》给出的总结是这样子的:

通知/增强包含了需要用于多个应用对象的横切行为;连接点是程序执行过程中能够应用通知的所有点;切点定义了通知/增强被应用的具体位置。其中关键的是切点定义了哪些连接点会得到通知/增强。

总的来说:

1.5Spring对AOP的支持

Spring提供了3种类型的AOP支持:

二、基于代理的经典SpringAOP

这部分配置比较麻烦,用起来也很麻烦,这里我就主要整理一下书上的内容,大家看看了解一下吧,我们实际上使用Spring AOP基本不用这种方式了!

首先,我们来看一下增强接口的继承关系图:

image

可以分成五类增强的方式:

image

Spring提供了六种的切点类型

image

切面类型主要分成了三种

image

一般切面,切点切面,引介/引入切面介绍:

image image

对于切点切面我们一般都是直接用就好了,我们来看看引介/引入切面是怎么一回事:

继承关系图:

image

引介/引入切面有两个实现类:

实际上,我们使用AOP往往是Spring内部使用BeanPostProcessor帮我们创建代理

这些代理的创建器可以分成三类:

对应的类继承图:

image

嗯,基于代理的经典SpringAOP就讲到这里吧,其实我是不太愿意去写这个的,因为已经几乎不用了,在《Spring 实战 第4版》也没有这部分的知识点了。

三、拥抱基于注解和命名空的AOP编程

Spring在新版本中对AOP功能进行了增强,体现在这么几个方面:

那我们使用@AspectJ来玩AOP的话,学什么??其实也就是上面的内容,学如何设置切点、创建切面、增强的内容是什么...

image

具体的切点表达式使用还是前往:Spring【AOP模块】就这么简单看吧~~

对应的增强注解:

image image

3.1使用引介/引入功能实现为Bean引入新方法

其实前置啊、后置啊这些很容易就理解了,整篇文章看下来就只有这个引介/引入切面有点搞头。于是我们就来玩玩吧~

我们来看一下具体的用法吧,现在我有个服务员的接口:


public interface Waiter {

    // 向客人打招呼
    void greetTo(String clientName);

    // 服务
    void serveTo(String clientName);
}

一位年轻服务员实现类:


public class NaiveWaiter implements Waiter {
    public void greetTo(String clientName) {
        System.out.println("NaiveWaiter:greet to " + clientName + "...");
    }

    @NeedTest
    public void serveTo(String clientName) {
        System.out.println("NaiveWaiter:serving " + clientName + "...");
    }

}

现在我想做的就是:想这个服务员可以充当售货员的角色,可以卖东西!当然了,我肯定不会加一个卖东西的方法到Waiter接口上啦,因为这个是暂时的~

所以,我搞了一个售货员接口:


public interface Seller {

  // 卖东西
  int sell(String goods, String clientName);
}

一个售货员实现类:


public class SmartSeller implements Seller {

    // 卖东西
    public int sell(String goods,String clientName) {
        System.out.println("SmartSeller: sell "+goods +" to "+clientName+"...");
        return 100;
    }

}

此时,我们的类图是这样子的:

image

现在我想干的就是:借助AOP的引入/引介切面,来让我们的服务员也可以卖东西

我们的引入/引介切面具体是这样干的:


@Aspect
public class EnableSellerAspect {

    @DeclareParents(value = "com.smart.NaiveWaiter",  // 指定服务员具体的实现
            defaultImpl = SmartSeller.class) // 售货员具体的实现
    public Seller seller; // 要实现的目标接口

}

写了这个切面类会发生什么??

是不是很神奇??我也觉得很神奇啊,我们来测试一下:

我们的bean.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:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
    <aop:aspectj-autoproxy/>
    <bean id="waiter" class="com.smart.NaiveWaiter"/>
    <bean class="com.smart.aspectj.basic.EnableSellerAspect"/>
</beans>

测试一下:


public class Test {
    public static void main(String[] args) {

        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("com/smart/aspectj/basic/beans.xml");
        Waiter waiter = (Waiter) ctx.getBean("waiter");

        // 调用服务员原有的方法
        waiter.greetTo("Java3y");
        waiter.serveTo("Java3y");

        // 通过引介/引入切面已经将waiter服务员实现了Seller接口,所以可以强制转换
        Seller seller = (Seller) waiter;
        seller.sell("水军", "Java3y");

    }
}

image

具体的调用过程是这样子的:

当引入接口方法被调用时,代理对象会把此调用委托给实现了新接口的某个其他对象。实际上,一个Bean的实现被拆分到多个类中

image

3.2在XML中声明切面

我们知道注解很方便,但是,要想使用注解的方式使用Spring AOP就必须要有源码(因为我们要在切面类上添加注解)。如果没有源码的话,我们就得使用XML来声明切面了~

其实就跟注解差不多的功能:

image

我们就直接来个例子终结掉它吧:

首先我们来测试一下与传统的SpringAOP结合的advisor是怎么用的:

实现类:

image

xml配置文件:

image

.......

一个一个来讲解还是太花时间了,我就一次性用图的方式来讲啦:

image

最后还有一个切面类型总结图,看完就几乎懂啦:

image

三、总结

看起来AOP有很多很多的知识点,其实我们只要记住AOP的核心概念就行啦。

下面是我的简要总结AOP:

最后,将我们上一次IOC的思维导图补充AOP的知识点上去吧~~~

image

参考资料:

如果文章有错的地方欢迎指正,大家互相交流。习惯在微信看技术文章,想要获取更多的Java资源的同学,可以关注微信公众号:Java3y。为了大家方便,刚新建了一下qq群:742919422,大家也可以去交流交流。谢谢支持了!希望能多介绍给其他有需要的朋友

文章的目录导航

上一篇下一篇

猜你喜欢

热点阅读