技术交流笔记——SPRING IOC 原理

简介:
前两天组织了一次内部的技术交流,主题是spring ioc框架的原理。时间很短,只有一个小时,所以内容比较简单,主要是几个题目,和围绕题目的一些讨论。

首先考虑这样一个场景:
系统中有如下几个类。
Class A {
  B b;
  C c;
  public void service(){
  Assert b!=null;
  Assert c!= null;
  ....
  }
}

Class B{
  D d;
}

Class C{
  E e;
  F f;
}

Class D{}
Class E{}
Class F{}

在调用A的service时,必须先对它进行初始化,并设置b和c的初始值。初始化B时,必须先初始化d;初始化C时,必须先初始化e和f。

问题1:使用new的方法,写出完整的对A进行初始化、并调用service()服务的步骤。
参考答案:
class A{
public A(){
this.b=new B();
this.c=new C();
}
……
}
Class B{
public B(){
this.d=new D();
}
}
Class C{
public C(){
this.e=new E();
this.f=new F();
}
}
调用代码:
public static void main(String[] args){
A a=new A();
a.service();
}

问题2: 由于需求变更,类A被修改为:

Class A {

//B b;

D d;

C c;

public void service(){

Assert d!=null;

Assert c!= null;

....

}

}

请修改问题1中的代码,使A能够正常初始化。

参考答案:

class A{
public A(){
this.d=new D();
this.c=new C();
}
……
}
……
调用代码:
public static void main(String[] args){
A a=new A();
a.service();
}

问题3、 由于需求变更,类A的服务service()被拆分成两部分service()和service_2(), 并且,系统中先有的调用service()服务的代码,有一些要改用service_2()。类A的 定义已修改如下:

Class A {

D d;

C c;

G g;

public void service(){

Assert d!=null;

Assert c!= null;

....

}

public void service_2(){

Assert g!= null;

……

}

}

请修改问题2中的代码,以适应新的需求。

参考答案:

class A{
public A(D _d, C _c){
this.d=_d;
this.c=_c;
}

public A(G _g){
this.g=_g;
}
……
}
……
调用代码:
public static void main(String[] args){
A a=new A(new D(),new C());
a.service();

A a_2=new A(new G());
a.service_2();
}
问题4、 公司发现类 A 可以使用单例实现。请修改上述代码以实现此需求。
参考答案:
class A{
private static A a=new A(new D(),new C());
private static A a_2=new A(new G());

public static A getA(){
return a;
}

public static A getA_2(){
return a_2;
}

private A(D _d, C _c){
this.d=_d;
this.c=_c;
}

private A(G _g){
this.g=_g;
}
……
}
……
调用代码:
public static void main(String[] args){
A a=A.getA();
a.service();

A a_2=A.getA_2();
a.service_2();
}


直接使用new关键字,是最基础的实例化对象的方式。使用这种方式直接进行实例化,最直接的问题是将服务的调用者和服务的实现类耦合在了一起。如问题1中,main方法中直接new一个A的实例,那么它就和类A耦合起来了。A和B、C,B和D,C和E、F,也是一样。

直接耦合带来的麻烦,在问题3、4中体现得最为明显。由于需求变更而导致的对类A进行的修改,都引发了对调用代码的修改。参考答案中只给出了一处调用。但是设想一下,如果A提供的是基础服务,比如数据库操作,或者一些基础的业务逻辑。那么,系统中会有多少对A的引用?一旦数据库从Oracle迁移到MySQL,或者某服务针对江西提供一种逻辑、针对湖南提供另一种逻辑(这种情况在我参与的项目中真实出现过),那么当修改类A时,系统中会有多少处代码要做变更?

希望这部分内容能帮助理解这样直接耦合会带来什么样的问题。
而解决问题的办法,无疑就是解耦合。问题2和问题4给了我们一种思路。
问题2将类A的创建全部封装在了无参数构造方法A()里面。这样,创建A的过程就和调用服务的过程完全隔离开了:调用A的时候完全不必知道,要创建A需要做些什么工作。可惜这种方式有点脆弱,遇到问题3就不行了,因为A()方法只能定义一个。它无法实现两种创建逻辑。
问题4延续了问题2的思路,把创建A的逻辑封装起来。调用代码中只需要获取实例并调用服务,而不需要考虑A是如何创建的。

这其实就是工厂模式的思路。

问题5、请使用工厂模式,改写问题4中的代码。
参考答案:

Public abstract class Factory {

Public static Factory aFactory(){

Return new FactoryA ();

}


Public static Factory a2Factory(){

Return new FactoryA_2();

}

Create();

}

Public class FactoryA implements Factory {

@Override

Public A Create(){

return new A(new D(),new C());

}

}


Public class FactoryA_2 implements Factory {

@Override

Public A Create(){

return new A_2(new G());

}

}

……

调用代码:

public static void main(String[] args){

A a = Factory.aFactory().Create();

a.service();


A a_2 = Factory.a2Factory().Create();

a_2.service_2();

}


问题6、将service()和service_2()方法提取到接口中,再修改问题5中的代码。

参考答案:略


问题7、用问题6的思路,为其它类(B/C/D/E/F/G)等创建工厂

参考答案:略

