IoC容器是Spring最核心的概念和内容,它代替了传统的new方式初始化对象,通过读取在XML文件中配置的Bean定义,自动创建并管理容器的Bean实例即其生命周期,并且可以在Bean的定义中进行依赖对象的配置,并根据依赖配置自动注入相关依赖,从而达到解耦的效果,Spring提供了多种依赖注入方式,包括构造函数注入和设置值注入,在理解这些概念前,首先必须掌握几个容易混淆的术语的意义和区别

组件-框架-容器

组件

  • 组件是实现特定的功能,并且符合某种规范的类的集合,它是一个通用的概念并不局限于某种语言,例如C#的COM组件、JavaScript的JQuery库、Java的AWT中UI组件、文件上传的Apache Commons FileUpload组件及处理Microsoft Office的Apache POI组件等等
  • 从组件的实现功能的角度可以将组件分为两类即实现特定逻辑的功能组件和用来进行界面呈现的UI组件,在Java中,实现数据库连接的JDBC驱动和实现日志的Log4j都可以称为逻辑组件,而AWT、Swing等界面开发库提供的输入框、按钮之类的是UI组件,组件可以自行开发,用来提高代码的重用性,其最终呈现的方式可能是单个或多个.class类文件,或者打包成.jar文件

框架

  • 在组件的概念基础上,理解框架,框架通常是包含具备结构关系的多个组件,这些组件类凑到一起相互协作构成特定的功能,Java EE是官方定义的Java企业级开发的一系列标准规范,这些标准规范中有的仅仅定义了规范和接口,有的也提供了官方实现的框架,例如Enterprise JavaBean管理的EJB框架、JavaWeb应用程序开发的JSF框架等、
  • 一些开源组织也根据Java EE的规范和接口,提供了实现框架,例如实现JMS规范的ActiveMQ和RabbitMQ的消息队列框架;例如实现JPA规范的Hibernate和MyBatis的对象数据映射框架
  • 此外还有一些框架没有完全遵循Java EE的标准,而是更贴近现实和便捷的方式来规范和实现,典型的就是Spring Bean管理的依赖注入框架

容器

在Java语言中容器概念的应用场景非常多:

  • Java基本数据类型的容器类型,如List、Set和Map
  • Java UI组件的容器类型:如AWT中的WIndows容器
  • 用于存放Java对象的Bean容器,并且对其中的Bean实例进行管理,与基本的容器类型不同,除了存放还可以对该Bean实例的生命周期和依赖进行管理,如Spring Bean容器、EJB容器等
  • Java程序运行所需要的环境,如支持Servlet的Web容器(Tomcat)、运行EJB的容器(JBoss),这里的容器更多的时候被称为服务器
  • 从对象的容器角度来看,EJB容器和Spring Bean容器本质上功能是一致的,不同的是EJB装载的是需要符合EJB规范且需要继承特定类和接口的类对象,Spring装载的是POJO
  • EJB容器和Web容器都是J2EE容器的组成部分,同时具备Web容器和EJB容器功能的软件才能被称为Java EE应用服务器;EJB需要运行在应用服务器中,Spring Bean容器只需要在开发端导入相关的jar文件即可,且它可以运行在一般的Java Web服务器中

一般而言,框架的范围大于组件,组件可以包含在框架中,二者与容器的关系需要结合容器所对应的应用场景,就Spring而言,它是一个Java开发的框架,包含了IoC类型的Bean管理容器,另外还提供了切面编程AOP、数据访问事务管理等组件

JavaBean-POJO-EJB

JavaBean、POJO和EJB都是对Java类定义的规范,其目的是为了提高规范性和重用性

JavaBean

JavaBean是JCP定义的一种Java类的标准,包括属性、方法和事件三方面的规范

  • 是一个公共作用域的类,从而可以提供给其他类使用
  • 这个类有默认的无参数构造函数,从而可以让框架和容器使用反射机制进行实例化
  • 这个类需要被序列化且实现自Serializable接口,从而可以序列化和反序列化来进行对象的传输或保存到文件中
  • 如果有一系列可读写属性则通过getter或setter方法存取属性值,从而将属性隐藏,容器可以通过发射机制来进行属性值的读写
  • 对于使用Java进行桌面开发的UI组件Bean,还需要支持发送外部或者从外部接收的事件,包括Click事件和Keyboard事件等

POJO

