首页 > 应用开发 > > 好程序员Java干货分享Spring框架之IOC原理
好程序员 Java 干货分享 Spring 框架之 IOC 原理, 前言:Spring 框架是我们进行企业级开发的最常用框架,本章我们将了解 Spring 框架,并学习 Spring 的 IOC 特性以及 IOC 的实现原理:注解和反射。
Spring 是一种轻量级的控制反转( IOC )和面向切面编程( AOP )的容器框架,能够为企业级开发提供一站式服务。
Spring 的优点有
通过 Spring 提供的 IoC 容器,我们可以将对象之间的依赖关系交由 Spring 进行控制,避免硬编码所造成的过度程序耦合。有了Spring ,用户不必再为单实例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。
通过 Spring 提供的 AOP 功能,方便进行面向切面的编程,许多不容易用传统 OOP 实现的功能可以通过 AOP 轻松应付。
在 Spring 中,我们可以从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活地进行事务的管理,提高开发效率和质量。
可以用非容器依赖的编程方式进行几乎所有的测试工作,在 Spring 里,测试不再是昂贵的操作,而是随手可做的事情。例如:Spring 对 Junit4 支持,可以通过注解方便的测试 Spring 程序。
Spring 不排斥各种优秀的开源框架,相反, Spring 可以降低各种框架的使用难度, Spring 提供了对各种优秀框架(如Struts,Hibernate 、 Hessian 、 Quartz )等的直接支持。
Spring 对很多难用的 Java EE API (如 JDBC , JavaMail ,远程调用等)提供了一个薄薄的封装层,通过 Spring 的简易封装,这些 Java EE API 的使用难度大为降低。

Spring Core : Spring 框架的核心。 Spring 其它组件都依赖于核心组件,主要通过 BeanFactory 提供 IOC 等服务。
Spring Context : Sprin 上下文是一个配置文件,向 Spring 框架提供上下文信息。 Spring 上下文包括企业服务,例如 JNDI 、EJB 、电子邮件、国际化、校验和调度功能。
Spring AOP :通过配置管理特性, Spring AOP 模块直接将面向切面的编程功能集成到了 Spring 框架中。
Spring ORM : Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO 、 Hibernate 和iBatisSQL Map 。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
Spring DAO: DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。 Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
Spring Web: Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以, Spring 框架支持与 Jakarta Struts 的集成。 Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
Spring Web MVC: 为 web 应用提供了模型视图控制( MVC )和 REST Web 服务的实现。 Spring 的 MVC 框架可以使领域模型代码和 web 表单完全地分离,且可以与 Spring 框架的其它所有功能进行集成。
IOC ( Inverse Of Control )是控制反转的意思,作用是降低对象之间的耦合度。
一般情况下我们直接在对象内部通过 new 进行创建对象,是程序主动去创建依赖对象;而 IoC 是有专门一个容器来创建这些对象,即由 Ioc 容器来控制对象的创建;这样就是由容器来控制对象,而不是由我们的对象来控制,这样就完成了控制反转。
DI(Dependency Injection )即“依赖注入”:是组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。
下面的案例讲解了 IOC 的原理,模拟为电脑配置不同的 CPU 和内存, CPU 有 AMD 和 INTEL 两种,内存有 DDR8G 和 DDR16G 两种
/**
* CPU 接口
*/
public interface Cpu {
void run();
}
/**
* 内存接口
*/
public interface Memory {
void read();
void write();
}
/**
* AMD 的 CPU
*/
public class AMDCpu implements Cpu {
public void run() {
System.out.println("AMD 的 CPU 正在运行 ....");
}
}
/**
* Intel 的 CPU
*/
public class IntelCpu implements Cpu{
public void run() {
System.out.println("Intel 的 CPU 正在运行 ....");
}
}
/**
* DDR8G 的内存
*/
public class DDR8GMemory implements Memory {
public void read() {
System.out.println(" 使用 DDR8G 的内存读取数据 ....");
}
public void write() {
System.out.println(" 使用 DDR8G 的内存写入数据 ....");
}
}
/**
* DDR16G 的内存
*/
public class DDR16GMemory implements Memory {
public void read() {
System.out.println(" 使用 DDR16G 的内存读取数据 ....");
}
public void write() {
System.out.println(" 使用 DDR16G 的内存写入数据 ....");
}
}
public class TestComputer {
@Test
public void testComputer(){
// 硬编码方式创建对象
Computer computer = new Computer();
Cpu cpu = new IntelCpu();
Memory memory = new DDR16GMemory();
computer.setCpu(cpu);
computer.setMemory(memory);
computer.start();
}
}上面是使用硬编码方式创建电脑的 CPU 和内存属性,代码和具体的子类紧密耦合,不利于后期的维护和扩展。
修改的思路是:不由让程序主动创建去创建 CPU 和内存对象,而是通过注解方式标记 CPU 和内存的类型,使用反射将 CPU 和内存的对象注入到电脑的属性中。
添加代码:
/**
* 电脑组件的注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface MyComponent {
/**
* 组件类型
* @return
*/
Class componentClass();
}
/**
* 电脑类
*/
public class Computer {
@MyComponent(componentClass = IntelCpu.class)
private Cpu cpu;
@MyComponent(componentClass = DDR8GMemory.class)
private Memory memory;
....}
public class TestComputer {
@Test
public void testComputer(){
// 通过反射和注解,将 cpu 和 memory 属性注入进去
try {
// 获得 Computer 类型
Class<Computer> computerClass = Computer.class;
// 创建 Computer 对象
Computer computer = computerClass.newInstance();
// 获得 Computer 对象的属性
Field[] fields = computerClass.getDeclaredFields();
// 遍历属性
for(Field field : fields){
// 获得属性上定义的 MyComponent 注解
MyComponent anno = field.getDeclaredAnnotation(MyComponent.class);
// 获得配置的组件类型
Class aClass = anno.componentClass();
// 创建该组件的对象
Object comp = aClass.newInstance();
// 调用 set 方法赋值给属性
String name = field.getName();
name = "set" + name.substring(0,1).toUpperCase() + name.substring(1);
// 通过方法名和参数类型获得方法
Method method = computerClass.getDeclaredMethod(name, field.getType());
// 调用方法
method.invoke(computer,comp);
}
// 启动电脑
computer.start();
} catch (Exception e) {
e.printStackTrace();
}
}
}程序如上面修改后,后期如果需要修改电脑的配置,只需要修改注解配置的类型,就可以注入不同的电脑组件,这样就降低了代码间的耦合性,维护代码变得比较简单。
@MyComponent(componentClass = AMDCpu.class)
private Cpu cpu;
@MyComponent(componentClass = DDR16GMemory.class)
private Memory memory;
IOC (控制反转)是 Spring 最重要的原理,它将创建对象的主动权交给 Spring 容器, Spring 程序只需要进行一些配置,就可以使用不同的对象,极大的降低了代码耦合性,提高了程序的灵活性, IOC 的实现原理是反射机制。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/3402/viewspace-3166825/ ,如需转载,请注明出处,否则将追究法律责任。