问题7的出现带来了一个新的困扰:那么多的类,要写那么多的工厂……尤其是,当我们对现有系统进行改造或者重构时,这种重复工作量会有多少,可想而知。


问题8:为了简化问题7的工作,公司定义了一个通用的工厂类

public Class Factory{

/**

根据入参,调用指定类的默认构造方法(无参数构造方法),生成一个指定的类的实例。如果找不到指定的类,或者指定的类没有可用的构造方法,则返回null

* <p />

例如,调用

* String a = Factory.product(java.lang.String),将返回一个””。等同于调用了 String a = new String();

*

* @param className 用户指定的类名。必须是全路径名,

* @return 用户指定的类的一个实例,或者是null

*/

public static Object product(String className){

}

}

请将①处的代码补充完整。

这里就需要用到java的反射机制了。



综合上述问题,思考一下:为什么会出现Spring IOC框架?它的基本原理是什么?

最简单的说,IOC出现的原因就是为了解耦合。利用一个通用的工厂,来管理各个实现类的创建过程以及在创建过程中引入的类的依赖关系。这样,各个类在代码层级上,是可以做到“兵不知将将不知兵”的,从而减少对类进行修改、扩展时的工作量。

它的基本原理,很明了,就是反射+工厂。



本文转自 斯然在天边 51CTO博客,原文链接:http://blog.51cto.com/winters1224/1327881,如需转载请自行联系原作者

相关文章
|
8月前
|
缓存 Java 开发者
【Spring】原理:Bean的作用域与生命周期
本文将围绕 Spring Bean 的作用域与生命周期展开深度剖析,系统梳理作用域的类型与应用场景、生命周期的关键阶段与扩展点,并结合实际案例揭示其底层实现原理,为开发者提供从理论到实践的完整指导。
1001 22
|
8月前
|
人工智能 Java 开发者
【Spring】原理解析:Spring Boot 自动配置
Spring Boot通过“约定优于配置”的设计理念,自动检测项目依赖并根据这些依赖自动装配相应的Bean,从而解放开发者从繁琐的配置工作中解脱出来,专注于业务逻辑实现。
2768 0
|
7月前
|
XML Java 测试技术
《深入理解Spring》:IoC容器核心原理与实战
Spring IoC通过控制反转与依赖注入实现对象间的解耦,由容器统一管理Bean的生命周期与依赖关系。支持XML、注解和Java配置三种方式,结合作用域、条件化配置与循环依赖处理等机制,提升应用的可维护性与可测试性,是现代Java开发的核心基石。
|
7月前
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
725 2
|
存储 人工智能 自然语言处理
RAG 调优指南:Spring AI Alibaba 模块化 RAG 原理与使用
通过遵循以上最佳实践,可以构建一个高效、可靠的 RAG 系统,为用户提供准确和专业的回答。这些实践涵盖了从文档处理到系统配置的各个方面,能够帮助开发者构建更好的 RAG 应用。
6370 117
|
9月前
|
Java 关系型数据库 数据库
深度剖析【Spring】事务:万字详解,彻底掌握传播机制与事务原理
在Java开发中,Spring框架通过事务管理机制,帮我们轻松实现了这种“承诺”。它不仅封装了底层复杂的事务控制逻辑(比如手动开启、提交、回滚事务),还提供了灵活的配置方式,让开发者能专注于业务逻辑,而不用纠结于事务细节。
1163 1
|
前端开发 Java 数据库连接
Spring核心原理剖析与解说
每个部分都是将一种巨大并且复杂的技术理念传达为更易于使用的接口,而这就是Spring的价值所在,它能让你专注于开发你的应用,而不必从头开始设计每一部分。
321 32
|
11月前
|
XML 人工智能 Java
Spring IOC 到底是什么?
IOC(控制反转)是一种设计思想,主要用于解耦代码,简化依赖管理。其核心是将对象的创建和管理交给容器处理,而非由程序直接硬编码实现。通过IOC,开发者无需手动new对象,而是由框架负责实例化、装配和管理依赖对象。常见应用如Spring框架中的BeanFactory和ApplicationContext,它们实现了依赖注入和动态管理功能,提升了代码的灵活性与可维护性。
270 1
|
10月前
|
缓存 安全 Java
Spring 框架核心原理与实践解析
本文详解 Spring 框架核心知识,包括 IOC(容器管理对象)与 DI(容器注入依赖),以及通过注解(如 @Service、@Autowired)声明 Bean 和注入依赖的方式。阐述了 Bean 的线程安全(默认单例可能有安全问题,需业务避免共享状态或设为 prototype)、作用域(@Scope 注解,常用 singleton、prototype 等)及完整生命周期(实例化、依赖注入、初始化、销毁等步骤)。 解析了循环依赖的解决机制(三级缓存)、AOP 的概念(公共逻辑抽为切面)、底层动态代理(JDK 与 Cglib 的区别)及项目应用(如日志记录)。介绍了事务的实现(基于 AOP
396 0
|
10月前
|
监控 架构师 NoSQL
spring 状态机 的使用 + 原理 + 源码学习 (图解+秒懂+史上最全)
spring 状态机 的使用 + 原理 + 源码学习 (图解+秒懂+史上最全)

热门文章

最新文章