从IOC控制反转到AOP切面编程,Spring 核心机制梳理
目录一. IOC的设计初衷二. IOC的核心设计理念三. AOP概述四. AOP相关术语4.1 横切关注点4.2 通知(增强)4.3 切面4.4 目标4.5 代理4.6 连接点4.7 切入点五. Spring 基于注解的AOP5.1 JDK动态代理5.2 cglib 动态代理5.3 AspectJ 代理一. IOC的设计初衷在没有IOC之前项目中调用某个方法通常都是先 new 一个方法的类对象然后通过该对象调用该方法但这种 new 对象的方式存在一个很大的缺点——项目代码之间耦合度太高了如果后期需求变动需要对项目功能做修改由于项目内部使用的 new 的方式导致耦合度较高后期代码很有可能会对之前的代码产生侵入就违背了 Java 面向对象中对扩展开放对修改封闭的原则。为了降低项目内部 new 对象导致模块之间耦合度较高的问题后来就提出了 IOC 容器这一解决方案二. IOC的核心设计理念IOC是 Inversion of Control 的简写翻译过来就是控制反转。IOC(控制反转)就是依赖倒置的一种设计思想IOC正是通过DI(依赖注入)实现了控制反转是一个面向对象的重要变成法则设计模式采用的是工厂模式。在 Spring 项目中程序猿可以将对象的实例化初始化对象之间的依赖关系对象的控制交由 IOC 容器来做IOC容器会完成 创建对象管理对象注入对象控制对象等一系列操作。创建出来的一个个对象其实本质上和我们自己 new 出来的对象没有本质区别但是 Spring 为了做区分将这些对象换了个名字称之为 Bean 。当在程序中想要调用某个类的方法的时候就不需要像以前一样自己去 new 对象而是将这个类的对象创建到管理交给 IOC容器在需要的时候直接从IOC容器中的对象取出来用就可以了这个过程中对象的创建和控制从程序员转化成IOC容器实现了控制反转。降低了项目代码内部的耦合度实现了高内聚低耦合的目的。同时Spring 容器将所有的对象都集中在一种非常方便配置和管理同时还提高了程序的性能减轻了JVM的压力。三. AOP概述AOP全称Aspect Oriented Programming 翻译过来为面向切面编程是对OOP(面向对象编程)的一种补充和完善。它是通过预编译方式和运行期动态代理的方式实现在不修改源代码的情况下添加新的功能给程序动态统一添加额外功能的一种技术。利用AOP可以对业务逻辑的各个部分进行隔离从而使得业务逻辑各部分之间耦合度降低提高程序的可重用性同时提高开发效率。举个例子假设现在要对以前的一个项目添加一些功能该如何做能修改源代码吗能但不建议而且存在风险并且违背了 Java 对扩展开放对修改封闭这一原则。再比如说我要在用户做一些事情之前先做用户校验确保安全该怎么办重构项目代码代价太大这个时候就需要用到AOP它可以做到不修改源代码的同时添加新的功能就好比是在程序内部方法与方法之间切开一个口子将要添加的方法放到切开的口子里。假设转账业务中A方法执行完毕执行B方法现在使用AOP将A和B切开将C方法加到AB中间那么程序在执行完A方法之后就会先去执行切入进去的C方法再执行B方法。四. AOP相关术语4.1 横切关注点来看下面addsubmuldiv 都是一个个方法在程序中自上而下独立执行程序执行的时候会调用很多的业务方法。以下面四个方法为例后期我现在希望在四个方法中都加入某个新的功能。比如执行完数据库操作之后添加一个日志方法记录一下记录插入操作我们要解决的问题就是添加一个新的通用日志功能又比如我要在所有业务之前都执行用户验证添加一个用户校验的方法我们要解决的问题是用户校验要添加用户校验这一业务功能但并没有去做这件事只是强调这件事的目的这就叫 横切关注点 业务中有多少个希望附加的功能就有多少个横切关注点。4.2 通知(增强)每个横切关注点上要做的事情就是添加一个方法去完成我们要达到的目的添加的这个方法就叫通知方法也叫增强方法所以用一句总结横切关注点是要添加的业务功能通知是实现业务功能的方法。方法中分为以下几种通知。前置通知 Before在被代理的目标方法前执行返回通知 AfterReturning在被代理的目标方法成功结束后执行异常通知 AfterThrowing在被代理的目标方法异常结束后执行后置通知 After在被代理的目标方法最终结束后执行环绕通知 Around使用 try...catch...finally 结构围绕整个被代理的目标方法包括上面四种通知对应的所有位置4.3 切面封装上述通知方法的类也可以叫做切面类。4.4 目标被代理的目标对象。4.5 代理向目标对象应用通知之后产生的代理对象。4.6 连接点我们原本的业务方法是自上而下执行的业务中可能会一步步调用不同的方法而我们的增强方法就是要添加到原本业务各个方法中的某一个位置放置增强方法的位置叫连接点。也可以说就是 Spring 允许你使用通知的地方就叫连接点。4.7 切入点连接点位置要放置的方法就是切入点这一点非常容易和通知搞混通知方法是实现我们业务功能的整体方法这个整体方法中又分为我们刚才说的众多通知每一个通知也可以是一个小的方法这些小的方法就是切入点。五. Spring 基于注解的AOPSpring 中实现 AOP 有两种方式一种是基于注解的 AOP另一种就是基于 xml 配置文件的AOP实际使用中基于直接的 AOP 要比 xml 的更加简单所以这里重点来说说基于注解的 AOP 实现。此外SpringAOP 有动态代理和静态代理两种动态代理又分为JDK动态代理和cglib 动态代理静态代理是 AspectJ(但最终效果是动态的)。5.1 JDK动态代理JDK 动态代理主要应用于目标方法有接口的动态代理是 JDK 原生的实现方式它底层实际上是生成了接口实现类的代理对象cglib 动态代理也可以适用于有接口的目标方法。5.2 cglib 动态代理cglib 动态代理则适用于目标方法没有接口的动态代理它底层是通过继承目标类创建目标类对象实现动态代理5.3 AspectJ 代理AspectJ 是AOP思想的一种实现它本身其实也是一个框架不算是 Spring 的一部分weaver 是织入器它将代理逻辑织入被代理的目标类编译得到的字节码文件对象所以最终效果是动态的。而 Spring 框架则是借用了里面的一些注解实现了AOP的功能。Spring 中有很多关于AOP的常用注解Before(value execution(方法路径(方法参数)))标注该方法为前置通知方法AfterReturning(value execution(方法路径(方法参数)))标注该方法为返回通知方法AfterThrowing(value execution(方法路径(方法参数)))标注该方法为异常通知方法After(value execution(方法路径(方法参数)))标注该方法为后置通知方法Around(value execution(方法路径(方法参数)))标注该方法为环绕方法Aspect标注该类是一个切面类Pointcut(execution(方法路径(方法参数)))标注一个切入点类似于MyBatis框架中的SQL片段可以重复利用不需要再众多方法上都写一边目标方法的路径