原做地址:https://github.com/frank-lam/2019_campus_applyjavascript
在本文中将总结 Java Web 开发技术和相关框架的核心知识。因框架知识体系比较庞大,具体每一个框架的使用我将放在 ../JavaWeb
这个目录下,包含 Spring、Strust二、Hibernate、Spring Boot 等框架。html
在面试指南中将列举面试中常见的考点,包含Servlet、JSP、Spring、中间件等常考Java Web框架知识前端
参考资料:java
Servlet 是在服务器上运行的小程序。一个 servlet 就是一个 Java 类,而且能够经过 “请求—响应” 编程模式来访问的这个驻留在服务器内存里的 servlet 程序。git
类的继承关系以下:程序员
Servlet三种实现方式:github
实现javax.servlet.Servlet接口web
继承javax.servlet.http.HttpServlet类面试
一般会去继承HttpServlet类来完成Servlet。算法
Tomcat的容器分为4个等级,Servlet的容器管理Context容器,一个Context对应一个Web工程。
主要描述了从浏览器到服务器,再从服务器到浏览器的整个执行过程
浏览器向服务器请求时,服务器不会直接执行咱们的类,而是到 web.xml 里寻找路径名
① 浏览器输入访问路径后,携带了请求行,头,体
② 根据访问路径找到已注册的 servlet 名称
③ 根据映射找到对应的 servlet 名
④ 根据根据 servlet 名找到咱们全限定类名,既咱们本身写的类
① 服务器找到全限定类名后,经过反射建立对象,同时也建立了 servletConfig,里面存放了一些初始化信息(注意服务器只会建立一次 servlet 对象,因此 servletConfig 也只有一个)
① 对象建立好以后,首先要执行 init 方法,可是咱们发现咱们自定义类下没有 init 方法,因此程序会到其父类 HttpServlet 里找
② 咱们发现 HttpServlet 里也没有 init 方法,因此继续向上找,既向其父类 GenericServlet 中继续寻找,在 GenericServlet 中咱们发现了 init 方法,则执行 init 方法(对接口 Servlet 中的 init 方法进行了重写)
注意: 在 GenericServlet 中执行 public void init(ServletConfig config) 方法的时候,又调用了本身无参无方法体的 init() 方法,其目的是为了方便开发者,若是开发者在初始化的过程当中须要实现一些功能,能够重写此方法。
接着,服务器会先建立两个对象:ServletRequest 请求对象和 ServletResponse 响应对象,用来封装浏览器的请求数据和封装向浏览器的响应数据
① 接着服务器会默认在咱们写的类里寻找 service(ServletRequest req, ServletResponse res) 方法,可是 DemoServlet 中不存在,那么会到其父类中寻找
② 到父类 HttpServlet 中发现有此方法,则直接调用此方法,并将以前建立好的两个对象传入
③ 而后将传入的两个参数强转,并调用 HttpServlet 下的另外个 service 方法
④ 接着执行 service(HttpServletRequest req, HttpServletResponse resp)
方法,在此方法内部进行了判断请求方式,并执行doGet和doPost,可是doGet和doPost方法已经被咱们本身重写了,因此会执行咱们重写的方法
看到这里,你或许有疑问:为何咱们不直接重写service方法?
由于若是重写service方法的话,咱们须要将强转,以及一系列的安全保护判断从新写一遍,会存在安全隐患
void init(ServletConfig servletConfig)
:Servlet对象建立以后立刻执行的初始化方法,只执行一次;void service(ServletRequest servletRequest, ServletResponse servletResponse)
:每次处理请求都是在调用这个方法,它会被调用屡次;void destroy()
:在Servlet被销毁以前调用,负责释放 Servlet 对象占用的资源的方法;特性:
Servlet 类由本身编写,但对象由服务器来建立,并由服务器来调用相应的方法
服务器启动时 ( web.xml中配置load-on-startup=1
,默认为0 ) 或者第一次请求该 servlet 时,就会初始化一个 Servlet 对象,也就是会执行初始化方法 init(ServletConfig conf)
该 servlet 对象去处理全部客户端请求,在 service(ServletRequest req,ServletResponse res)
方法中执行
最后服务器关闭时,才会销毁这个 servlet 对象,执行 destroy() 方法。
总结(面试会问):
1)Servlet什么时候建立
默认第一次访问servlet时建立该对象(调用init()方法)
2)Servlet什么时候销毁
服务器关闭servlet就销毁了(调用destroy()方法)
3)每次访问必须执行的方法
public void service(ServletRequest arg0, ServletResponse arg1)
<servlet></servlet>
之间添加如下代码:<load-on-startup>1</load-on-startup>
其中,数字越小表示优先级越高。
例如:咱们在 web.xml 中设置 TestServlet2 的优先级为 1,而 TestServlet1 的优先级为 2,启动和关闭Tomcat:优先级高的先启动也先关闭。
客户端首次向某个Servlet发送请求
Servlet 类被修改后,Tomcat 容器会从新装载 Servlet。
本节参考:《Java程序员面试笔试宝典》P172
在设计 Web 应用程序时,常常须要把一个系统进行结构化设计,即按照模块进行划分,让不一样的 Servlet 来实现不一样的功能,例如可让其中一个 Servlet 接收用户的请求,另一个 Servlet 来处理用户的请求。为了实现这种程序的模块化,就须要保证在不一样的 Servlet 之间能够相互跳转,而 Servlet 中主要有两种实现跳转的方式:forward 与 redirect 方式。
forward 是服务器内部的重定向,服务器直接访问目标地址的 URL,把那个 URL 的响应内容读取过来,而客户端并不知道,所以在客户端浏览器的地址栏中不会显示转向后的地址,仍是原来的地址。因为在整个定向的过程当中用的是同一个 Request,所以 forward 会将 Request 的信息带到被定向的 JSP 或 Servlet 中使用。
redirect 则是客户端的重定向,是彻底的跳转,即客户端浏览器会获取到跳转后的地址,而后从新发送请求,所以浏览器中会显示跳转后的地址。同事,因为这种方式比 forward 方式多了一次网络请求,所以其效率要低于 forward 方式。须要注意的是,客户端的重定向能够经过设置特定的 HTTP 头或改写 JavaScript 脚本实现。
下图能够更好的说明两者的区别:
鉴于以上的区别,通常当 forward 方式能够知足需求时,尽量地使用 forward 方式。但在有些状况下,例如,须要跳转到下一个其余服务器上的资源,则必须使用 redirect 方式。
引伸:filter的做用是什么?主要实现什么方法?
filter 使用户能够改变一个 request 而且修改一个 response。filter 不是一个 Servlet,它不能产生一个 response,但它可以在一个 request 到达 Servlet 以前预处理 request,也能够在离开 Servlet 时处理 response。filter 实际上是一个 “Servlet Chaining” (Servler 链)。
一个 filter 的做用包括如下几个方面:
1)在 Servlet 被调用以前截获
2)在 Servlet 被调用以前检查 Servlet Request
3)根据须要修改 Request 头和 Request 数据
4)根据须要修改 Response 头和 Response 数据
5)在 Servlet 被调用以后截获
一、不一样之处在哪?
二、各自的特色
三、经过MVC双剑合璧
既然 JSP 和 Servlet 都有自身的适用环境,那么可否扬长避短,让它们发挥各自的优点呢?答案是确定的——MVC(Model-View-Controller)模式很是适合解决这一问题。
MVC模式(Model-View-Controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller):
在 JSP/Servlet 开发的软件系统中,这三个部分的描述以下所示:
MVC 模式在 Web 开发中的好处是很是明显,它规避了 JSP 与 Servlet 各自的短板,Servlet 只负责业务逻辑而不会经过 out.append() 动态生成 HTML 代码;JSP 中也不会充斥着大量的业务代码。这大大提升了代码的可读性和可维护性。
Tomcat是Web应用服务器,是一个Servlet/JSP容器。Tomcat 做为 Servlet 容器,负责处理客户请求,把请求传送给Servlet,并将Servlet的响应传送回给客户。而 Servlet 是一种运行在支持 Java 语言的服务器上的组件。Servlet最多见的用途是扩展 Java Web 服务器功能,提供很是安全的,可移植的,易于使用的CGI替代品。
从 http 协议中的请求和响应能够得知,浏览器发出的请求是一个请求文本,而浏览器接收到的也应该是一个响应文本。可是在上面这个图中,并不知道是如何转变的,只知道浏览器发送过来的请求也就是 request,咱们响应回去的就用 response。忽略了其中的细节,如今就来探究一下。
① Tomcat 将 http 请求文本接收并解析,而后封装成 HttpServletRequest 类型的 request 对象,全部的 HTTP 头数据读能够经过 request 对象调用对应的方法查询到。
② Tomcat 同时会要响应的信息封装为 HttpServletResponse 类型的 response 对象,经过设置 response 属性就能够控制要输出到浏览器的内容,而后将 response 交给 tomcat,tomcat 就会将其变成响应文本的格式发送给浏览器
Java Servlet API 是 Servlet 容器(tomcat) 和 servlet 之间的接口,它定义了 serlvet 的各类方法,还定义了 Servlet 容器传送给 Servlet 的对象类,其中最重要的就是 ServletRequest 和 ServletResponse。因此说咱们在编写 servlet 时,须要实现 Servlet 接口,按照其规范进行操做。
相似这种面试题,实际上都属于“开放性”问题,你扯到哪里均可以。不过若是我是面试官的话,我仍是但愿对方能作到一点——不要混淆 session 和 session 实现。
原本 session 是一个抽象概念,开发者为了实现中断和继续等操做,将 user agent 和 server 之间一对一的交互,抽象为“会话”,进而衍生出“会话状态”,也就是 session 的概念。
而 cookie 是一个实际存在的东西,http 协议中定义在 header 中的字段。能够认为是 session 的一种后端无状态实现。
而咱们今天常说的 “session”,是为了绕开 cookie 的各类限制,一般借助 cookie 自己和后端存储实现的,一种更高级的会话状态实现。
因此 cookie 和 session,你能够认为是同一层次的概念,也能够认为是不一样层次的概念。具体到实现,session 由于 session id 的存在,一般要借助 cookie 实现,但这并不是必要,只能说是通用性较好的一种实现方案。
引伸
因为 HTTP 协议是无状态的协议,因此服务端须要记录用户的状态时,就须要用某种机制来识具体的用户,这个机制就是 Session。典型的场景好比购物车,当你点击下单按钮时,因为 HTTP 协议无状态,因此并不知道是哪一个用户操做的,因此服务端要为特定的用户建立了特定的 Session,用用于标识这个用户,而且跟踪用户,这样才知道购物车里面有几本书。这个 Session 是保存在服务端的,有一个惟一标识。在服务端保存Session 的方法不少,内存、数据库、文件都有。集群的时候也要考虑 Session 的转移,在大型的网站,通常会有专门的 Session 服务器集群,用来保存用户会话,这个时候 Session 信息都是放在内存的,使用一些缓存服务好比 Memcached 之类的来放 Session。
思考一下服务端如何识别特定的客户?
这个时候 Cookie 就登场了。每次 HTTP 请求的时候,客户端都会发送相应的 Cookie 信息到服务端。实际上大多数的应用都是用 Cookie 来实现 Session 跟踪的,第一次建立 Session 的时候,服务端会在 HTTP 协议中告诉客户端,须要在 Cookie 里面记录一个Session ID,之后每次请求把这个会话 ID 发送到服务器,我就知道你是谁了。有人问,若是客户端的浏览器禁用了 Cookie 怎么办?通常这种状况下,会使用一种叫作URL重写的技术来进行会话跟踪,即每次 HTTP 交互,URL后面都会被附加上一个诸如 sid=xxxxx 这样的参数,服务端据此来识别用户。
Cookie 其实还能够用在一些方便用户的场景下,设想你某次登录过一个网站,下次登陆的时候不想再次输入帐号了,怎么办?这个信息能够写到 Cookie 里面,访问网站的时候,网站页面的脚本能够读取这个信息,就自动帮你把用户名给填了,可以方便一下用户。这也是 Cookie 名称的由来,给用户的一点甜头。
因此,总结一下:
作企业应用开发时,常常采用三层架构分层:表示层、业务层、持久层。表示层负责接收用户请求、转发请求、显示数据等;业务层负责组织业务逻辑;持久层负责持久化业务对象。
这三个分层,每一层都有不一样的模式,就是架构模式。表示层最经常使用的架构模式就是MVC。
所以,MVC 是三层架构中表示层最经常使用的架构模式。
MVC 是客户端的一种设计模式,因此他自然就不考虑数据如何存储的问题。做为客户端,只须要解决用户界面、交互和业务逻辑就行了。在 MVC 模式中,View 负责的是用户界面,Controller 负责交互,Model 负责业务逻辑。至于数据如何存储和读取,固然是由 Model 调用服务端的接口来完成。
在三层架构中,并无客户端/服务端的概念,因此表示层、业务层的任务其实和 MVC 没什么区别,而持久层在 MVC 里面是没有的。
各层次的关系:表现层的控制->服务层->数据持久化层。
参考资料:
能够总结为一句话:REST 是全部 Web 应用都应该遵照的架构设计指导原则。
Representational State Transfer,翻译是”表现层状态转化”。
面向资源是 REST 最明显的特征,对于同一个资源的一组不一样的操做。资源是服务器上一个可命名的抽象概念,资源是以名词为核心来组织的,首先关注的是名词。REST要求,必须经过统一的接口来对资源执行各类操做。对于每一个资源只能执行一组有限的操做。(7个HTTP方法:GET/POST/PUT/DELETE/PATCH/HEAD/OPTIONS)
符合REST架构设计的API。
以豆瓣网为例
应该尽可能将 API 部署在专用域名之下
http://api.douban.com
/v2/user/1000001?apikey=XXX
应该将 API 的版本号放入URL
http://api.douban.com/v2
/user/1000001?apikey=XXX
在 RESTful 架构中,每一个网址表明一种资源(resource),因此网址中不能有动词,只能有名词
,并且所用的名词每每与数据库的表格名对应
。通常来讲,数据库中的表都是同种记录的”集合”(collection),因此 API 中的名词也应该使用复数。
http://api.douban.com/v2/book
/:id (获取图书信息)
http://api.douban.com/v2/movie
/subject/:id (电影条目信息)
http://api.douban.com/v2/music
/:id (获取音乐信息)
http://api.douban.com/v2/event
/:id (获取同城活动)
对于资源的具体操做类型,由HTTP动词表示。经常使用的HTTP动词有下面四个(对应增/删/改/查
)。
GET(select
):从服务器取出资源(一项或多项)。
eg. 获取图书信息 GET
http://api.douban.com/v2/book/:id
POST(create
):在服务器新建一个资源。
eg. 用户收藏某本图书 POST
http://api.douban.com/v2/book/:id/collection
PUT(update
):在服务器更新资源(客户端提供改变后的完整资源)。
eg. 用户修改对某本图书的收藏 PUT
http://api.douban.com/v2/book/:id/collection
DELETE(delete
):从服务器删除资源。
eg. 用户删除某篇笔记 DELETE
http://api.douban.com/v2/book/annotation/:id
若是记录数量不少,服务器不可能都将它们返回给用户。API应该提供参数,过滤返回结果
?limit=10:指定返回记录的数量
eg. 获取图书信息 GET
http://api.douban.com/v2/book/:id?limit=10
服务器向用户返回的状态码和提示信息
每一个状态码表明不一样意思, 就像代号同样
2系 表明正常返回
4系 表明数据异常
5系 表明服务器异常
Spring的IoC容器是Spring的核心,Spring AOP是spring框架的重要组成部分
优势
个人理解
Spring AOP实现原理
动态代理(利用反射和动态编译将代理模式变成动态的)
JDK的动态代理
cglib动态代理
优势
DI(依赖注入)
IOC容器的初始化分为三个过程实现:
更详细说明请阅读:2 IOC容器初始化过程 - CSDN博客
参考资料:
AOP(Aspect Oriented Programming )称为面向切面编程,扩展功能不是修改源代码实现,在程序开发中主要用来解决一些系统层面上的问题,好比日志,事务,权限等待,Struts2的拦截器设计就是基于AOP的思想,是个比较经典的例子。
Struts2拦截器浅析-慕课网
https://www.imooc.com/learn/450
事务管理能够帮助咱们保证数据的一致性,对应企业的实际应用很重要。
Spring的事务机制包括声明式事务和编程式事务。
声明式事务管理使用了AOP面向切面编程实现的,本质就是在目标方法执行先后进行拦截。在目标方法执行前加入或建立一个事务,在执行方法执行后,根据实际状况选择提交或是回滚事务。
Spring事务管理主要包括3个接口,Spring的事务主要是由它们(PlatformTransactionManager,TransactionDefinition,TransactionStatus)三个共同完成的。
1. PlatformTransactionManager:事务管理器–主要用于平台相关事务的管理
主要有三个方法:
2. TransactionDefinition:事务定义信息–用来定义事务相关的属性,给事务管理器PlatformTransactionManager使用
这个接口有下面四个主要方法:
事务管理器可以根据这个返回值进行优化,这些事务的配置信息,均可以经过配置文件进行配置。
3. TransactionStatus:事务具体运行状态–事务管理过程当中,每一个时间点事务的状态信息。
例如它的几个方法:
声明式事务的优缺点:
http://blog.csdn.net/jie_liang/article/details/77600742
【Spring】详解Spring中Bean的加载 - weknow619 - 博客园
https://www.cnblogs.com/weknow619/p/6673667.html
在传统的Java应用中,bean的生命周期很简单。使用Java关键字new进行bean实例化,而后该bean就可使用了。一旦该bean再也不被使用,则由Java自动进行垃圾回收。
相比之下,Spring容器中的bean的生命周期就显得相对复杂多了。正确理解Spring bean的生命周期很是重要,由于你或许要利用Spring提供的扩展点来自定义bean的建立过程。下图展现了bean装载到Spring应用上下文中的一个典型的生命周期过程。
上图bean在Spring容器中从建立到销毁经历了若干阶段,每一阶段均可以针对Spring如何管理bean进行个性化定制
正如你所见,在bean准备就绪以前,bean工厂执行了若干启动步骤。咱们对上图进行详细描述:
是Spring里面最低层的接口,提供了最简单的容器的功能,只提供了实例化对象和拿对象的功能。
BeanFactory 延迟实例化的优势:
应用启动的时候占用资源不多,对资源要求较高的应用,比较有优点;
缺点:速度会相对来讲慢一些。并且有可能会出现空指针异常的错误,并且经过bean工厂建立的bean生命周期会简单一些
ApplicationContext 不延迟实例化的优势:
缺点:把费时的操做放到系统启动中完成,全部的对象均可以预加载,缺点就是消耗服务器的内存
除了提供BeanFactory所支持的全部功能外,ApplicationContext还有额外的功能
因为ApplicationContext会预先初始化全部的Singleton Bean,因而在系统建立前期会有较大的系统开销,但一旦ApplicationContext初始化完成,程序后面获取Singleton Bean实例时候将有较好的性能。
也能够为bean设置lazy-init属性为true,即Spring容器将不会预先初始化该bean。
通常拦截器都是实现HandlerInterceptor,其中有三个方法preHandle、postHandle、afterCompletion
不一样项目使用不一样分模块策略,spring配置文件分为
PS:能够借鉴Servlet的生命周期,实例化、初始init、接收请求service、销毁destroy;
Spring上下文中的Bean也相似,【Spring上下文的生命周期】
注意:以上工做完成之后就能够用这个Bean了,那这个Bean是一个single的,因此通常状况下咱们调用同一个ID的Bean会是在内容地址相同的实例
以上10步骤能够做为面试或者笔试的模板,另外这里描述的是应用Spring上下文Bean的生命周期,若是应用Spring的工厂也就是BeanFactory的话去掉第5步就Ok了;
@Resource和@Autowired都是作bean的注入时使用,其实@Resource并非Spring的注解,它的包是javax.annotation.Resource,须要导入,可是Spring支持该注解的注入。
一、共同点
二者均可以写在字段和setter方法上。二者若是都写在字段上,那么就不须要再写setter方法。
二、不一样点
(1)@Autowired
@Autowired为Spring提供的注解,须要导入包org.springframework.beans.factory.annotation.Autowired;只按照byType注入。
public class TestServiceImpl { // 下面两种@Autowired只要使用一种便可 @Autowired private UserDao userDao; // 用于字段上 @Autowired public void setUserDao(UserDao userDao) { // 用于属性的方法上 this.userDao = userDao; } }
@Autowired注解是按照类型(byType)装配依赖对象,默认状况下它要求依赖对象必须存在,若是容许null值,能够设置它的required属性为false。若是咱们想使用按照名称(byName)来装配,能够结合@Qualifier注解一块儿使用。以下:
public class TestServiceImpl { @Autowired @Qualifier("userDao") private UserDao userDao; }
(2)@Resource
@Resource默认按照ByName自动注入,由J2EE提供,须要导入包javax.annotation.Resource。@Resource有两个重要的属性:name和type,而Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。因此,若是使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。若是既不制定name也不制定type属性,这时将经过反射机制使用byName自动注入策略。
public class TestServiceImpl { // 下面两种@Resource只要使用一种便可 @Resource(name="userDao") private UserDao userDao; // 用于字段上 @Resource(name="userDao") public void setUserDao(UserDao userDao) { // 用于属性的setter方法上 this.userDao = userDao; } }
注:最好是将@Resource放在setter方法上,由于这样更符合面向对象的思想,经过set、get去操做属性,而不是直接去操做属性。
@Resource装配顺序:
若是同时指定了name和type,则从Spring上下文中找到惟一匹配的bean进行装配,找不到则抛出异常。
若是指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常。
若是既没有指定name,又没有指定type,则自动按照byName方式进行装配;若是没有匹配,则回退为一个原始类型进行匹配,若是匹配则自动装配。
@Resource的做用至关于@Autowired,只不过@Autowired按照byType自动注入。
思考:spring怎么知道应该哪些Java类当初bean类处理?
答案:使用配置文件或者注解的方式进行标识须要处理的java类!
@Component :标准一个普通的spring Bean类。
@Repository:标注一个DAO组件类。
@Service:标注一个业务逻辑组件类。
@Controller:标注一个控制器组件类。
这些都是注解在平时的开发过程当中出镜率极高,@Component、@Repository、@Service、@Controller实质上属于同一类注解,用法相同,功能相同,区别在于标识组件的类型。@Component能够代替@Repository、@Service、@Controller,由于这三个注解是被@Component标注的。以下代码
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Controller { String value() default ""; }
举例:
(1)当一个组件表明数据访问层(DAO)的时候,咱们使用@Repository进行注解,以下
@Repository public class HappyDaoImpl implements HappyDao{ private final static Logger LOGGER = LoggerFactory.getLogger(HappyDaoImpl .class); public void club(){ //do something ,like drinking and singing } }1234567
(2)当一个组件表明业务层时,咱们使用@Service进行注解,以下
@Service(value="goodClubService") //使用@Service注解不加value ,默认名称是clubService public class ClubServiceImpl implements ClubService { @Autowired private ClubDao clubDao; public void doHappy(){ //do some Happy } }12345678910
(3)当一个组件做为前端交互的控制层,使用@Controller进行注解,以下
@Controller public class HappyController { @Autowired //下面进行讲解 private ClubService clubService; // Control the people entering the Club // do something } /*Controller相关的注解下面进行详细讲解,这里简单引入@Controller*/
三、总结注意点
<!-- 自动扫描指定包及其子包下的全部Bean类 --> <context:component-scan base-package="org.springframework.*"/>
@Autowired:属于Spring 的org.springframework.beans.factory.annotation包下,可用于为类的属性、构造器、方法进行注值
@Resource:不属于spring的注解,而是来自于JSR-250位于java.annotation包下,使用该annotation为目标bean指定协做者Bean。
...
更详细请转向:Spring经常使用注解介绍【经典总结】 - CSDN博客
Spring框架中使用到了大量的设计模式,下面列举了比较有表明性的:
Spring容器就是实例化和管理Bean的工厂
工厂模式隐藏了建立类的细节,返回值一定是接口或者抽象类,而不是具体的某个对象,工厂类根据条件生成不一样的子类实例。当获得子类的实例后,就能够调用基类中的方法,没必要考虑返回的是哪个子类的实例。
这个很明显,在各类BeanFactory以及ApplicationContext建立中都用到了;
Spring经过配置文件,就能够管理全部的bean,而这些bean就是Spring工厂能产生的实例,所以,首先咱们在Spring配置文件中对两个实例进行配置。
Spring默认将全部的Bean设置成 单例模式,即对全部的相同id的Bean的请求,都将返回同一个共享的Bean实例。这样就能够大大下降Java建立对象和销毁时的系统开销。
使用Spring将Bean设置称为单例行为,则无需本身完成单例模式。
| 能够经过singleton=“true | false” 或者 scope=“?”来指定 |
在Spring的Aop中,使用的Advice(通知)来加强被代理类的功能。Spring实现这一AOP功能的原理就使用代理模式(一、JDK动态代理。二、CGLib字节码生成技术代理。)对类进行方法级别的切面加强,即,生成被代理类的代理类, 并在代理类的方法前,设置拦截器,经过执行拦截器重的内容加强了代理方法的功能,实现的面向切面编程。
Spring实现了一种可以经过额外的方法调用完成任务的设计模式 - 代理设计模式,好比JdkDynamicAopProxy和Cglib2AopProxy。
代理设计模式的一个很好的例子是org.springframework.aop.framework.ProxyFactoryBean。该工厂根据Spring bean构建AOP代理。该类实现了定义getObject()方法的FactoryBean接口。此方法用于将需求Bean的实例返回给bean factory。在这种状况下,它不是返回的实例,而是AOP代理。在执行代理对象的方法以前,能够经过调用补充方法来进一步“修饰”代理对象(其实所谓的静态代理不过是在装饰模式上加了个要不要你来干动做行为而已,而不是装饰模式什么也不作就加了件衣服,其余还得由你来全权完成)。
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,全部依赖于它的对象都获得通知并被自动更新。spring中Observer模式经常使用的地方是listener的实现。如ApplicationListener。
补充面试题:Spring里面的工厂模式和代理模式,IO中的装饰者模式,挑几个最熟的能讲讲思路和伪代码实现?
用过spring的朋友都知道spring的强大和高深,都以为深不可测,其实当你真正花些时间读一读源码就知道它的一些技术实现实际上是创建在一些最基本的技术之上而已;例如AOP(面向方面编程)的实现是创建在CGLib提供的类代理和jdk提供的接口代理,IOC(控制反转)的实现创建在工厂模式、Java反射机制和jdk的操做XML的DOM解析方式.
Spring MVC 的工做原理以下图:
组件及其做用
前端控制器 (DispatcherServlet)
接收请求,响应结果,至关于转发器,中央处理器。负责调用系统的其余模块来真正处理用户的请求。
有了DispatcherServlet减小了其余组件之间的耦合度
处理器映射器 (HandlerMapping)
做用:根据请求的 url 查找 Handler
处理器 (Handler)
注意:编写 Handler 时按照 HandlerAdapter 的要求去作,这样适配器才能够去正确执行 Handler
处理器适配器 (HandlerAdapter)
做用:按照特定规则(HandlerAdapter要求的规则)执行Handler。
视图解析器 (ViewResolver)
做用:进行视图解析,根据逻辑视图解析成真正的视图 (View)
视图 (View)
View 是一个接口实现类支持不一样的 View 类型(jsp,pdf等等)
注意:只须要程序员开发,处理器和视图。
参考资料:
参考面经: