好程序员Java干货分享Spring框架之IOC原理

好程序员 Java 干货分享 Spring 框架之 IOC 原理, 前言:Spring 框架是我们进行企业级开发的最常用框架,本章我们将了解 Spring 框架,并学习 Spring 的 IOC 特性以及 IOC 的实现原理:注解和反射。

创新互联专业为企业提供本溪网站建设、本溪做网站、本溪网站设计、本溪网站制作等企业网站建设、网页设计与制作、本溪企业网站模板建站服务,10余年本溪做网站经验,不只是建网站,更提供有价值的思路和整体网络服务。

Spring 框架简介

   Spring 是一种轻量级的控制反转( IOC )和面向切面编程( AOP )的容器框架,能够为企业级开发提供一站式服务。

   Spring 的优点有

   1. 方便解耦,简化开发

  通过 Spring 提供的 IoC 容器,我们可以将对象之间的依赖关系交由 Spring 进行控制,避免硬编码所造成的过度程序耦合。有了 Spring ,用户不必再为单实例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。

   2.AOP 编程的支持

  通过 Spring 提供的 AOP 功能,方便进行面向切面的编程,许多不容易用传统 OOP 实现的功能可以通过 AOP 轻松应付。

   3. 声明式事务的支持

  在 Spring 中,我们可以从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活地进行事务的管理,提高开发效率和质量。

   4. 方便程序的测试

  可以用非容器依赖的编程方式进行几乎所有的测试工作,在 Spring 里,测试不再是昂贵的操作,而是随手可做的事情。例如: Spring 对 Junit4 支持,可以通过注解方便的测试 Spring 程序。

   5. 方便集成各种优秀框架

   Spring 不排斥各种优秀的开源框架,相反, Spring 可以降低各种框架的使用难度, Spring 提供了对各种优秀框架(如 Struts,Hibernate 、 Hessian 、 Quartz )等的直接支持。

   6. 降低 Java EE API 的使用难度

   Spring 对很多难用的 Java EE API (如 JDBC , JavaMail ,远程调用等)提供了一个薄薄的封装层,通过 Spring 的简易封装,这些 Java EE API 的使用难度大为降低。

  

Spring 的组成

好程序员Java干货分享Spring框架之IOC原理

   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 和 DI

   IOC ( Inverse Of Control )是控制反转的意思,作用是降低对象之间的耦合度。

  一般情况下我们直接在对象内部通过 new 进行创建对象,是程序主动去创建依赖对象;而 IoC 是有专门一个容器来创建这些对象,即由 Ioc 容器来控制对象的创建;这样就是由容器来控制对象,而不是由我们的对象来控制,这样就完成了控制反转。

   DI(Dependency Injection )即“依赖注入”:是组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。

  

IOC 的原理:注解 + 反射

下面的案例讲解了 IOC 的原理,模拟为电脑配置不同的 CPU 和内存, CPU 有 AMD 和 INTEL 两种,内存有 DDR8G 和 DDR16G 两种

  1. /**
  2. * CPU 接口
  3. */
  4. public interface Cpu {
  5. void run();
  6. }
  7. /**
  8. *  内存接口
  9. */
  10. public interface Memory {
  11. void read();
  12. void write();
  13. }
  14. /**
  15. * AMD 的 CPU
  16. */
  17. public class AMDCpu implements Cpu {
  18. public void run() {
  19. System.out.println("AMD 的 CPU 正在运行 ....");
  20. }
  21. }
  22. /**
  23. * Intel 的 CPU
  24. */
  25. public class IntelCpu implements Cpu{
  26. public void run() {
  27. System.out.println("Intel 的 CPU 正在运行 ....");
  28. }
  29. }
  30. /**
  31. * DDR8G 的内存
  32. */
  33. public class DDR8GMemory implements Memory {
  34. public void read() {
  35. System.out.println(" 使用 DDR8G 的内存读取数据 ....");
  36. }
  37. public void write() {
  38. System.out.println(" 使用 DDR8G 的内存写入数据 ....");
  39. }
  40. }
  41. /**
  42. * DDR16G 的内存
  43. */
  44. public class DDR16GMemory implements Memory {
  45. public void read() {
  46. System.out.println(" 使用 DDR16G 的内存读取数据 ....");
  47. }
  48. public void write() {
  49. System.out.println(" 使用 DDR16G 的内存写入数据 ....");
  50. }
  51. }
  52. public class TestComputer {
  53. @Test
  54. public void testComputer(){
  55. // 硬编码方式创建对象
  56. Computer computer = new Computer();
  57. Cpu cpu = new IntelCpu();
  58. Memory memory = new DDR16GMemory();
  59. computer.setCpu(cpu);
  60. computer.setMemory(memory);
  61. computer.start();
  62. }
  63. }

 

上面是使用硬编码方式创建电脑的 CPU 和内存属性,代码和具体的子类紧密耦合,不利于后期的维护和扩展。

修改的思路是:不由让程序主动创建去创建 CPU 和内存对象,而是通过注解方式标记 CPU 和内存的类型,使用反射将 CPU 和内存的对象注入到电脑的属性中。

添加代码:

  1. /**
  2. *  电脑组件的注解
  3. */
  4. @Retention(RetentionPolicy.RUNTIME)
  5. @Target(ElementType.FIELD)
  6. public @interface MyComponent {
  7. /**
  8. *  组件类型
  9. * @return
  10. */
  11. Class componentClass();
  12. }
  13. /**
  14. *  电脑类
  15. */
  16. public class Computer {
  17. @MyComponent(componentClass = IntelCpu.class)
  18. private Cpu cpu;
  19. @MyComponent(componentClass = DDR8GMemory.class)
  20. private Memory memory;
  21. ....}
  22. public class TestComputer {
  23. @Test
  24. public void testComputer(){
  25. // 通过反射和注解,将 cpu 和 memory 属性注入进去
  26. try {
  27. // 获得 Computer 类型
  28. Class computerClass = Computer.class;
  29. // 创建 Computer 对象
  30. Computer computer = computerClass.newInstance();
  31. // 获得 Computer 对象的属性
  32. Field[] fields = computerClass.getDeclaredFields();
  33. // 遍历属性
  34. for(Field field : fields){
  35. // 获得属性上定义的 MyComponent 注解
  36. MyComponent anno = field.getDeclaredAnnotation(MyComponent.class);
  37. // 获得配置的组件类型
  38. Class aClass = anno.componentClass();
  39. // 创建该组件的对象
  40. Object comp = aClass.newInstance();
  41. // 调用 set 方法赋值给属性
  42. String name = field.getName();
  43. name = "set" + name.substring(0,1).toUpperCase() + name.substring(1);
  44. // 通过方法名和参数类型获得方法
  45. Method method = computerClass.getDeclaredMethod(name, field.getType());
  46. // 调用方法
  47. method.invoke(computer,comp);
  48. }
  49. // 启动电脑
  50. computer.start();
  51. } catch (Exception e) {
  52. e.printStackTrace();
  53. }
  54. }
  55. }

程序如上面修改后,后期如果需要修改电脑的配置,只需要修改注解配置的类型,就可以注入不同的电脑组件,这样就降低了代码间的耦合性,维护代码变得比较简单。

  @MyComponent(componentClass = AMDCpu.class)

    private Cpu cpu;

 

  @MyComponent(componentClass = DDR16GMemory.class)

   private Memory memory;

 

总结

IOC (控制反转)是 Spring 最重要的原理,它将创建对象的主动权交给 Spring 容器, Spring 程序只需要进行一些配置,就可以使用不同的对象,极大的降低了代码耦合性,提高了程序的灵活性, IOC 的实现原理是反射机制。


本文名称:好程序员Java干货分享Spring框架之IOC原理
URL分享:http://ybzwz.com/article/pocpig.html