> 文档中心 > 尊敬的面试官,我该如何告诉你我精通Spring(一)初入Spring

尊敬的面试官,我该如何告诉你我精通Spring(一)初入Spring

目录

  • 1 写在前面的话
  • 2 为什么要学 Spring
    • 2.1 从面包来说
    • 2.2 从精神食粮来说
  • 3 如果没有 Spring,我们是怎么写代码
    • 3.1 方案
    • 3.2 方案二
    • 3.3 方案三
    • 3.4 方案四
    • 3.5 方案五
    • 3.6 小结

1 写在前面的话

1、小七不提供任何可以直接运行的源代码,好记性不如烂笔头,希望大家可以亲自动手跟着文章中的代码敲一下。
2、本系列文章说的 Spring,未做特殊说明皆指代 SpringFramework。
3、为了更好的阅读本文,读者至少要学习了解过JavaSE和JavaEE。

2 为什么要学 Spring

2.1 从面包来说

SpringFramework 实际上已经成为了 JavaEE 的标准,作为一个后台 JavaCoder 是肯定离不开它的。说直白点就是,企业需要,学习 Spring 能让你升职加薪。

2.2 从精神食粮来说

Spring 无论是设计还是代码规范都很好(如果你有幸拜读过 eureka 的源码,小七相信你一定不会反对我的),对开发人员技术的提升很有帮助。说直白点,多看大佬写的代码,你会感觉自己也是个大佬~

3 如果没有 Spring,我们是怎么写代码

首先我们来看下面这个例子。
假设我们有两个类
类 A

public class A {    public void a(){ System.out.println("类 A 的 a()方法被调用了...");    }}

类 B

public class B {    public void b(){ System.out.println("类 B 的 b()方法被调用了...");    }}

如果我们要在 B 类的 b 方法中调用 A 类的 a 方法(这个时候,我们说B是依赖于A的),我们能怎么做呢?

3.1 方案一

直接在 b 方法中,创建 A 对象,通过 A 对象调用 a 方法

public class B {    public void b(){ System.out.println("类 B 的 b()方法被调用了..."); A a = new A(); a.a();    }}

此方案缺点很明显,A和B是强耦合在一起的,并且还是直接写死在b()方法中的。

3.2 方案二

我们通过组合的方式,将A作为B的属性,并且构造B的时候就实例化一个A类。

public class B {    private A a;    public B(){ this.a = new A();    }    public void b(){ System.out.println("类 B 的 b()方法被调用了..."); this.a.a();    }}

以上方案也有缺点。B中A对象的创建是写死的,也就是我们无法控制A对象的生成,举个例子,如果我们想在创建B对象的时候,使用不同的A对象,以上方法就是无能为力的。

3.3 方案三

为了不把B中A对象的创建写死,我们可以改变B的构造方法,外部传A进去。

public class B {    private A a;    public B(A a){ this.a = a;    } public void b(){ System.out.println("类 B 的 b()方法被调用了..."); this.a.a();    }}

这个时候,当前需求下我们的问题基本上都解决了。但是如果B中不仅仅依赖了A,还有CDF等等复杂的依赖关系,且不说写起来复杂,修改、拓展也很困难。

3.4 方案四

以上三种方案都在生成对象的时候存在问题,站在前人的肩膀上,生成对象我们可以使用工厂模式,如下:

public class BeanFactory {    public static A getBean(String className) { try {     return (A) Class.forName(className).newInstance(); } catch (Exception e) {     e.printStackTrace();     throw new RuntimeException("初始化失败, 失败原因: " + e.getMessage()); }    }}

这里我们通过反射,传入全类名去获取我们需要的对象,那我们通过BeanFactory.getBean(className)方法,就能很简单的获取到我们想要的那个对象了。

3.5 方案五

针对方案四,我们还可以做一丢丢优化,从外部配置文件获取。
首先在resources下面写一个spring.properties,内容如下

a=com.sheep.ioc.ioc001.A

然后初始化的时候加载这个文件,最后修改一下反射的代码

public class BeanFactory {    // 直接使用java的类库    private static Properties properties;    // 加载spring.properties文件    static { properties = new Properties(); try {     properties.load(BeanFactory.class.getClassLoader().getResourceAsStream("spring.properties")); } catch (IOException e) {     throw new ExceptionInInitializerError("BeanFactory初始化失败, 失败原因: " + e.getMessage()); }    }    public static Object getBean(String beanName) { try {     Class<?> beanClazz = Class.forName(properties.getProperty(beanName));     return beanClazz.newInstance(); } catch (ClassNotFoundException e) {     throw new RuntimeException("未获取到[" + beanName + "]的bean!", e); } catch (IllegalAccessException | InstantiationException e) {     throw new RuntimeException("[" + beanName + "]初始化失败!", e); }    }}

3.6 小结

方案四、五,我们将获取对象的方式交给了 BeanFactory 。这种将控制权交给别人的思想,就叫做:控制反转(IOC)。而 BeanFactory 根据指定的 beanName 去获取和创建对象的过程,就叫做:依赖查找( DL )。 说直白点,就是你去洗脚,平常你随便点一个小姐姐,那么控制权在你;但是有一天你对老板说,你安排,那么控制权就不在你了,你就把点小姐姐的权利给了老板,那么就是控制反转了。