我们知道,Java方面的高级程序员一定得掌握Spring的技能,其中包括Spring 依赖注入(IOC),面向切面(AOP),和数据库的整合(比如和Hibernate整合或声明式事务等)以及Spring MVC架构。其中,Spring的依赖注入是重中之重,在面试时,面试官一定会问这方面的问题。
根据我的培训和面试经验,这方面的知识点虽然不难(初学者估计最多3天就能看明白并调通程序),但要把其中的各混淆点(也就是面试点)讲清楚不容易,换句话说,初级程序员在学习Spring IOC这部分的知识时,或多或少会走些弯路,在通常情况下,会经过一次或多次面试的失败(就是交学费)后才能理顺这部分的知识体系。
在本文里,将整理归纳 java web轻量级开发面试教程 里的相关知识点,一次性地把这部分的知识点讲全,可以这样说,大家看完这篇文章后,能尽量减少交学费的次数。
以上是开场白,如下是正文。
--------------------------------------------------------------------------------------------------------------------
1 通过一个简单但易学的案例来了解依赖注入
步骤一 开发提供服务的SayHello.java程序。
package com;
public class SayHello {
private HelloWorldSpring helloWorldSpring;
public HelloWorldSpring getHelloWorldSpring() {
return helloWorldSpring;
}
public void setHelloWorldSpring(HelloWorldSpring helloWorldSpring) {
this.helloWorldSpring = helloWorldSpring;
}
public void sayHello(){
System.out.println("Say Hello:" + helloWorldSpring.sayHello());
}
}
第10行定义了一个sayHello的方法,在这方法里,调用了在第3行定义的helloWorldSpring对象,输出一串文字。
这里有一个比较有意思的现象,虽然在第4行和第7行针对helloWorldSpring对象定义了get和set的方法,但在第11行使用helloWorldSpring对象之前,始终没有用new关键字初始化这个对象,那么按照以往的经验,会不会出现空指针异常呢?
别着急,先看下HelloWorldSpring这个类里有没有特殊的动作。
步骤二 定义HelloWorldSpring.java这个类。
package com;
public class HelloWorldSpring {
private String sayContent;
public String sayHello() {
System.out.println("HelloWorld Spring!");
return "Hello World Spring";
}
}
这里直接在第4行定义了sayHello的方法,也没看到特殊的代码。接下来看一下在SpringMain这个类里是如何调用的。
步骤三 开发调用者SpringMain.java,请大家注意一下调用sayHello方法的方式。
package com;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringMain {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(
"conf/applicationContext-*.xml"); SayHello sayHello = (SayHello) context.getBean("SayHello");
sayHello.sayHello();
}
}
关键代码在第9行和第10行,是通过一个getBean方法,获得了SayHello对象的一个实例,随后调用了其中的sayHello方法。在这之前,通过第6行的代码,装载了一个配置文件。
戏法变到这里,大家看到了两个不可思议的地方。第一,在SayHello类里,始终没有初始化HelloWorldSpring对象,就直接用了。第二,在SpringMain类里,没有像往常那样用SayHello sayHello = new SayHello(); 的方法初始化对象,而是通过getBean的方式来获得类的实例。
其实,这里大家已经能看到“低耦合”的写法了。让我们最后看完Spring的配置文件再来综合体验IoC的好处。
步骤四 编写Spring的配置文件applicationContext-service-api.xml,关键代码如下
<bean id="HelloWorldSpring" class="com.HelloWorldSpring">
</bean>
<bean id="SayHello" class="com.SayHello" >
<property name="helloWorldSpring" ref="HelloWorldSpring" />
</bean>
在第1行和第2行里,定义了一个Bean。在Spring里,一个Bean往往和一个类所对应,这里id是HelloWorldSpring的这个Bean是和com.HelloWorldSpring这个类所对应。
而在第3行到第5行里,用id是SayHello这个Bean对应com.SayHello这个类,请大家注意第4行,用内置property这个方式,把HelloWorldSpring这个类内嵌到SayHello类里。
2 IoC的特点,不用New就可以初始化类
SpringMain.java的主要代码如下。
1 ApplicationContext context = new ClassPathXmlApplicationContext("conf/applicationContext-*.xml");
2 SayHello sayHello = (SayHello) context.getBean("SayHello");
3 sayHello.sayHello();
运行SpringMain.java时,首先是把配置文件里定义的信息装载到context类里;接着在第2行里,通过context.getBean方法,根据配置文件的定义,获取ID为SayHello(即class是com.SayHello)这个类;随后在第3行里使用这个类的sayHello方法。从代码中大家可以看出,这里同样没有用到new,而是根据配置文件来初始化类。
没有使用new,就意味着低耦合,具体而言,就是SayHello、HelloWorldSpring和SpringMain这三个类之间的耦合度很低。
假设有三个团队在开发维护这三个类,如果用常规new方法来创建类,比如在SayHello类里用HelloWorldSpring helloWorldSpring = new HelloWOrldSpring();,那么一旦管理HelloWorldSpring类的团队要修改调用的接口,比如new的构造函数需要带参数,那么SayHello类的管理者就不得不受无妄之灾,也需要修改本身的代码。
要知道在公司里,修改代码并且发布到生产环境,要经过很烦琐且很严格的审批流程,必须要经历代码审查、代码提交、测试人员测试、领导审批、最终发布以及发布后检查这些步骤。如果用刚才看到的通过配置文件装载类,在本地代码里没有new的这套开发方式,那么如果一个团队修改了代码,其他团队就有可能不必改动代码,这样就可以很大程度上避免不必要的工作。
3 控制翻转和依赖注入
控制翻转的英文名字叫IoC(Inversion of Control),依赖注入英文名叫DI(Dependency Injection),下面通过下表来看一下它们的概念。
概念名 |
含义 |
表现形式 |
控制翻转(IoC,控制反转) |
类之间的关系,不用代码控制,而是由Spring容器(也就是Spring的jar包)来控制。控制权由代码翻转到容器里,这叫控制翻转 |
在初始化对象时,在代码里无须new,而是把类之间的关系写到配置文件里 |
依赖注入(DI) |
在代码运行时,如果我们要在一个类里使用(也叫注入)另一个类,比如在上述的SayHello类里要初始化另外一个HelloWorldSpring类,那么这种注入就是依赖于配置文件的 |
同样是把类之间的调用关系写到配置文件里,在运行时,会根据配置文件,把HelloWorldSpring这个类注入SayHello里 |
通过上面的描述,能看到它们其实是从不同的角度讲述的同一件事情。依赖注入强调类的注入是由Spring容器在运行时完成,而控制反转强调类之间的关系是由Spring容器控制。
从这两个名词可知, Spring给我们带来了一种全新的编程理念,即不用new也可以创建和使用对象。这种开发方式让我们能像搭积木一样组装不同的类,组装后的类之间的耦合度很低,一个类的修改可以不影响(或者影响度很小)其他的类,这样就可以避免一个小修改带来的一大串连锁反应。
大家在了解Spring的时候,一定请理解“低耦合”这个好处,这本来是面向对象思想带给我们的好处,在Spring开发的过程中我们确实能感受到。
4 读取配置文件的各种方式
在Spring里,通常在配置文件中描述各类以及类之间的包含关系,在使用的时候,会先加载配置文件,Spring的内核会读取配置文件,随后动态地组装各类。
通过下表来总结一下读取配置文件的各种方式,它们之间没有优劣之分,大家可以挑选个最适用的,具体来讲,没有特殊情况,就可以用ClassPathXmlApplicationContext。
类名 |
例子 |
XmlBeanFactory |
Resource resource = new ClassPathResource("bean.xml"); BeanFactory factory = new XmlBeanFactory(resource); |
ClassPathXmlApplicationContext |
ApplicationContext factory=new ClassPathXmlApplicationContext("conf/appcontext.xml"); |
用文件系统类来读取 FileSystemXmlApplicationContext |
ApplicationContext factory=new FileSystemXmlApplicationContext("classpath:appcontext.xml"); |
5 单例和多例
我们知道,Spring的容器会在程序运行时,根据配置文件自动地创建(或者叫实例化)具体的Java类(也叫class,或叫Bean)。在配置文件里,可以设置创建文件时是否用单例的方式,如果没有设置,则会自动用默认的单例的方式来创建文件。如果不想用单例,则可以通过如下两种语法来修改,它们是等价的。
<bean id="SayHello" class="com.SayHello" singleton="false"> 或者
<bean id="SayHello" class="com.SayHello" scope="prototype">
在实际项目中,一般用单例模式来创建无状态的Bean,而对于有状态的Bean,一般不用这种模式。所谓无状态的Bean,是指没有能够标识它目前状态属性的Bean,比如共享单车,A用好以后,可以放入共享池(即放到马路边上),B可以继续使用。由于没有供某个特定的用户使用,所以也就不能保持某一用户的状态,所以叫无状态Bean。相反,如果针对个人的自行车,那么会有个状态来表明是个人的。
讲到这里,请大家确认如下概念,并不是我们首先设置了singleton是false,所以Spring容器才用单例的方式,恰恰相反,根据实际的需求,待创建的类可以被其他多个类共享,因此我们才设置singleton是false。是先有需求再有具体的实现。
这个知识点可以说是Spring面试的必考点,下面通过下表来对比一下两者的差别
列别 |
实际用例 |
特点 |
有状态Bean |
我们访问网站登录后都有自己的用户名和密码,系统可以用一个有状态的Bean来记录我们的访问信息,比如来源IP访问页面列表和访问时间等 |
会为每次调用创建一个实例,一旦调用结束,比如用户离开了网站,则该Bean就会被销毁 |
无状态Bean |
数据库连接的通用类,其他类可以用它来获取数据库连接并进行操作 |
可以在缓冲池里只维护一个实例,无须创建和销毁操作,性能高,但是线程不安全 |
6 论面试
当年我追过一本小说,叫天择,里面有个故事情节,皇帝请主角吃饭,让主角点菜,主角点的不是龙肝凤胆,也不是山珍海味,是两个家常菜,炒青菜和蛋炒饭,如下我引用的是书中原话:
天下万事万物,都是有一个从简单到复杂,又从复杂趋向于简单的过程,用道家的话来说,就是天下大道,以简驭繁,用佛家的话来说,就是看山是山,看山不是山,看山仍是山的三大境界。蛋炒饭和炒青菜这两样东西每个人都吃了不知道多少次,但是,正因为如此,能够在这平凡当中做出来令人难忘的伟大味道,这才是顶尖的高手的境界!
学习Spring IOC这平凡的知识点,也会经历过上述”从简单到复杂“的过程,作者根据多年面试培训(甚至包括写书)的经验,从纷繁复杂的Spring IOC的诸多知识点中提炼出针对初级程序员有用的上述内容,不能说是顶尖高手,但至少也经过沉淀,对大家多少有些帮助,也一定能帮助大家少走些弯路(这也是本文申请加入首页的理由)。
面试时也这样,面试官会在乎候选人掌握多少知识点(广度),更在乎对于知识点的深度,如果候选人能从IOC这种平凡的知识点里说出自己的高深体会,这样反而能更打动面试官。
在这方面可以说出如下的要点:
1 基本概念(谁都会说)
2 结合项目说明怎么用IOC,以及IOC的好处(不用new就能用,低耦合),这大家可以结合本文里提到的案例说明
3 一些外围的知识点,比如如何导入配置文件
4 特别地,请讲述单例和多例,并请结合具体例子说明在项目里的用法。
如何用比较快速的方法掌握Spring的核心——依赖注入,Java web轻量级开发面试教程 读书笔记的更多相关文章
-
java web方面的面试问题,Spring MVC方面的面试问题,摘自java web轻量级开发面试教程
本文摘自java web轻量级开发面试教程: https://baike.baidu.com/item/Java%20Web%E8%BD%BB%E9%87%8F%E7%BA%A7%E5%BC%80%E ...
-
java web轻量级开发面试教程摘录,java web面试技巧汇总,如何准备Spring MVC方面的面试
本内容摘自 java web轻量级开发面试教程 https://baike.baidu.com/item/Java%20Web%E8%BD%BB%E9%87%8F%E7%BA%A7%E5%BC%80% ...
-
JavaEE开发之Spring中的依赖注入与AOP
上篇博客我们系统的聊了<JavaEE开发之基于Eclipse的环境搭建以及Maven Web App的创建>,并在之前的博客中我们聊了依赖注入的相关东西,并且使用Objective-C的R ...
-
JavaEE开发之Spring中的依赖注入与AOP编程
上篇博客我们系统的聊了<JavaEE开发之基于Eclipse的环境搭建以及Maven Web App的创建>,并在之前的博客中我们聊了依赖注入的相关东西,并且使用Objective-C的R ...
-
Spring Framework------>;version4.3.5.RELAESE----->;Reference Documentation学习心得----->;Spring Framework的依赖注入和控制反转
Dependency Injection and Inversion of Control 1.概述: 1.1相关概念 bean:由IoC容器所管理的对象,也即各个类实例化所得对象都叫做bean 控制 ...
-
谈谈自己了解的spring.NET的依赖注入
spring.net里实现了控制反转IOC(Inversion of control),也即依赖注入DI(Dependency Injection),以达到解耦的目的,实现模块的组件化.程序 ...
-
Spring学习(三)——Spring中的依赖注入的方式
[前面的话] Spring对我太重要了,做个关于web相关的项目都要使用Spring,每次去看Spring相关的知识,总是感觉一知半解,没有很好的系统去学习一下,现在抽点时间学习一下Spring.不知 ...
-
Spring学习(一)——Spring中的依赖注入简介【转】
[前面的话] Spring对我太重要了,做个关于web相关的项目都要使用Spring,每次去看Spring相关的知识,总是感觉一知半解,没有很好的系统去学习一下,现在抽点时间学习一下Spring. ...
-
spring六种种依赖注入方式
平常的java开发中,程序员在某个类中需要依赖其它类的方法,则通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理,spring提出了依赖注入的思想,即依赖类不由程 ...
随机推荐
-
activiti和SSH项目做整合
最近因公司的业务需求,需要使用工作流来做我们业务中的流程审批工作,so 就安排我做了这个工作,发现整合的时候有一些问题,及时的记录下来分享给大家. 介绍: 一.如果你的web项目只是单纯的web项目那 ...
-
Myeclipse 60.激活
Myeclipse 用来开发java web应用是十分的方便的,不过如果没有激活的话,用起来感觉会非常不爽. 当然,个人来说还是非常支持正版的,也鼓励大家支持正版. 好了,下面介绍一下怎么破解Myec ...
-
教你用shell写CGI程序
以前用shell写过一些cgi的例子.今天向大家介绍一下. CGI是一种接口的标准,并不区分编程语言,也就是说,CGI可以用任何一种语言编写,只要这种语言具有标准输入.输出和环境变量.CGI会将标准输 ...
-
spark算子
1.map 一条一条读取 def map(): Unit ={ val list = List("张无忌", "赵敏", "周芷若") va ...
-
浏览器中的 JS 和 Node.js 中的 JS
一个是前端技术,一个是后端技术 浏览器中的 JavaScript ECMAScript 语言基础,如语法.数据类型结构.一些内置对象 BOM(Browser Object Model) 一些操作页 ...
-
如何查看当前应用包名和activity
这里提供一个简单的方法来获取package和activity: 在Android模拟器上打开微信APP,然后打开CMD,输入以下命令: adb shell 接下来在#后面继续输入以下命令: logca ...
-
前端的业余设计-about my 毕业季
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ...
-
在win10下安装eclipse
1.在官网下载jdk.目前最新版本为jdk8. http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-21331 ...
-
pip安装离线包
离线包从pypi.org下载 pip download -r requirements.txt -d /tmp/paks/ 在linux下 1.下载指定的包到指定文件夹. ...
-
FZU1759(SummerTrainingDay04-B 欧拉降幂公式)
Problem 1759 Super A^B mod C Accept: 1056 Submit: 3444Time Limit: 1000 mSec Memory Limit : 327 ...