此篇文章是应届生临时总结的Java开发面试开源框架部分:主要总结了主要的几个点,便于回答,用于有一定Java基础的同学面试所用,由于是面试问题,所以内容多有不详尽之处。
学习一个技术要明白几个点:这个技术是什么?有什么特点?怎么使用?什么时候使用?这是学一个技术的态度问题。
另外,大公司的面试官往往也很喜欢问这样的笼统问题:可以谈谈你对Spring的理解么!面对这种问题,初出茅庐的应届生往往都哑口无言,如果想要回答的体面,可以从这四个点来回答,你回答的过程中,面试官可能一直在听直到你讲完,也可能让你不用继续说了,因为他已经明白了你懂这些内容,并且善于组织这些东西,也有所准备。无论是哪一种,都能给面试官留下一个好印象。
Tomcat是什么?
(是什么)Tomcat是一个免费的开源代码的轻量级Web应用服务器;
(应用场合)一般在中小型系统和并发用户不多的场合下使用于开发和调试Jsp程序;
(使用目的)用来运行Jsp页面和Servlet来响应HTML页面请求。
Tomcat按功能划分为许多不同的组件,并可通过/conf/server.xml文件对其定义和配置,包括Server, Service, Connector,Engine, Host, Context……一般可分4个等级:
1、顶级组件:位于配置层次的顶级,并且彼此间有着严格的对应关系,有Server和Service组件;
2、连接器:连接客户端(浏览器或Web服务器)请求至Servlet容器,如Connector组件,
3、容器:功能是处理传入请求的组件,并创建相应的响应。如Engine处理对一个Service的所有请求,Host处理对特定虚拟主机的所有请求,Context处理对特定web应用的所有请求;
4、被嵌套的组件:位于一个容器当中,但不能包含其它组件;一些组件可以嵌套在任何Container中,而另一些只能嵌套在Context中。
如果把Tomcat比较一个框架类,那么一个Server服务器表示一个Tomcat实例,通常一个JVM也只包含一个Tomcat实例,一个Server中可以有多个Service服务,Service可以包含一个或多个Connector用于连接Container容器中的一个Engine,连接器Connector通过特定端口接收客户端请求,并将其转发到关联的Engine;
而Engine作为Servlet容器引擎,包含多个Host组件和其他组件,引擎接收并处理来自一个或多个连接器的请求,并辨别请求的HTTP首部信息以便确定发往哪个Context或Host(客户端通常使用主机名来标识他们希望连接的服务器),并将完成的响应返回到连接器,以便最终传输回客户端。
一个Context上下文对应一个Web应用程序,即一个Web project,而一个Web工程包含多一个Wrapper(Servlet应用程序的包装类)。也就是说,在tomcat容器等级中,Context容器直接管理Servlet在容器中的包装类Wrapper,所以Context容器如何运行将直接影响servlet的工作方式。
【可省略不看……
1 Server
Server(服务器)表示Tomcat的一个实例,因此,它必须是/conf / server.xml配置文件中的单个最外层元素,它的属性表示servlet容器的整体特性。通常一个JVM只能包含一个Tomcat实例。默认配置表示监听在8005端口以接收shutdown命令,默认仅允许通过本机访问。
2 Service
Service(服务)主要用于关联一个Engine和与此Engine相关的Connector,每个Connector通过一个特定的端口和协议接收请求,并将其转发至关联的Engine进行处理。
因此,Service可以包含一个Engine、以有一个或多个Connector;而一个Server可以包含多个Service组件,但通常情下只为一个Server指派一个Service。通常需要给Service命名,可以方便管理员在日志文件中识别不同Service产生的日志。
如默认配置中server只包含一个名为"Catalina"的service,而service里包含两个Connector,其中一个监听8080端口接收HTTP请求,另一个监听8009端口接收AJP协议的请求。
3 Connector
Connector(连接器)通过一个特定的端口接收特定协议的客户端请求,并将其转发至关联的Engine进行处理。一个Engine可以配置多个连接器,但这些连接器必须使用不同的端口。
定义连接器可以使用多种属性,有些属性也只适用于某特定的连接器类型。一般说来,连接器类型可以分为两种:Http连接器和AJP连接器。
4 Engine
Engine(引擎)表示与特定Service相关联的整个请求处理机制,即Servlet容器引擎。它接收和处理来自一个或多个连接器的所有请求,并检查每一个请求的HTTP首部信息以辨别此请求应该发往哪个Host或Context,并将完成的响应返回到连接器,以便最终传输回客户端。
一个Engine元素必须嵌套在Service元素内,它可以包含多个host组件,还可以包含Realm、Listener和Valve等子容器。
5 Host
Host(虚拟主机)类似于Apache中的虚拟主机,但在Tomcat中只支持基于FQDN的"虚拟主机"。Host位于Engine容器中用于接收请求并进行相应处理,它是服务器(例如"www.mycompany.com")的网络名称与运行Tomcat的特定服务器的关联。
客户端通常使用主机名来标识他们希望连接的服务器,但要使客户端能够使用其网络名称连接到Tomcat服务器,此名称必须在管理所属的Internet域的域名服务(DNS)服务器中注册。
6 Context组件
Context(上下文)表示在特定虚拟主机中运行的Web应用程序,一个Context对应一个Web应用程序(Web工程),而里面的Wrapper可以理解为一个Servlet程序。
Context需要根据其定义的上下文路径(path)匹配请求URI的最长前缀(除主机名外)来选择。一旦选择,可以由docBase来找到该上下文将对应的web应用程序部署目录,由目录中web.xml定义的servlet映射选择一个合适的servlet来处理传入的请求。 】
Tomcat和Jetty都是一种应用的比较广泛的Servlet引擎,但是相比较于Jetty,Tomcat更加稳定成熟,其市场霸主地位仍然难以撼动。但是两者各有优劣,现对其进行综合比较:
(1)架构方面
Jetty所有组件都是基于Handler来实现的,是一种面向Handler的架构。(Spring是一种面向Bean的架构,IBatis是一种面向Statement的架构)
从设计模式角度来看:一、Handler采用责任链设计模式:HandlerCollection可以帮助开发者构建一个链,接口类ScopeHandler可以帮助开发者控制这个链的访问顺序;二、采用了观察者设计模式,对象只要继承了LifeCycle接口就可以被Jetty管理控制整个生命周期。
Tomcat则是一种多级容器的构建模式,所有组件依附于其构建骨架;其核心就是容器设计,设计臃肿复杂,是为了更好扩展,但是将内部结构暴露给了外部使用者,学习难度变大,增加学习成本,其难度。
Jetty讲的是做某件事的规范,即告诉你应该怎么做,如果做由开发者自己实现;
Tomcat则是已经做了很多的工作,你要先理解这些工作,然后在此基础上做额外的工作。
(2)性能方面
Tomcat和Jetty的使用场景不尽相同,即对相同的使用场景,两者性能各有优劣。
Jetty可以同时处理并保持大量的连接,适合生命周期长的;按需加载组件,使用NIO技术,处理I/O请求上更具优势。例如,淘宝Web旺旺使用的就是Jetty作为Servlet引擎。
Tomcat适合处理少数频繁并且生命周期短的连接;使用BIO技术,处理静态资源时性能较差。
(3)特性方面
Jetty和Tomcat都支持标准的Servlet规范、JavaEE规范。
只不过Tomcat更加成熟,支持的更加全面而已,集成了很多这些规范的特性;整体结构复杂,修改功能缓慢,不易扩展。
而Jetty轻便灵敏(因为其开发社区更加灵活,修改更加简单),整体结构简单易用,组件可替换,功能修改较快,容易扩展。
根据自己的理解,Servlet是什么?作用?
(是什么?)Servlet是实现了Servlet接口,并通过“请求-响应”模式来访问的服务端Java程序;
(干什么的)主要用于开发动态Web资源;交互式的浏览和修改数据,动态的扩展Server的能力。
(1)接受请求,并与服务器资源进行通信;
(2)创建并返回一个基于客户端请求性质的动态内容HTML页面给客户端。
下面是一段Servlet的具体定义:
Servlet是sun公司提供的一种用于开发动态web资源的技术,其API提供了servlet接口,若用户想要开发一个动态web资源,需要:
1、编写一个实现servlet接口的Java类。
2、把开发好的Java类部署到web服务器中。
通常,按照习惯把实现了Servlet接口的java程序,称为Servlet。
Servlet依赖于Servlet容器(如常用的Tomcat和Jetty),两者类似于枪和子弹,相互依存、相互增强,但又相互独立,通过标准化接口进行协调工作。
Servlet容器独立发展,种类很多,各有定位,各有特点,比较流行的有Jetty、Tomcat等,其中以Tomcat占据市场主流。
servlet始于装入web服务器内存,并在web服务器终止或重装servlet时结束。servlet一旦被装入web服务器,一般不会从web服务器内存中删除,直至web服务器关闭或重装才会结束。
(1)初始化:web服务器启动时或web服务器接收到请求时加载Servlet。执行init();
(2)调用:运行service()方法,service()自动派遣运行与请求相对应的doGet()或doPost()方法;
(3)销毁:停止服务器时调用destroy()方法,销毁实例。
结合着生命周期说,Servlet程序是由WEB服务器调用,web服务器收到客户端的Servlet访问请求后:
(1)Web服务器接收到浏览器发送的请求之后,首先检查是否已经装载并创建了该Servlet的实例对象。
(2)如果没有Servlet实对象,装载并创建该Servlet的一个实例对象,调用Servlet实例对象的init()方法初始化。
(3)创建一个用于封装HTTP请求消息的HttpServletRequest对象和一个代表HTTP响应消息的HttpServletResponse对象,然后调用Servlet的service()方法并将请求和响应对象作为参数传递进去。
(4)WEB应用程序被停止或重新启动之前,Servlet引擎将卸载Servlet,并在卸载之前调用Servlet的destroy()方法。
IE浏览器:http://localhost:8080/Demo/function.do 这个过程都经历了什么?
(1)连接上web服务器
(2)发送http请求
GET/FirstServlet/first.do HTTP/1.1
Accept: image/gif,image/jpeg, image/pjpeg, image/pjpeg, application/xaml+xml,application/x-ms-xbap, application/x- ms-application,application/vnd.ms-xpsdocument, */*
Accept-Language:zh-cn,en-US;q=0.7,ar-OM;q=0.3
User-Agent:Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET4.0C;.NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)
Accept-Encoding:gzip, deflate
Host:localhost:8080
Connection:Keep-Alive
web服务器(Tomcat)
(3)解析出想访问的主机名
(4)解析出想访问的web应用
(5)解析出想访问的web资源
FirstServlet.java
(6)第一次则创建servlet实例对象
(7)第一次的话,则调用servlet的init方法完成对象初始化
(8)创建代表请求request和代表响应的response对象,然后调用servlet的service方法响应客户端的请求
(9)service方法执行,向代表客户端响应的response对象写入了要输出的数据
(10)服务器从response中取出数据,构建出一个http响应,回写给客户机
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Length: 14
Date: Sat, 24 Dec 2011 04:00:55 GMT
hello servlet!
(11)浏览器解析http响应,提取数据显示
(12)WEB应用程序被停止或重新启动之前,Servlet引擎将卸载Servlet,并在卸载之前调用Servlet的destroy()方法。
1)实现 SingleThreadModel接口;(不一定安全)
针对Service()方法
2)使用Syncronized关键字实现数据共享;
3)避免使用实例变量;
Web容器在启动的时候为每个应用创建一个ServletContext对象,ServletConfig对象中维护了ServletContext的引用,开发人员在编写servlet时,可以通过ServletConfig.getServletContext方法获取到ServletContext对象。由于一个web应用中的所有servlet共享一个ServletContext对象,因此servlet对象之间可以通过ServletContext对象来实现通讯。ServletContext对象也通常被称为Context域对象。
1.多个servlet通过ServletContext对象实现数据共享。Initservlet的Service方法中利用ServletContext对象存入需要共享的数据
ServletContext context=this.getServletContext();
Context.setAttribute(“name”,“Lucy”);
在其他的servlet中利用ServletContext对象获取共享数据
ServletContext context =this.getServletContext();
String name =context.getAttribute(“name”);
2.获取web应用的初始化参数。在DemoServlet的doPost方法中获取初始化参数的步骤如下:
ServletContextcontext=this.getServlenContext();
String url=context.getInitParmeter(“url”);
1:用户通过浏览器向服务器发送一个请求url: http://hostname:port/contextpath/servletpath; 其中,hostname和port用来与服务器简历TCP连接,contextpaht和servletpath路径用于选择服务器中对应子容器服务请求。
2:如何选择子容器?使用org.apache.tomcat.util.http.mapper这个映射类保存Container容器中所有子容器信息, org.apache.tomcat.catalina.connector.Request请求类进入Container容器之前,Mapper类就根据hostname和contextpath在mappingData属性中保存了host和Container容器之间的关系,可以根据这个映射关系选择子容器。
3:Mapper类又如何保存这个映射关系呢?使用类似于观察者模式的方法,将MapperListener作为一个监听者加入Container容器的每个子容器,一旦容器发生变化,保存容器关系的MapperListener类的mapper属性也会修改更新。
public class SecondServlet extends HttpServlet {
@Override
public void init() throws ServletException {
System.out.println("这是init()方法..."); }
@Override
Public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("这是doGet()方法..."); // 设置内容类型
resp.setContentType("text/html");
PrintWriter out = resp.getWriter();
out.println("Hello World Sample ");
out.println("Hello World Title" +new Date().toLocaleString() + "
");
out.flush();
}
@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("这是doPost()方法...");
}
Public void service(){};
@Override
public void destroy() {
System.out.println("这是destroy()方法...");
}
}
除了Servlet的书写,还有Servlet配置:
对于一个web应用程序来说,过滤器是处于web容器内的一个组件,它会过滤特定请求资源请求信息和响应信息。一个请求来到时,web容器会判断是否有过滤器与该信息资源相关联,如果有则交给过滤器处理,然后再交给目标资源,响应的时候则以相反的顺序交给过滤器处理,最后再返回给用户浏览器。
过滤器类需要实现javax.servlet.Filter,该接口的doFilter()方法是业务处理的核心代码区,类似于servlet的service()方法。doFilter()方法的参数列表有一个FilterChain接口的实现对象,它只有一个方法doFilter(),在调用该方法之前的代码会在达到目标资源前执行,之后的代码会在目标资源已经响应后执行。
工作原理:
当客户端发出Web资源的请求时,Web服务器根据应用程序配置文件设置的过滤规则进行检查,若客户请求满足过滤规则,则对客户请求/响应进行拦截,对请求头和请求数据进行检查或改动,并依次通过过滤器链,最后把请求/响应交给请求的Web资源处理。请求信息在过滤器链中可以被修改,也可以根据条件让请求不发往资源处理器,并直接向客户机发回一个响应。当资源处理器完成了对资源的处理后,响应信息将逐级逆向返回。同样在这个过程中,用户可以修改响应信息,从而完成一定的任务。
两个过滤器同时过滤一个请求时,就要用到过滤链FilterChain.Filter的FilterChain中,服务器会按照web.xml中过滤器定义的先后循序组装成一条链,然后一次执行其中的doFilter()方法。执行的顺序就如下图所示,执行第一个过滤器的chain.doFilter()之前的代码,第二个过滤器的chain.doFilter()之前的代码,请求的资源,第二个过滤器的chain.doFilter()之后的代码,第一个过滤器的chain.doFilter()之后的代码,最后返回响应。
public class EncodingFilterTest implementsFilter {
public void destroy(){ // TODO Auto-generated method stub }
public void doFilter(ServletRequestrequest,ServletResponse response,FilterChain chain) throws IOException, //三个参数比较重要
ServletException {
System.out.println("encodingFilterdoFilter-----");
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
chain.doFilter(request,response);
}
public void init(FilterConfigarg0) throws ServletException { System.out.println("过滤器初始化"); }
}
配置:
1、应用程序:是能完成我们所需要功能的成品,比如购物网站、OA系统。
2、框架:是能完成一定功能的半成品,比如我们可以使用框架进行购物网站开发;框架做一部分功能,我们自己做一部分功能,这样应用程序就创建出来了。而且框架规定了你在开发应用程序时的整体架构,提供了一些基础功能,还规定了类和对象的如何创建、如何协作等,从而简化我们开发,让我们专注于业务逻辑开发。
3、非侵入式设计:从框架角度可以这样理解,无需继承框架提供的类,这种设计就可以看作是非侵入式设计,如果继承了这些框架类,就是侵入设计,如果以后想更换框架之前写过的代码几乎无法重用,如果非侵入式设计则之前写过的代码仍然可以继续使用。
4、轻量级及重量级:轻量级是相对于重量级而言的,轻量级一般就是非入侵性的、所依赖的东西非常少、资源占用非常少、部署简单等等,其实就是比较容易使用,而重量级正好相反。
5、POJO:POJO(Plain Old Java Objects)简单的Java对象,它可以包含业务逻辑或持久化逻辑,但不担当任何特殊角色且不继承或不实现任何其它Java框架的类或接口。
6、容器:在日常生活中容器就是一种盛放东西的器具,从程序设计角度看就是装对象的的对象,因为存在放入、拿出等操作,所以容器还要管理对象的生命周期。
7、控制反转:即Inversion of Control,缩写为IoC,控制反转还有一个名字叫做依赖注入(DependencyInjection),就是由容器控制程序之间的关系,而非传统实现中,由程序代码直接操控。
8、Bean:一般指容器管理对象,在Spring中指Spring IoC容器管理对象。
Spring是什么?
Spring是一个开源的轻量级Java SE(Java 标准版本)/Java EE(Java 企业版本)开发应用框架,其目的是用于简化企业级应用程序开发。
干什么的,优点?
(1)通过配置方式来创建对象,并自动管理对象之间依赖关系(IOC控制反转); 【轻量级容器】
(比起传统方式避免了源码修改,重新编译和部署,减少工作,加速开发,节省时间)
(2)除此之外,还提供像通用日志记录、性能统计、安全控制、异常处理等面向切面的能力;将这些常用功能从业务逻辑中分离出来,通过面向切面编程,在需要这些功能的地方动态添加这些功能,无需渗透到各个需要的方法或对象中;【AOP面向切面】
(相比较于传统代码使用对象调用或代理等,这种面向切面的能力避免了代码重复,实现了零耦合)
(3)还能繁琐的数据库事务;Spring本身提供了一套简单的JDBC访问实现;【简单的数据库事务管理】
(相比于传统代码管理事务的“获取连接,执行SQL,提交或回滚事务,关闭连接”一系列繁琐操作,使用Spring,我们只需获取连接并执行SQL,其他的一切都交给Spring管理)
(4)Spring还提供与第三方数据访问框架(如Hibernate、JPA)无缝集成的能力;提供JDBC访问模板。【JDBC抽象及ORM框架支持】
(5)与各种Java EE技术整合(如JavaMail、任务调度等等),提供一套自己的web层框架SpringMVC、而且还能非常简单的与第三方web框架集成;
从图中可以看出,Spring的核心组件为:Core、Context、Beans,他们三个构成Spring的基础骨架,其他功能组件的使用都依赖于这三个核心组件,其实Spring可以看做是一个面向Bean的编程。
参考链接:
http://blog.csdn.net/lp1052843207/article/details/51253071
https://www.ibm.com/developerworks/cn/java/j-lo-spring-principle/
Spring在IOC容器中根据配置文件来管理对象之间的依赖关系,即依赖注入机制。
把Bean比作演员,Context就是演出的舞台背景,Core相当于演出的道具;Bean包装了Object,Context则给这些Bean提供生存环境,并利用Core工具(类似于Utils)发现每个Bean之间的关系,并建立和维护这种关系;所以,可以说Context是一个Bean关系的集合,又叫IOC容器。
Bean组件:
在org.springframework.beans包下,主要用来解决:Bean的定义、Bean的创建、Bean的解析。
Bean的创建使用了工厂模式,顶级接口是BeanFactory,BeanFactory有三个子类:ListableBeanFactory(可列表)、 HierarchicalBeanFactory(有继承关系)、AutowirecapableBeanFactory(自动装配),三者各有自己的使用场合,在Spring内部对象传递和转化过程中,对对象数据访问进行限制。
Bean的定义主要由BeanDefinition描述,完整的描述了在Spring的配置文件中定义的
Bean的解析主要是对Spring配置文件的解析,依赖于LoadBeanDefinition。
Context组件:
在org.springframework.context包下,给Spring提供一个运行时环境,用以保存各对象状态。
ApplicationContext是Context的顶级父类,它继承了BeanFactory和ResourceLoader(使得Spring可以 访问外部资源),前者用于运行主体对象Bean,后者用于访问任何外部资源。
ApplicationContext派发的两个子类:ConfigurableApplicationContext和WebApplicationContext前者用于用户动态的修改或添加配置信息,后者用于为Web准备的Context,可直接访问ServletContext;
总体来讲ApplicationContext主要完成了:
标识一个应用环境;利用BeanFactory创建Bean对象;保存对象关系表;捕捉各种事件。
Core组件:
包含了很多关键类,比较重要的是定义了资源的访问方式。把所有资源都抽象成一个接口用于访问。
Resource接口封装了资源类型,屏蔽了文件类型的不同。
Resource接口的父接口InputStreamSource接口,可利用getInputInstream()直接得到资源InputStream类,屏蔽了资源提供者。
Resource派发的子接口ResourceSourceLoader接口,可屏蔽所有资源加载者的差异。
1 何为控制反转?
控制反转:即Inversionof Control,缩写为IOC;依赖注入(DependencyInjection)可以认为是IOC的实现。
将控制权交给IOC容器来掌管,通过控制对象之间的关系来管理程序,而非像传统实现中,由程序代码直接操控。
2 为什么把这种方式叫做控制反转?
如果对象存在组合关系,传统的代码程序中,对象之间相互依赖,需要用的时候,自己必须主动创建对象或者使用已经创建好的对象;控制权都在我们自己手上;
但是,如果软件系统引入了Ioc容器之后,对象之间失去了直接联系,一个对象实例化或运行时,如果需要用到另外的对象,IoC容器会主动创建这个对象并注入到使用的对象中,这种控制权的主动行为变成被动行为,控制转发生转移,我们把它叫做控制反转。控制反转带来的一个直观的好处就是低耦合,组件之间相互独立。
3 IOC如何实现控制反转或控制反转原理?
【主要利用 工厂模式+反射技术】
IOC中最基本的技术就是“反射(Reflection)”编程:Spring在配置文件中给出了要生成对象的定义,利用反射技术根据配置文件给出的类名(字符串方式)来动态地生成对象,这种编程方式可以让对象在生成时才决定到底是哪一种对象;目的就是提高灵活性和可维护性。
或
IOC容器的工作模式可以看做是一个工厂模式,IOC容器就像一个工厂,这个工厂要生成的对象都在配置文件中已经给出定义,然后利用编程语言的的反射技术 ,根据配置文件中给出的类名生成相应的对象;在实现上,IOC是把以前在工厂方法里写死的对象生成代码,改变为由配置文件来定义,实现了工厂和对象生成的分离,目的就是提高灵活性和可维护性。
【具体请看设计模式之工厂模式和反射技术】
4 IOC容器如何工作:
IOC实际是Context利用Core构建的一个Bean关系网。构建的入口在AbstractApplicationContext类的refresh方法中,功能有:1.构建BeanFactory,便于生产bean;2.注册可能感兴趣的事件;3.创建Bean实例对象;4.触发被监听的事件。
LoadBeanDefinition(beanFactory)完成加载、解析Bean的定义,把用户的数据转换成 Ioc中的BeanDefinition结构。
Bean的生命周期:
1.Bean的建立:由BeanFactory读取Bean定义文件配置文件,并生成各个实例
2.Setter注入:执行Bean的属性依赖注入
3.BeanNameAwaer的SetBeanName:如果Bean实现了该接口,就执行该方法
BeanFactoryAware的setBeanFactory:如果Bean实现了该接口,则执行方法。
4.Bean定义文件中定义的init-method属性用于设置方法名称,初始化时会执行init-method方法,无参。
DisposableBean的destroy() 在容器关闭时,执行实现类Bean的destroy()方法。
5.Bean文件中定义的destory-method,在容器关闭的时候使用dstory-method方法,不带参数。
总结:
Bean的完整生命周期从 spring 容器开始实例化bean 开始,到销毁。可以从三点来理解
1、 bean自身的方法:包括构造方法、set 方法、 init-method 指定的方法、destroy-method 指定的方法
2、 Bean级生命周期接口方法:如 BeanNameAware 、 BeanFactoryAware 等这些接口方法由 bean类实现。
3、 容器级生命周期接口方法:上图中带星的。有InstantiationAwareBeanPostProcessor 、 BeanPostProcessor 等。一般称为后处理 器。他们一般不由bean 本身实现,独立存在,注册到spring 容器中。Spring 通过接口反射预先知道,当spring 容器创建任何bean 时,这些后处理器都会发生作用。所以他们是全局的,用户可以通过编码对只感兴趣的bean 进行处理。
5 使用IOC的好处、优势?
(1)【测试调试】可维护性比较好,非常便于进行单元测试,便于调试程序和诊断故障。代码中的每一个Class都可以单独测试,彼此之间互不影响,只要保证自身的功能无误即可,这就是组件之间低耦合或者无耦合带来的好处。
(2)【分工明确】IOC可使任务独立,各自进行单元测试,每个团队只需要关注自己的业务逻辑即可,分工明确,责任明晰,提高效率。
(3)【组件复用】IoC独立了组件单元,使得组件可复用性好,可把具有普遍性的常用组件独立出来,反复应用;
(4)【修改维护】IoC把对象的生成放在配置文件里进行定义,更换实现子类时更加简单,只要修改配置文件即可,完全具有热插拨特性。
6 使用IOC容器应该注意的地方?
(1)软件系统中由于引入了第三方IOC容器,生成对象的步骤变得有些复杂。不太直观。
(2)由于IOC容器生成对象是通过反射方式,在运行效率上有一定的损耗。
(3)需要进行大量的配制工作,比较繁琐,对小项目而言可能加大一些工作成本。
(4)IOC框架产品本身的成熟度需要进行评估,存在隐性风险。
3.4.1 Spring AOP是什么,用来干什么的?
AOP是一种面向切面的编程技术,主要用来通过预编译方式和运行期动态代理实现程序功能的统一维护的技术。
AOP是对OOP的补充和完善。OOP引入了封装、继承、多态等概念来建立一种对象层次结构,用于开发者定义一种纵向关系,但并不适合定义横向的关系。例如日志功能,日志代码往往横向地散布在各个层次中,但是却对该层对应的对象没有什么关系。在OOP中,这种散布在各处的无关代码横切(cross cutting)了对应层次对象,但是却导致了代码重复,不利于模块复用。
AOP则是利用"横切"技术,剖解开封装的对象,抽取出那些散落在各个层次中但和纵向业务无关的重复调用的功能,并将其封装为一个可重用模块,并将其命名为"Aspect",即切面。降低了模块之间的耦合度,并有利于未来的可操作性和可维护性。
AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事物。
AOP的作用就在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。
3.4.2 AOP核心概念
1、横切关注点
对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点
2、切面(aspect)
类是对物体特征的抽象,切面就是对横切关注点的抽象
3、连接点(joinpoint)
被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器
4、切入点(pointcut)
对连接点进行拦截的定义
5、通知(advice)
所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类
6、目标对象
代理的目标对象
7、织入(weave)
将切面应用到目标对象并导致代理对象创建的过程
8、引入(introduction)
在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段
3.4.3 Spring AOP如何实现?
Spring中AOP代理由Spring的IOC容器负责生成、管理,其依赖关系也由IOC容器负责管理。因此,AOP代理可以直接使用容器中的其它bean实例作为目标,这种关系可由IOC容器的依赖注入提供;
第一、SPring AOP默认使用Java动态代理,加载一个动态代理类来代理接口并实现一些自定义操作。
1、SPringAOP 利用JDK环境下java.lang.reflect包下的Proxy类来构造代理类。
2、具体创建:调用Proxy类下的static Object newProxyInstance(ClassLoader loader,Class>[] interfaces,InvocationHandler h)方法创建代理对象;
参数1 ClassLoader --用于加载代理类的Loader类;
参数2 Interfaces--被代理接口;
参数3 InvocationHandler --用于执行除了代理接口中定义的方法外的其他的自定义操作,这些操作都定义在该类的invoke()方法
3、newProxyInstance(ClassLoaderloader,Class>[] interfaces,InvocationHandler h)主要业务代码:
Class c1=getProxyClass(loader,interfaces); //1:构造代理类名
Constructorcons=c1.getConstructor(constructorParams);// 2创建构造函数类
return(Object)cons.newInstance(new Object[] {h}); //创建代理对象(参数传入)
意思就是:
1:调用getProxyClass方法把加载类和被代理接口作为参数传入来构建代理类名;
2:调用代理类名的getConstructor创建构造函数类。
3:利用构造函数类的newInstance()方法,并传入实现了自定义操作的类对象h,创建Spring AOP的代理类。(会自动将方法对应属性参数传给invoke()方法的Method参数并执行)
第二、当需要代理的类不是代理接口的时候,Spring会切换为使用CGLIB代理,也可强制使用CGLIB
AOP编程其实是很简单的事情,纵观AOP编程,程序员只需要参与三个部分:
1:定义普通业务组件
2:定义切入点,一个切入点可能横切多个业务组件
3:定义增强处理,增强处理就是在AOP框架为普通业务组件织入的处理动作
所以进行AOP编程的关键就是定义切入点和定义增强处理,一旦定义了合适的切入点和增强处理,AOP框架将自动生成AOP代理,即:代理对象的方法=增强处理+被代理对象的方法。
普通业务实现类
普通业务实现类
增强处理
定义切入点
如果一个切入点要执行多个方法,可以通过order属性定义横切关注点的顺序。
3.4.4 动态代理
在程序运行时,运用反射机制动态创建而成。
动态代理的作用:
主要用来做方法的增强,让你可以在不修改源码的情况下,增强一些方法,在方法执行前后做任何你想做的事情(甚至根本不去执行这个方法),因为在InvocationHandler的invoke这个方法中,你可以直接获取正在调用方法对应的Method对象,具体应用,比如,添加日志,做事物控制等。
是什么?
提供了一个经典架构MVC(Model-View-Controller),使程序分层,既相互独立,又协同工作。
View视图层:为用户提供UI,重点关注数据的呈现,负责布局问题;
Model模型层:业务数据的信息标识,关注支撑业务的信息构成,通常是多个业务实体的组合;负责需要将什么信息展示给用户。
Controller控制层:通过调用业务逻辑产生合适的数据Model,传递数据给视图层用于呈现,负责调用哪些业务逻辑。
干什么的?
MVC的本质,及其核心思想就是业务数据抽取同业务数据呈现相分离。
Spring MVC框架,主要利用中央控制器DispatcherServlet完成客户端发送的请求。
SpringMVC的工作原理:
1、客户端发出一个http请求给web服务器,web服务器对http请求进行解析,如果匹配DispatcherServlet的请求映射路径(在web.xml中指定),web容器将请求转交给DispatcherServlet.
2、DipatcherServlet接收到这个请求之后将根据请求的信息(包括URL、Http方法、请求报文头和请求参数Cookie等)以及HandlerMapping的配置找到处理请求的处理器(Handler)。
3-4、DispatcherServlet根据HandlerMapping找到对应的Handler,将处理权交给Handler(Handler将具体的处理进行封装),再由具体的HandlerAdapter对Handler进行具体的调用。
5、Handler对数据处理完成以后将返回一个ModelAndView()对象给DispatcherServlet,为页面呈现做准备。
6、Handler返回的ModelAndView()只是一个逻辑视图并不是一个正式的视图,DispatcherSevlet通过ViewResolver将逻辑视图转化为真正的视图View。
7、Dispatcher通过model解析出ModelAndView()中的参数进行解析最终展现出完整的view并返回给客户端。
写一个Spring MVC框架的Controller类:
@Controller @RequestMapping ( "/test" ) public class MyController { @Autowaired private DAO dao; @RequestMapping ( "/showView" ) public ModelAndView showView() { ModelAndView modelAndView = new ModelAndView(); modelAndView.setViewName( "viewName" ); modelAndView.addObject( " 需要放到 model 中的属性名称 " , " 对应的属性值,它是一个对象 " ); return modelAndView; } @RequestMapping ( "/func" ) public void func(@RequestParam(value="id") int id) { //operation…… } }
有几个地方需要注意:@Controller @Autowaired @RequestMapping ( "/showView" ) @RequestParam 等这些注解、路径格式、路参绑定等都需要写出来。
有的面试官会让写现场撸代码,不过他们会让你写经典常用的代码,比如写一个Servlet,写一个Controller,写一个Singleton单例,笔者就曾经遇到了类似的题目。
Struts2框架是一个轻量级的MVC流程框架,轻量级是指程序的代码不是很多,运行的时候占用的资源不是很多,MVC流程框架就是说它支持分层开发,控制数据的流程。
升级的改善:
Struts1的缺点:
1.struts框架基于servlet进行开发的,所以servlet的问题在这个框中都能体现出来
2.struts框架的流程是固定的,想要扩展业务流程非常的不方便。
3.只支持动态视图JSP展现数据,对于现在的SEO(搜索引擎优化)支持不好
Struts2框架改善的地方:
1.核心基于Filter
2.流程可以动态扩展
3.多例创建对象
4.支持多种视图展现技术(JSP,Freemarker,Volicity)
1. 机制:spring mvc的入口是servlet,而struts2是filter,这样就导致了二者的机制不同。
2. 性能:
spring会稍微比struts快。spring mvc是基于方法的设计,而sturts是基于类,每次发一次请求都会实例一个action,每个action都会被注入属性,而spring基于方法,粒度更细,但要小心把握像在servlet控制数据一样。spring3mvc是方法级别的拦截,拦截到方法后根据参数上的注解,把request数据注入进去,在spring3 mvc中,一个方法对应一个request上下文。而struts2框架是类级别的拦截,每次来了请求就创建一个Action,然后调用setter getter方法把request中的数据注入;struts2实际上是通 setter getter方法与request打交道的;struts2中,一个Action对象对应一个request上下文。
3. 参数传递:struts是在接受参数的时候,可以用属性来接受参数,这就说明参数是让多个方法共享的。
4. 设计思想上:struts更加符合oop(面向对象编程)的编程思想, spring就比较谨慎,在servlet上扩展。
5. intercepter的实现机制:
struts有自己的interceptor机制,spring mvc用的是独立的AOP方式。这样导致struts的配置文件量还是比spring mvc大,虽然struts的配置能继承,所以我觉得论使用上来讲,spring mvc使用更加简洁,开发效率SpringMVC确实比struts2高。spring mvc是方法级别的拦截,一个方法对应一个request上下文,而方法同时又跟一个url对应,所以说从架构本身上spring3 mvc就容易实现restful url。struts2是类级别的拦截,一个类对应一个request上下文;实现restful url要费劲,因为struts2action的一个方法可以对应一个url;而其类属性却被所有方法共享,这也就无法用注解或其他方式标识其所属方法了。spring3 mvc的方法之间基本上独立的,独享requestresponse数据,请求数据通过参数获取,处理结果通过ModelMap交回给框架方法之间不共享变量,而struts2搞的就比较乱,虽然方法之间也是独立的,但其所有Action变量是共享的,这不会影响程序运行,却给我们编码,读程序时带来麻烦。
另外,spring3 mvc的验证也是一个亮点,支持JSR303,处理ajax的请求更是方便,只需一个注解@ResponseBody,然后直接返回响应文本即可。
是什么,干什么用的?
mybatis是一个优秀的基于java的持久层框架,它内部封装了jdbc,使开发者只需关注sql本身,而不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。
mybatis通过xml或注解的方式将要执行的各种statement配置起来,并通过java对象和statement中sql的动态参数进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射为java对象并返回,消除了几乎所有的JDBC代码、参数的手工设置、结果集的检索。
主要用来通过XML配置或注解提供一种Java Bean和数据库记录的ORM映射。
什么是hibernate?
hibernate是数据访问层的框架,对jdbc进行了封装,可以直接访问对象,hibernate自动将此访问转换为sql执行,从而达到间接访问数据库的目的,简化了数据访问层的代码开发。
hibernate和mybatis对比:
共性:采用ORM思想解决了实体和数据库映射的问题,对jdbc进行了封装,屏蔽了jdbc api底层访问细节,使我们不用与jdbc api打交道,就可以完成对数据库的持久化操作。
Hibernate是全自动化ORM的映射工具,Mybatis实现业务代码和SQL的分离采用了面向接口编程的技术,是一种半自动化的映射工具,接口中定义的方法(方法返回类型,方法名,方法参数)对应了配置文件dao.xml中对应的SQL执行返回类型、SQL配置名称、传输参数。
1.sql语句与代码分离,存放于Dao.xml配置文件中;
优点:便于维护管理,不用在java代码中找这些语句;
缺点: JDBC方式可以用用打断点的方式调试,但是Mybatis不能,需要通过log4j日志输出日志信息帮助调试,然后在配置文件中修改。
2.用逻辑标签控制动态SQL的拼接
优点:用标签代替编写逻辑代码;
缺点:拼接复杂SQL语句时没有代码灵活,拼写比较复杂。不要使用变通手段来应对这种复杂的语句。
3.查询的结果集与java对象自动映射
优点:保证名称相同,配置好映射关系即可自动映射或者,不配置映射关系,通过配置列名=字段名也可完成自动映射。
缺点:对开发人员所写的SQL依赖很强。
4.编写原声SQL
优点:接近JDBC,比较灵活。
缺点:对SQL语句依赖程度很高;并且属于半自动,数据库移植比较麻烦,比如mysql数据库编程Oracle数据库,部分的sql语句需要调整。
两者相同点
Hibernate与MyBatis都可以是通过SessionFactoryBuider由XML配置文件生成SessionFactory,然后由SessionFactory 生成Session,最后由Session来开启执行事务和SQL语句。其中SessionFactoryBuider,SessionFactory,Session的生命周期都是差不多的。
Hibernate和MyBatis都支持JDBC和JTA事务处理。
Mybatis优势
MyBatis可以进行更为细致的SQL优化,可以减少查询字段。
MyBatis容易掌握,而Hibernate门槛较高。
Hibernate优势
Hibernate的DAO层开发比MyBatis简单,Mybatis需要维护SQL和结果映射。
Hibernate对对象的维护和缓存要比MyBatis好,对增删改查的对象的维护要方便。
Hibernate数据库移植性很好,MyBatis的数据库移植性不好,不同的数据库需要写不同SQL。
Hibernate有更好的二级缓存机制,可以使用第三方缓存。MyBatis本身提供的缓存机制不佳。
他人总结
Hibernate功能强大,数据库无关性好,O/R映射能力强,如果你对Hibernate相当精通,而且对Hibernate进行了适当的封装,那么你的项目整个持久层代码会相当简单,需要写的代码很少,开发速度很快,非常爽。
Hibernate的缺点就是学习门槛不低,要精通门槛更高,而且怎么设计O/R映射,在性能和对象模型之间如何权衡取得平衡,以及怎样用好Hibernate方面需要你的经验和能力都很强才行。
iBATIS入门简单,即学即用,提供了数据库查询的自动对象绑定功能,而且延续了很好的SQL使用经验,对于没有那么高的对象模型要求的项目来说,相当完美。
iBATIS的缺点就是框架还是比较简陋,功能尚有缺失,虽然简化了数据绑定代码,但是整个底层数据库查询实际还是要自己写的,工作量也比较大,而且不太容易适应快速数据库修改。