POJO(Plain Old Java Object),具体含义就是指没有继承任何类,也没有实现任何接口,不需要遵从框架的定义,更没有被其他框架侵入的Java对象,它不依赖于任何框架,不担当任何特殊的角色,不需要实现任何Java框架指定的接口,POJO基本上不需要遵循任何规范,当一个POJO可序列化,有无参数的构造函数,使用getter和setter方法来访问属性时,他就是一个JavaBean

EJB

EJB习惯性被称作企业Bean,它是Java EE服务器端的组件模型也是一种规范,EJB定义的组建模型,开发者无须关注事务处理、安全性、资源缓存池和容错性,具体来说,EJB是用来定义分布式业务逻辑的组件Bean的,它规定的Bean定义必须遵循EJB定义的规范,继承特定的接口,所以EJB也常用来指这种类型的Bean的规范

EJB包含3中类型的Bean,分别是会话Bean(Session Bean)、实体Bean(Entity Bean)和消息驱动Bean(MessageDriven Bean),在EJB3规范中,实体Bean被单拿出来形成了JPA规范

EJB设计的目标是分布式应用,它基于RMI和JNDI等技术实现,而RMI使用的JRMP协议是位于TCP协议之上封装的一层协议,综合来看,EJB是一般JavaBean规范的强化和提升

IoC(Inversion of Control 控制反转)

IoC(Inversion of Control 控制反转) 是一种编程思想,或者说一种设计模式,设计模式中的抽象工厂方法从工厂类中获取同一接口的不同实现,一定程度上缓解了耦合,但代码的耦合还是实质的存在,IoC模式将耦合从代码中移除去,放入到配置中(例如XML文件),容器在启动时依据依赖配置生成依赖对象并注入,使用IoC容器后,代码从内部的耦合转移到外部容器,解耦性更高也更灵活

实例场景:有两个类,ClassA和ClassB,ClassA中的方法methodA()需要调用ClassB中的methodB()方法,传统的编程方式是现在ClassA的方法中new ClassB(),获取到ClassB的实例后调用methodB()方法
改进场景I:使用单例或工厂模式获取ClassB的实例
改进场景II:使用IoC模式,由容器创建和维护ClassB的实例,ClassA需要的时候从容器中获取即可,如此创建ClassB的实例的控制权就由程序代码转到容器

DI

控制权的转移即所谓的反转,依赖对象创建的控制权从应用程序本身转移到外部容器,控制反转的实现策略通常有如下两种:

  • 依赖查找(Dependency Lookup):JavaEE中传统的依赖管理方式,JavaEE的JNDI(Java Naming and Directory Interface)规范对服务和组件的注册和使用类似于这种策略;首先需要将依赖或服务进行注册,然后通过容器提供的API来查找依赖对象和资源,该策略是中央控管的方式,例如EJB和Webservice等就是这种方式
  • 依赖注入(Dependency Injection):依赖对象通过注入进行创建,由容器负责组建的创建和注入,这是更流行的IoC实现策略,根据配置将符合依赖关系的对象传递给需要的对象,属性注入和构造器注入式常见的依赖注入方式
  • IoC是一种软件设计思想,DI是这种思想的一种实现,控制反转乃至依赖注入的目的不是提升系统性能,而是提升组件重用性和系统可维护性
  • 依赖注入使用反射等底层技术,根据类名来生成相应的对象,注入依赖项和执行方法,但与常规方式相比反射会消耗更多的资源并导致性能衰减,但在提升代码的结构性和可维护性的同时,需要牺牲一定的系统性能

Spring与EJB

Spring和EJB同作为Bean托管容器,Spring管理的是一般的POJO,EJB管理的是继承特定接口的Enterprise JavaBean,在EJB的框架下开发的EJB组件必须继承指定的接口和类,并把编写好的类打包放到EJB服务器上运行,业务逻辑相关的实现集中在EJB中完成,而EJB容器则负责提供重复性质的和系统级的功能,通过开放接口的方式对外提供完整的业务服务,因为需要配置很多XML文件,而且需要打包部署到EJB容器,因此EJB被称为重量级框架

EJB是JCP官方提出的大型企业级应用开发的框架,目标和核心是分布式应用而对于中小应用而言,分布式和远程访问不是必须要有的甚至根本不需要,所以Spring更受开发者的推崇

基于Spring框架开发,组件不需要继承特定的类和接口,通过配置容器创建和管理对象并装载依赖对象,而且与Web开发无缝集成被称为轻量级容器