Spring 中 AOP IOC 的最简单易懂整理归纳

165 阅读6分钟

学习java的路上,Spring是一个必不可缺的框架,他的本意是为了解决企业应用程序开发复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许您选择使用哪一个组件,同时贯穿表现层(controller),业务层(service),持久层(dao),且能和其他框架无缝整合

Spring共有五大特点 1. 轻量且非侵入式 2.控制反转IOC 3.面向切面AOP 4.容器 5.框架集合

轻量

在Spring项目完成且想要进行发布时,可以使用jar文件进行一键打包,并在命令行使用 java -jar myjar.jar 进行运行。jar包的大小可以小至1M,所以我么称spring是一个轻量级的框架。
同时,Spring框架在系统初始化的时候不用加载所有的服务,有些bean在其他bean需要他时才加载,这也是他被称为轻量级开发的原因之一。

非侵入式

  • 侵入式: 即代码里嵌入了别的代码,可能是引入框架或继承接口,当我们更改时可能需要同时更改很多地方。
  • 非侵入式:引入了框架,对现有的类结构没有影响,不需要实现框架某些接口或者特定的类。比如Spring框架,通过配置完成依赖注入就可以使用,当我们想换个框架,只需要修改相应的配置,程序仍然可以运行。

侵入式代码

public class Ham extends Food{
    private static final long id = 1L;
    private Date produceDate = new Date();
    
    public String list() throws Exception {
        return SUCCESS;
    }
}

非侵入式代码

public class Ham{
    private static final long id = 1L;
    private Date produceDate = new Date();
    
    public String list() throws Exception {
        return SUCCESS;
    }
}

控制反转 IOC

IOC是Spring拥有低耦合这一特性的重要原因.

什么是IOC?

IOC即一个对象依赖的其他对象会通过被动的方式传进来,即利用反射机制,而不是这个对象自己创建或者查找依赖对象,即new 一个新对象。

IOC代码示例

public static void main(String[] args){

        // 1. 获取核心容器对象
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        // 2. 根据id获取bean对象
        IAccountService as = (IAccountService) ac.getBean("accountService");
        IAccountDao adao = ac.getBean("accountDao",IAccountDao.class);

    }

Spring注入依赖的4种方式

  • 构造器注入
  • setter注入
  • 静态工厂注入 (DaoFactory, 这里获取对象实例的方法是静态的,所以我们只能通过spring注入获得)
  • 实例工厂注入 (这里获取实例的方法是非静态的,所以我们可以调用实例方法)

面向切面 AOP

Spring的最终目的是简化开发。通俗的讲减少重复代码。就是每个模块的代码都只干与他业务相关的事,别的模块如果需要其他业务时只用调用相对应的模块就好,而不是在自己的模块里再重复编写代码,降低模块间的耦合度。
例如如果没有使用aop,业务员A做香辣鸡腿堡时,需要先炸鸡,再进行汉堡的其他流程比如挤沙拉酱,配上西红柿片,而业务员B做川香鸡腿堡时,也需要先炸鸡 ,再挤上川香酱等,这样A,B都需要学会炸鸡。而使用aop即我们专门那排一个人员进行炸鸡这项活动,A,B再制作汉堡时,只用向炸鸡专员索取炸鸡,并进行组装即可。AOP也可以提高可操作性和可维护性,比如如果炸鸡炸的有问题,我们就只用去询问炸鸡专员,并安排他进行进修,而不是让AB都去进修花双份的钱了。

先给出一个比较专业的概念定义:

  • Joint point(连接点):表示在程序中明确定义的点,典型的包括方法调用,对类成员的访问以及异常处理程序块的执行等等,它自身还可以嵌套其它 joint point。
  • Pointcut(切点):表示一组 joint point,这些 joint point 或是通过逻辑关系组合起来,或是通过通配、正则表达式等方式集中起来,它定义了相应的 Advice 将要发生的地方。
  • Advice(增强):Advice 定义了在 Pointcut 里面定义的程序点具体要做的操作,它通过 before、after 和 around 来区别是在每个 joint point 之前、之后还是代替执行的代码。
  • Aspect(切面): Aspect 声明类似于 Java 中的类声明,在 Aspect 中会包含着一些 Pointcut 以及相应的 Advice。
  • Target(目标对象):织入 Advice 的目标对象。
  • Weaving(织入):将 Aspect 和其他对象连接起来, 并创建 Adviced object 的过程

让我们继续沿用上面的肯德基例子,在肯德基里,我们的后厨会做出非常多种的炸鸡,有的是用鸡胸,有的是用鸡腿,有的是加了辣椒,有的是有骨,而我们现在需要制作一个香辣鸡腿堡,那我们就根据香辣鸡腿堡里的炸鸡要求来找出哪块炸鸡(由鸡腿为原料,无骨且由辣味的)可以组装成一份合格的香辣鸡腿堡。

来让我们看一下上面的一个小故事和 AOP 到底有什么对应关系. 首先我们知道, 在 Spring AOP 中 Joint point 指代的是所有方法的执行点, 而 point cut 是一个描述信息, 它修饰的是 Joint point, 通过 point cut, 我们就可以确定哪些 Joint point 可以被织入 Advice. 对应到我们在上面举的例子, 我们可以做一个简单的类比, Joint point 就相当于 所有的炸鸡,pointcut 就相当于 符合香辣鸡腿堡里的炸鸡要求:由鸡腿为原料,无骨且由辣味的, 而 Advice 则是施加在符合香辣鸡腿堡里炸鸡要求的动作: 放入没有炸鸡的香辣鸡腿堡. 为什么可以这样类比呢?

  • Joint point : 肯德基里后厨做出来的所有炸鸡: 因为根据定义, Joint point 是所有可能被织入 Advice 的候选的点, 在 Spring AOP中, 则可以认为所有方法执行点都是 Joint point. 而在我们上面的例子中, 按理说所有的炸鸡都有可能被放入香辣鸡腿堡里.

  • Pointcut :由鸡腿为原料,无骨且由辣味的: 我们知道, 所有的方法(joint point) 都可以织入 Advice, 但是我们并不希望在所有方法上都织入 Advice, 而 Pointcut 的作用就是提供一组规则来匹配 joinpoint, 给满足规则的 joinpoint 添加 Advice. 同理, 对于我们组装香辣鸡腿堡来说, 已经是鸡腿堡了,我们肯定不能把炸鸡翅给夹进去,而是根据由鸡腿为原料,无骨且由辣味的炸鸡夹进去。 在这里它限定了可以被加进香辣鸡腿堡的炸鸡的范围,满足此修饰规则的炸鸡都可以放进香辣鸡腿堡.

  • Advice :=放进香辣鸡腿堡, Advice 是一个动作, 即一段 Java 代码, 这段 Java 代码是作用于 point cut 所限定的那些 Joint point 上的. 同理, 对比到我们的例子中, 放进香辣鸡腿堡 这个动作就是对作用于那些满足 由鸡腿为原料,无骨且由辣味的炸鸡

  • Aspect::Aspect 是 point cut 与 Advice 的组合, 因此在这里我们就可以类比: "凡是由鸡腿为原料,无骨且由辣味的炸鸡,放进香辣鸡腿堡" 这一整个动作可以被认为是一个 Aspect.