spring技术的通俗理解
原文入口:https://blog.csdn.net/u012556994/article/details/81149312
一提到spring技术,随之而来的必然就是这样3个名词:控制反转IOC,依赖注入DI、面向切面编程AOP。但是这3个词语何其晦涩,根本无法“顾名思义”,只有理解其本质才有可能准确get到这3个词语的精确含义。
一、控制反转IOC(Inversion of Control)
IOC技术本质上就是对象创建技术,更具体点,就是将类实例化为对象的技术。
但是,在java里面的对象创建技术不是通过new来实现的么?例如,现在有一个Student类,可以利用这个Student类通过new关键字来创建一个“张三”同学的具体对象。这一点对于大家来说是十分熟悉的了。我们也知道,每次new一下就可以创建一个新的对象,但是有些时候这样做反而是一件危险的事。因为我们若想让这个类永远只有一个对象存在,即“单例模式”的话,这样每次new一下
就有了一个新对象的做法就达不到单例模式的要求了。那怎么办呢?还有,在java设计模式里也可以通过工厂模式来产生对象,这又该怎么做呢?
上述2种情况恰恰就是spring里bean的定义:
- spring里bean的scope属性值singleton用来产生单例模式下的对象;
- spring里bean的prototype属性用来产生新对象;
- spring里的bean还可以通过工厂模式来产生对象。
这样看来,spring里的bean就是创建对象的工具。也就是说,IOC是对象创建技术,这种技术是通过bean工具来完成的。
但是啊,项目中创建对象往往是很复杂的,并不是想象中的那般简单。那么到底复杂在哪呢?举个例子:现在有一个“学习”对象,创建这个对象的时候,要用到课本对象、钢笔对象、教师对象……才能完成这个“学习”对象。但是在“课本”对象里,又需要纸张对象、编者对象、出版社对象……,“钢笔”对象又需要金属对象、颜色对象、厂家对象……这样看起来,对象与对象之间是相互关联相
互嵌套着的。如果这些对象及其关系都要用java来实现的话,是一个何其庞大的工程,耗时耗力不说,产生错误的几率也大大增加了。
那有没有一种非常好的方式来消除这些对象之间的依赖关系呢?
答案就是:spring容器。spring的XML文件负责就将对象之间的依赖关系定义好,spring容器负责创建好这些对象。当java程序需要使用某个对象的时候,直接去spring容器里取就好了,根本不用利用new关键字来创建这么麻烦。
重点来了,这个过程的转换说明了什么?说明java对象的创建权利发生转移了呀!原来创建对象的控制权是掌握在java代码new关键字中的,现在这个权利由spring容器来接管了!这不是“控制反转”是啥?
二、依赖注入DI(Dependency Injection)
如果理解了上述“控制反转”的本质,那么要理解“依赖注入”也不是什么难事了。
在“控制反转”中,我们是这么说的:当java程序需要使用某个对象的时候,直接去spring容器里取就好了。这句话是站在java程序的角度说的。那么反过来,站在spring容器的角度来又该怎么说呢?spring容器直接给出java程序需要的对象,那么java程序就可以直接使用这个对象了。那么这个“给出”的动作,就叫做“依赖注入”。即专业的说法是:当java程序需要使用某个对象的时候,spring
容器就把这个对象及其依赖关系注入到java程序里供其使用。
spring里的3种注入方式:接口注入、setter注入、构造器注入。
三、面向切面编程AOP(Aspect Oriented Programming)
在谈spring中的AOP之前,我们先来看一种设计模式:代理模式。顾名思义,在Java程序里,“代理”就是某个具体实例对象的代表。
举个例子,具体实例对象就是“总裁”,这个“代表”就是“总裁特助”。那么像类似于端茶送水、打扫办公室这样的非核心业务自然是“总裁特助”来做,“总裁”可是要去做那些核心业务的。但是,想要与“总裁”打交道的,那么必须通过“总裁特助”才可以。也就是说,代理是某个具体实例对象的入口与出口。
上面这个例子用专业术语描述,其实就是AOP的思想。将程序中那些重复的、非核心的业务提取出来,独立进行管理。最常见的就是与数据持久层关系紧密的事务、日志、安全、权限认证等方面的处理。这些虽然都不是项目中最核心的部分,但是在具体应用场景中却又必不可少。
AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志
功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切(cross-cutting)代码,在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。
而AOP技术则恰恰相反,它利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。AOP代表的是一个横向的关系,
如果说“对象”是一个空心的圆柱体,其中封装的是对象的属性和行为;那么面向方面编程的方法,就仿佛一把利刃,将这些空心圆柱体剖开,以获得其内部的消息。而剖开的切面,也就是所谓的“方面”了。然后它又以巧夺天功的妙手将这些剖开的切面复原,不留痕迹。
Aop 的作用在于分离系统中的各种关注点,将核心关注点(与主要业务相关的)和横切关注点(与主要业务关系不大的)分离开来。AOP的核心思想就是将应用程序中的商业逻辑同对其提供支持的通用服务进行分离。
实现AOP的技术,主要分为两大类:
一 、是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;
二、 是采用静态织入的方式,引入特定的语法创建“方面(Aspect)”,从而使得编译器可以在编译期间织入有关“方面”的代码。
AOP的使用场景:AOP用来封装横切关注点,具体可以在下面的场景中使用:
Authentication 权限、Caching 缓存、Context passing 内容传递、Error handling 错误处理、Lazy loading懒加载、Debugging调试、logging, tracing, profiling and monitoring日志(记录、跟踪、优化、校准)、Performance optimization性能优化、Persistence持久化、Resource pooling资源池、Synchronization同步、Transactions 事务。