尊敬的面试官,我该如何告诉你我精通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 )。 说直白点,就是你去洗脚,平常你随便点一个小姐姐,那么控制权在你;但是有一天你对老板说,你安排,那么控制权就不在你了,你就把点小姐姐的权利给了老板,那么就是控制反转了。