java学习笔记

来源:互联网 发布:多粒度大数据 编辑:程序博客网 时间:2024/06/01 15:28

1.相同对象的hashcode一定相同,但相同的hashcode不一定是相同的对象。
2.深复制和浅复制
浅复制:被复制对象的所有变量都含有与原来对象相同的值,而所有的对其他对象的引用任然指向原来的对象,浅复制仅仅考虑复制的对象,不复制它所引用的对象。
深复制:被复制对象的所有变量都含有与原来对象相同的值,除去那些引用其他对象的变量,那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象,深复制把复制的对象所引用的对象都复制了一遍。
3.什么是servlet?
servlet是用来处理客户端请求并产生动态网页内容的java类,servlet主要是用来处理 或者是存储HTML表单提交的数据,产生动态内容,在无状态的HTTP协议下管理状态信息
4.说一下servlet的体系结构
所有的servlet都必须要实现的核心接口是 javax.servlect.Servlect,每一个Servlect都必须直接或间接的实现这个接口,或者是继承javax.servlet.GenericServlet,Servlect使用多线程可以并行为多个请求服务。
5.Servlect的生命周期
对每一个客户端的请求,Servlect引擎载入Servlect,调用它的init方法,完成Servlect的初始化,然后Servlect对象通过为每一个请求单独调用service方法来处理所有随后来自客户端的请求,最后调用Servlect的destroy方法把servlect删除掉。
6.doGet和doPost方法的区别
doGet:GET方法把名值对追加在请求的URL后面,因为URL对字符数目有限制,进而限制了用客户端请求的参数值的数目,并且请求中的参数值是可见的,因此,敏感信息不能使用这种方式传递。
doPost:POST方法通过把请求参数值放在请求体中来克服GET方法的限制,因此,可以发送参数的数目是没有限制的,最后通过POST请求传递的敏感信息对外部客户端是不可见的。
7.jdk和jre的区别
java运行时环境(jre)是将要执行java程序的java虚拟机,它同时也包含了执行applet需要的浏览器插件,java考法工具包(jdk)是完整的java软件开发包,包含了jre,编译器和其他工具(比如:javadoc,java调试器),可以让开发者开发,编译,执行java程序。
8.是否可以在static环境中访问非static变量
static变量在java中是属于类的,它在所有的实例中的值是一样的。当类被java虚拟机载入的时候会对static变量进行初始化,如果你的代码尝试不用实例来访问非static的变量,编译器会报错,因为这些变量还没有被创建出来,还没有跟任何实例关联上。
9.java中的方法覆盖和方法重载是什么意思
java中的方法重载发生在同一个类里面两个或是多个方法的方法名相同但是参数不同的情况。与此相对,方法覆盖是说类重新定义了父类的方法。方法覆盖必须有相同的方法名,参数列表和返回类型。覆盖者可能不会限制他/她所覆盖的方法的访问。
10.java中,什么是构造函数,什么是构造函数重载,什么是复制构造函数
当新对象被创建的时候,构造函数会被调用。每一个类都有构造函数,在程序员没有给类提供构造函数的情况下,java编译器会为这个类创建一个默认的构造函数。
11.什么是值传递和引用传递?
对象被值传递,意味着传递了对象的一个副本。因此,就算是改变了对象的副本,也不会影响原对象的值。对象被引用传递,意味着传递的并不是实际的对象,而是对象的引用。因此外部对引用对象的改变会反映到全部的对象上。
12.线程的几种可用状态
就绪
运行中
等待中
睡眠中
i/o阻塞
同步阻塞
死亡
13.同步方法和同步代码块的区别是什么?
在java语言中,每一个对象有一把锁。线程可以使用synchronized关键字来获取对象上的锁,synchronized关键字可应用在方法级别(粗粒度锁)或者是代码块级别(细粒度锁)。
14.在监视器(Monitor)内部,是如何做线程同步的?程序应该做哪种级别的同步?
监视器和锁在java虚拟机中是一块使用的。监视器监视一块同步代码块,确保一次只有一个线程执行同步代码块。每一个监视器都和一个对象引用相关联。线程在获取锁之前不允许使用同步代码块。
15.什么是死锁?
两个进程都在等待对方执行完毕才能继续往下执行的时候就发生了死锁,结果就是两个进程都陷入了无限等待中。
16.如何确保N个线程可以访问N个资源同事又不导致死锁?
使用多线程时,一种非常简单的避免死锁的方式就是:指定获取锁的顺序,并强制线程按照指定的顺序获取锁。因此,如果所有的线程都是以同样的顺序加锁和释放。就不会出现死锁了。
17.java集合类框架的基本接口有哪些?
java集合类提供了一套设计良好的支持对一组对象进行操作的接口和类,java集合类里面最基本的接口有:
Collection:代表一组对象,每一个对象都是它的子元素
Set:不包含重复元素的Collection
List:有顺序的collection,并且可以包含重复元素
Map:可以把键映射到值的对象,键不能重复
18.为什么集合类没有实现Cloneable和Serializable接口
集合类接口指定了一组叫做元素的对象。集合类接口的每一种具体实现类都可以选择以它自己的方式对元素进行保存和排序。有的集合类允许重复的建,有些不允许。
19.什么是迭代器(Iterator)?
Iterator接口提供了很多对集合元素进行迭代的方法。每一个集合类都包含了可以返回迭代器实例的迭代方法。迭代器可以在迭代的过程中删除底层集合的元素。
克隆或者是序列化的语义和含义是跟具体的实现相关的。因此,应该由集合类的具体实现来决定如何被克隆或者是序列化。
20.Iterator和ListIterator的区别是什么?
iterator可用来遍历list和set集合,但是ListIterator只能用来遍历list
Iterator对 集合只能是前向遍历,ListIterator既可以前向也可以后向。
ListIterator实现了Iterator接口,并包含其他的功能,比如:增加元素,替换元素,获取前一个和后一个元素的索引
21.java中的HashMap的工作原理是什么?
java中的HashMap是以键值对的形式存储元素的,HashMap需要一个hash函数,它使用hashCode()
和equals()方法来想集合/从集合添加和检索元素,当调用put()方法的时候,HashMap会计算key的hash的值,然后把键值对存储在集合中合适的索引上。如果key已经存在了,value会被更新成新值。HashMap的一些重要的特性是它的容量,负载因子和扩容极限
22.hashCode和equals方法的重要性提现在什么地方?
java中的hashMap使用hashaCode和equals方法来确认键值对的索引,当根据键获取值的时候也会用到这两个方法。如果没有正确是的实现这两个方法,两个不同的键可能会有相同的hash值,因此可能会被集合认为是相等的。而且,这两个方法也用来发现重复元素,所以这两个方法的实现对hashmap的精确性和正确性是至关重要的。
23.hshMap和HashTable有什么区别?
不同点:
HashMap允许键和值都是null,而HashTable不允许键或者是值是null
HashTable是同步的,而HashMap不是,因此,HashMap更适合于单线程环境,而hashTable更适合于多线程环境
HshMap提供了可供应用迭代的集合,因此,HashMap是快速失败的,另一方面,HashTable提供了对键的列举。
24.数组(Array)和列表(ArrayList)有什么区别?什么时候应该用Array而不是ArrayList?
Array可以包含基本类型和对象类型,ArrayList只能包含对象类型
Array大小是固定的,ArrayList的大小是动态变化的
ArrayList提供了更多的方法和特性,比如:addAll,removeAll,iterator等
对于基本类型数据,集合使用自动装箱来减少编码工作量,但是在处理固定大小的基本数据类型的时候,这中方式相对比较慢
25.ArrayList和LinkedList有什么区别?
ArrayList是基于索引的数据接口,它的底层是数组,它可以以O(1)时间复杂度对元素进行随机访问,与此对应,LinkedList是以元素列表的形式存储它的数据,每一个元素都和它的前一个和后一个连接在一起,在这种情况下,查找某个元素的时间复杂度是O(n)。
相对于A让rayList,LinkedList的插入,添加,删除操作速度更快,因为当元素被添加到集合任意位置的时候,不需要像数组那样重新计算大小或者是更新索引。
LinkedList比ArrayList更占内存,因为LinkedList为每一个节点存储了两个引用,一个指向前一个元素,一个指向下一个元素。
26.HshSet和TreeSet有什么区别?
HashSet是由一个hash表来实现的,因此,它的元素是无序的,add,remove,contains方法的时间复杂度都是O(1)。另一方面,TreeSet是由一个树形的结构来实现的,它里面的元素是有序的,因此,add,remove,contains方法的时间复杂度是O(logn)。
27.java的两种异常类型是什么?它们有什么区别?
java中有两种异常:受检查的异常和不受检查的异常,不受检查的异常不需要在方法或者是构造函数上声明,就算方法或者是构造函数的执行可能会抛出这样的异常,并且不受检查的异常可以传播到方法或者是构造函数的外面,相反,受检查的异常必须要throws语句在方法或者是构造函数上声明
28.java中Exception和Error有什么区别?
Exception和Error都是Throwable的子类,Exception用于用户程序可以捕捉的异常情况,Error定义了不期望被用户程序捕捉的异常。
29.throw和throws有什么区别?
throw关键字用来在程序中明确的抛出异常,相反,throws语句用来表名方法不能处理的异常,每一个方法都必须要指定哪些异常不能处理,所以方法的调用者才能确保处理可能发生的异常,多个异常使用逗号分隔的。
30.finally代码块和finalize方法有什么区别?
无论是否抛出异常,finally代码块都会执行,它主要是用来释放应用占用的资源,finalize方法是Object类的一个protected方法,它是对象被垃圾回收之前由java虚拟机来调用的。
31.什么是JDBC?
JDBC是允许用户在不同数据库之间做选择的一个抽象层,JDBC允许开发者用java写数据库应用程序,而不需要关心底层特定数据库的细节。
32.Class.forName()方法有什么作用?
这个方法用来载入跟数据库建立连接的驱动。
33.PreparedStatement比Statement有什么优势?
PreparedStatement是预编译的,因此,性能会更好,同时,不同的查询参数值,PreparedStatement可以重用。
34.什么时候使用CallableStatement?用来准备CallableStatement的方法是什么?
CallableStatement用来执行存储过程,存储过程是由数据库存储和提供的,存储过程可以接受输入参数,也可以有返回结果,非常鼓励使用存储过程,因为它提供了安全和模块化,准备一个CallableStatement的方法是:
CallableStatement.prepareaCall();
35.数据库连接池是什么意思?
像打开关闭数据库连接这种和数据库的交互可能是很费时的,尤其是当客户数量增加的时候,会消耗大量的资源,成本是非常高的。可以在应用服务器启动的时候建立很多个数据库连接并维护在一个池中。连接请求由池中的连接提供,在连接使用完毕以后,把连接归还池中,以用于满足将来更多的请求。
36.GenericServlect和HttpServlect有什么区别?
GenericServlect是一个通用的协议无关的Servlect,它实现了Servlect和ServlectConfig接口,继承自GenericServlect的Servlect应该要覆盖service()方法,最后,为了开发一个能用在网页上服务于使用HTTP协议请求的Servlect,你的Servlect必须要继承自HttpServlect。
37.什么Servlect链?
Servlect是把一个Servlect的输出发送给另一个Servlect的方法,第二个Servlect输出可以发送给第三个Servlect,以此类推,链条上最后一个Servlect负责把响应发送给客户端。
38.如何知道是哪一个客户端的几期正在请求你的Servlect?
ServlectRequest类可以找出客户端几期的IP地址或者是主机名,getRemoteAddr()方法获取客户端主机的IP地址,getRemoteHost()可以获取主机名。
39.HTTP响应的结构是怎么样的?
HTTP响应由三个部分组成:
状态码:描述了响应的状态,可以用来检查是否成功的完成了请求,请求失败的情况下,状态码可用来找出失败的原因,如果Servlect没有返回状态码,默认会返回成功的状态码,HttpServlectResponse.SC_OK。
HTTP头部:它们包含了更多关于响应的信息,比如:头部可以指定认为响应的过期日期,或者是指定用来给用户安全的传输实体内容的编码格式。
主体:它包含了响应的内容,它可以包含HTML代码,图片等等,主体是由传输在HTTP消息中紧跟在头部后面的数据字节组成的。
40.什么是Cookie?Session和Cookie有什么区别?
cookie是Web服务器发送给浏览器的一块信息,浏览器会在本地文件中给每一个Web服务器存储cookie,以后服务器在给特定的Web服务器发请求的时候,同时会发送所有为该服务器存储的cookie
cookie和session的区别:
无论客户端浏览器做怎么样的设置,session都应该能正常工作,客户端可以选择禁用cookie,但是session任然是能够工作的,因为客户端无法禁用服务器端的session。
在存储的数据量方面cookie和session也是不一样的,session能够存储任意的java对象,cookie只能存储String类型的对象。
41.浏览器和Servlect通信使用的是什么协议?
浏览器和Servlect通信使用的是HTTP协议。
42.什么是HTTP隧道?
HTTP隧道是一种利用HTTP或者是HTTPS把多种网络协议封装起来进行通信的技术,因此,HTTP协议扮演了一个打通用于通信的网络协议的管道的包装期的角色,把其他协议的请求掩盖成HTTP的请求就是HTTP隧道。
43.什么是JSP页面?
JSP页面是一种包含了静态数据和JSP元素两种类型的文本的文本文档,静态数据可以用任何基于文本的格式来表示,比如:HTML或者XML,JSP是一种混合了静态内容和动态产生的内容的技术。
44.JSP请求是如何被处理的?
浏览器首先要请求一个以.JSP扩展名结尾的页面,发起JSP请求,然后,Web服务器读取这个请求,使用JSP编译器把JSP页面转化成一个Servlect类。需要注意的是,只有当第一次请求页面或者是JSP
文件发生改变的时候JSP文件才会被编译,然后服务器调用Servlect类,处理浏览器的请求,一旦请求执行结束,servlect会把响应发送给客户端。
45.JSP有什么优点?
JSP页面是被动态编译成Servlect的,因此,开发者可以很容易的更新展现代码。
JSP页面是可以被预编译的
JSP页面可以很容易的和静态模版结合,包括:HTML或者XML,也可以很容易的和产生动态内容的代码结合起来。
开发者可以提供让页面设计者以类XML格式来访问的自定义的JSP标签库
开发者可以在组件层做逻辑上的改变,而不需要编辑单独使用了应用层逻辑的页面
46.什么是JSP指令?JSP中有哪些不同类型的指令?
Directive是当JSP页面被编译成Servlect的时候,JSP引擎要处理的指令。Directive用来设置页面级别的指令,从外部文件插入数据,指定自定义的标签库。Directive是定义在<%@ 和 %>之间的,下面列出来了不同类型的Directive:
包含指令:用来包含文件和合并文件内容到当前的页面
页面指令:用来定义JSP页面中特定的属性,比如错误页面和缓冲区
Taglib指令:用来声明页面中使用的自定义的标签库
47.什么是JSP动作?
JSP动作以XML语法的结构来控制Servlect引擎的行为,当JSP页面被请求的时候,JSP动作会被执行,它们可以被动态的插入到文件中,重用JavaBean组件,转发用户到其他的页面,或者是给java插件产生HTML代码,下面列出了可用的动作:
jsp:include-当JSP页面被请求的时候包含一个文件
jsp:useBean-找出或者是初始化JavaBean
jsp:setProperty-设置JavaBean的属性
jsp:getProperty-获取JavaBean的属性
jsp:forward-把请求转发到新的页面
jsp:plugin-产生特定浏览器的代码
48.什么是Scriptlets?
JSP技术中,scriptlets是嵌入在JSP页面中的一段java代码,scriptlet是位于标签内部的所有的东西,在标签与标签之间,用户可以添加任意有效的scriptlet。
49.声明(Decalaration)在哪里?
声明跟java的变量声明很相似,它用来声明随后要被表达或者scriptlet使用的变量,添加的声明必须要开始和结束标签包起来。
50.什么是表达式(Expression)?
JSP表达式是Web服务器把脚本语言表达式的值转化成一个String对象,插入到返回给客户端的数据流中,表达式是在<%= 和 %>这两个标签之间定义的。
51.隐含对象是什么意思?有哪些隐含对象?
JSP隐含对象是页面中的一些Java对象,JSP容器让这些Java对象可以为开发者所用,开发者不用明确的声明就可以使用他们,JSP隐含对象也叫做预定义变量,下面列出了JSP的隐含对象:
application,page,request,response,session,exception,out,config,pageContext
52.java多线程中的死锁
死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种相互等待的现象,若无外力作用,它们都将无法推进下去。死锁会让你的程序挂起无法完成任务,造成死锁必须满足四条件:
互斥条件,一个资源只能被一个进程使用
请求与保持条件,一个进程因请求资源而阻塞时,对已经获得的资源保持不放
不剥夺条件,进程已获得的资源,在未使用完之前,不能强行剥夺
循环等待条件,若干进程之间行程一种头尾相接的循环等待资源关系
避免死锁最贱的方法就是组织循环等待条件,将系统中所有的资源设置成标志位,排序,规定所有的进程申请资源必须以一定的顺序(升序或降序)做操作来避免死锁
53.java中死锁和活锁有什么区别?
活锁和死锁类似,不同之处在于处于活锁的线程或进程是不断改变的,活锁可以认为是一种特殊的饥饿,一个现实的活锁例子是两个人在狭小的走廊碰到,两个人都试着避让对方让彼此通过,但是因为避让的方向都一样导致谁都不能通过,简单的说就是,活锁和死锁的主要区别就是前者进程的状态可以改变但是却不能继续执行
54.怎么检查一个线程是否拥有锁?
在java.lang.Thread中有一个方法叫holdsLock,它返回true如果当且仅当当前线程拥有某个具体对象的锁
55.有三个线程T1,T2,T3,怎么确保它们按顺序执行
可以使用join方法在一个线程中启动另一个线程,另外一个线程完成该线程继续执行,为了确保三个线程的顺序你应该先启动最后一个(T3调用T2,T2调用T1),这样T1就会先完成而T3最后完成
56.Thread类中的yield方法有什么作用?
Yield方法可以暂停当前正在执行的线程对象,让其他拥有相同优先级的线程执行,它是一种静态方法 ,而且只保证当前线程放弃CPU占用而不能保证线程一定能占用CPU,执行yield的线程可能在进入到暂停状态后马上又被执行。
57.说出Servlet的生命周期,并说出Servlet和CGI的区别
Servlet被服务器实例化后,容器运行其init方法,请求到达时运行service方法,service方法自动派遣运行与请求对应的doXXX方法(doGet,doPost)等,当服务器决定将实例销毁的时候调用destroy方法,与cgi的区别在于servlet处于服务器进程中,它通过多线程方式运行其service方法,一个实例可以服务于多个请求,并且其实例一般不会销毁,而CGI对每个请求都产生新的进程,服务完成后销毁,所以效率上低于servlet。
58.Statement和PreparedStatement有什么区别?哪个性能更好?
与Statement相比:
1)PreparedStatement接口代表预编译的语句,它主要的优势在于可以减少SQL的编译错误并增加SQL的安全性(减少SQL注射攻击的可能性);
2)PreparedStatement中的SQL语句是可以带参数的,避免了用字符串连接拼接SQL语句的麻烦和不安全;
3)当批量处理SQL或频繁执行相同的查询时,PreparedStatement有明显的性能上的优势,由于数据库可以将编译优化后的SQL语句缓存起来,下次执行相同结构的语句时就会很快。
59.使用JDBC操作数据库时,如何提升读取数据的性能?如何提升更新数据的性能?
要提升读取数据的性能,可以指定通过结果集(ResultSet)对象的setFetchSize()方法指定每次读取的记录数(空间换时间),要提升更新数据的性能可以使用PreparedStatement语句构建批处理,将若干SQL语句置于一个批处理中执行。
60.在进行数据库编程时,连接池有什么作用?
由于创建连接和释放连接都有很大的开销(尤其是数据库服务器不在本地时,每次建立连接都需要进行TCP的三次握手,释放连接需要进行TCP四次握手,造成的开销是不可忽视的),为了提升系统访问数据库的性能,可以事先创建若干连接置于连接池中,需要时直接从连接池获取,使用结束时归还连接池而不必关闭连接,从而避免频繁创建和释放连接所造成的开销,这是典型的用空间换时间的策略(浪费了空间存储连接,但节省了创建和释放连接的时间)。
61.事务的ACID是什么?
原子性(Atomic):事务中各项操作,要么全做要么全不做,任何一项操作的失败都会导致整个事务的失败;
一致性(Consistent):事务结束后系统状态是一致的;
隔离性(Isolated):并发执行的事务批次无法看到对象的中间状态;
持久性(Durable):事务完成后所做的改动都会被持久化,即使发生灾难性的失败,通过日志和同步备份可以在故障发生后重建数据。
脏读(Dirty Read):A事务读取B事务尚未提交的数据并在此基础上操作,而B事务执行回滚,那么A读取到的数据就是脏数据。
不可重复度(Unrepeatable Read):事务A重新读取前面读取过的数据,发现该数据已经被另一个已提交的事务B修改过了。
幻读(Phantom Read):事务A重新执行一个查询,返回一系列符合查询条件的行,发现其中插入了被事务B提交的行。
第1类丢失更新:事务A撤销时,把已经提交的事务B的更新数据覆盖了。
第2类丢失更新:事务A覆盖事务B已经提交的数据,造成事务B所做的操作丢失。
数据并发访问所产生的问题,在有些场景下可能是允许的,但是有些场景下可能就是致命的,数据库通常会通过锁机制来解决数据并发访问问题,按锁定对象不同可以分为表级锁和行级锁;按并发事务锁关系可以分为共享锁和独占锁。
直接使用锁非常麻烦的,为此数据库用户提供了自动锁机制,只要用户指定会话的事务隔离级别,数据库就会通过分析SQL语句然后为事务访问的资源加上合适的锁,此外,数据库还会维护这些锁通过各种手段提高系统的性能,这些对用户来说是透明的

需要说明的是,事务隔离级别和数据访问的并发性是对立的,事务隔离级别越高并发性就越差。所以要根据具体的应用来确定合适的事务隔离级别,这个地方没有万能的原则。
62.获得一个类的类对象的方式有哪些?
1):类型.class,例如:String.class
2):对象.getClass(),例如:”hello”.getClass()
3):Class.forName(),例如:Class.forName(“java.lang.string”)
63.如何通过反射创建对象?
1)通过类对象调用newInstance()方法,例如:
String.class.newInstance()
2)通过类对象的getConstructor()或getDeclaredConstructor()方法获得构造器(Constructor)对象并调用其newInstance()方法创建对象,例如:
String.class.getConstructor(String.class).newInstance(“Hello”);
63.如何通过反射调用对象的方法?
class MethodInvokeTest { public static void main(String[] args) throws Exception { String str = “hello”; Method m = str.getClass().getMethod(“toUpperCase”); System.out.println(m.invoke(str)); // HELLO }
}
64.简述一下面向对象的“六原则-法则”
单一职责原则:一个类值做它该做的事,高内聚,低耦合
开闭原则:软件实体对扩展开放,对修改关闭
依赖倒转原则:面向接口编程
里氏替换原则:任何时候都可以用子类型替换掉父类型
接口隔离原则:接口小而专,绝不能大而全
合成聚合复用原则:优先使用聚合或合成关系复用代码
迪米特法则:最少知道原则,一个对象应该对其他对象有尽可能少的了解(低耦合)
这里写图片描述
图一:不符合迪米特法则的设计
这里写图片描述
图二:符合迪米特法则的设计
65.设计模式
工厂模式:工厂类可以根据条件生成不同的子类实例,这些子类有一个公共的抽象父类并且实现了相同的方法,但是这些方法针对不同的数据进行了不同的操作(多态方法),当得到子类的实例后,开发人员可以调用基类中的方法而不必考虑到底返回的是哪一个子类的实例
代理模式:给一个对象提供一个代理对象,并由代理对象控制原对象的引用。实际开发中,按照使用目的的不同,代理可以分为:远程代理,虚拟代理,保护代理,Cache代理,防火墙代理,同步化代理,智能引用代理。
适配器模式:把一个类的接口换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起使用的类能够一起工作。
模版方法模式:提供一个抽象类,将部分逻辑以具体方法或构造器的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑,不同的子类可以以不同的方式实现这些抽象方法,从而实现不同的业务逻辑。
66.排序算法
1)冒泡排序
2)二分查找
67.Servlet接口中有哪些方法?
Servlet接口定义了5个方法,其中前三个方法与Servlet生命周期有关:
void init(ServletConfig config) throws ServletException
void service(ServletRequest req, ServletResponse resp) throws ServletException, java.io.IOException
void destory()
java.lang.String getServletInfo()
ServletConfig getServletConfig()
Web容器加载Servlet并将其实例化后,Servlet生命周期开始,容器运行其init()方法进行Servlet的初始化;请求到达时调用Servlet的service()方法,service()方法会根据需要调用与请求对应的doGet或doPost等方法;当前服务器关闭或项目被卸载时服务器会将Servlet实例销毁,此时调用Servlet的destroy()方法。
68.get和post请求的区别
1)get请求用来从服务器上获得资源,而post是用来向服务器提交数据;
2)get将表单中数据按照anme = value的形式,添加到action所指向的URL后面,并且两者使用“?”连接,而两个变量之间使用“&”连接;post是将表单中的数据放在HTTP协议的请求头或消息体中,传递到action所指向URL;
3)get传输的数据收到URL长度限制(1024字节);而post可以传输大量数据,上传文件通常要使用post方式;
4)使用get时参数会显示在地址栏上,如果这些数据不是敏感数据,那么可以使用get;对于敏感数据还是应该使用post;
5)get使用MIME类型application/x-www-form-urlencoded的URL编码(也叫百分号编码)文本的格式传递参数,保证被传送的参数由遵循规范的文本组成,例如一个空格的编码是“%20”。
69.讲解JSP中的四种作用域。
JSP中的四种作用域包括page,request,session,application
page代表一个与页面相关的对象和属性
request代表与web客户机发出的一个请求相关的对象和属性,一个请求可能跨越多个页面,涉及多个web组件,需要在页面显示的临时数据可以置于此作用域
session代表与某个用户与服务器建立的一次会话相关的对象和属性,跟某个用户相关的数据应该放在用户自己的session中
application代表与整个web应用程序相关的对象和属性,它实质上是跨越整个web应用程序,包括多个页面,请求和会话的一个全局作用域。
70.你的项目中使用过哪些JSTL标签?
项目中主要使用了JSTL的核心标签库,包括、、、、等,主要用于构造循环和分支结构以控制显示逻辑。
71.Servlet3中的异步处理指的是什么?
如果一个任务处理时间相当长,那么Servlet或Filter会一直占用着请求处理线程直到任务结束,随着并发用户的增加,容器将会遭遇线程超出的风险,这种情况下很多的请求将会堆积起来而后续的请求可能会遭遇拒绝服务,直到有资源可以处理请求为止,异步特性可以帮助应用节省容器中的线程,特别适合执行时间长而且用户需要得到结果的任务,如果用户不需要得到结果则直接将一个Runnable对象交给Executor并立即返回即可。
72.Servlet中如何获取用户提交的查询参数或表单数据?
可以通过请求对象(HttpServletRequest)的getParameter()方法通过参数名获得参数值,如果有包含多个值的参数(例如复选框),可以通过请求对象的getParameterValues()方法获得,当然也可以通过请求对象的getParameterMap()获得一个参数名和参数值的映射(Map)。
73.Servlet中如何获取用户配置的初始化参数以及服务器上下文参数?
可以通过重写Servlet接口的init(ServletConfig)方法并通过ServletConfig对象的getInitParameter()方法来获取Servlet的初始化参数。可以通过ServletConfig对象的getServletContext()方法获取ServletContext对象,并通过该对象的getInitParameter()方法来获取服务器上下文参数。当然,ServletContext对象也在处理用户请求的方法(如doGet()方法)中通过请求对象的getServletContext()方法来获得。
74.如何设置请求的编码以及响应内容的类型?
通过请求对象(ServletRequest)的setCharacterEncoding(String)方法可以设置请求的编码,其实要彻底解决乱码问题就应该让页面、服务器、请求和响应、Java程序都使用统一的编码,最好的选择当然是UTF-8;通过响应对象(ServletResponse)的setContentType(String)方法可以设置响应内容的类型,当然也可以通过HttpServletResponsed对象的setHeader(String, String)方法来设置。
75.网络应用模式
典型的网络应用:B/S、C/S、P2P
B2B(如阿里巴巴)、B2C(如当当、亚马逊、京东)、C2C(如淘宝、拍拍)、C2B(如威客)、O2O(如美团、饿了么)
76.概念解释:SOAP,WSDL,UDDI
SOAP:简单对象访问协议(SimpleObjectAccessProtocol),是Web Service中交换数据的一种协议规范。
WSDL:Web服务描述语言(Web Service Description Language),它描述了Web服务的公共接口。这是一个基于XML的关于如何与Web服务通讯和使用的服务描述;也就是描述与目录中列出的Web服务进行交互时需要绑定的协议和信息格式。通常采用抽象语言描述该服务支持的操作和信息,使用的时候再将实际的网络协议和信息格式绑定给该服务。
UDDI:统一描述、发现和集成(Universal Description, Discovery and Integration),它是一个基于XML的跨平台的描述规范,可以使世界范围内的企业在互联网上发布自己所提供的服务。简单的说,UDDI是访问各种WSDL的一个门面(可以参考设计模式中的门面模式)。
77.什么是ORM(Object-Relational Mapping,简称ORM)?
对象关系映射是一种为了解决程序的面向对象模型与数据库的关系模型互不匹配问题的技术;ORM是通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系数据库中或者将关系数据库中的行转换成java对象,实质上是将数据从一种形式转换到另外一种形式
78.持久层设计要考虑的问题有哪些?你用过的持久层框架有哪些?
所谓“持久”就是将数据保存到可掉电式存储设备中以便今后使用,简单的说,就是将内存中的数据保存到关系型数据库,文件系统,消息队列等提供持久化支持的设备中,持久层就是刺痛中专注于实现数据持久化的相对独立的层面。
持久层设计的目标包括:
数据存储逻辑的分离,提供抽象化的数据访问接口。
数据访问底层实现的分离,可以在不修改代码的情况下切换底层实现。
资源管理和调度的分离,在数据访问层实现统一的资源调度(如缓存机制)。
数据抽象,提供更面向对象的数据操作。
持久层框架有:
Hibernate
MyBatis
TopLink
Guzz
jOOQ
Spring Data
ActiveJDBC
79.Hibernate中SessionFactory是线程安全的吗?Session是线程安全的吗(两个线程能够共享同一个Session吗)?
SessionFactory对应Hibernate的一个数据存储的概念,它是线程安全的,可以被多个线程并发访问。SessionFactory一般只会在启动的时候构建。对于应用程序,最好将SessionFactory通过单例模式进行封装以便于访问。Session是一个轻量级非线程安全的对象(线程间不能共享Session),它表示与数据库进行交互的一个工作单元,Session是由SessionFactory创建的,在任务完成之后它会被关闭,Session是持久层服务对外提供的主要接口。Session会延迟获取数据库连接(也就是在需要的时候才获取),为了避免创建太多的Session,可以使用ThreadLocal将Session和当前线程绑定在一起,这样可以让同一个线程获得的总是同一个session,Hibernate3中的SessionFactory的getCurrentSession()方法就可以得到。
80.Hibernate中Session的load和get方法的区别是什么?
主要有三个区别:
1):如果没有找到符合条件的记录,get返回null,load方法抛出异常。
2):get方法直接返回实体类对象,load方法返回实体类对象的代理
3):在Hibernate3之前,get方法只在一级缓存中进行数据查找,如果没有找到对应的数据则越过二级缓存,直接发出SQL语句完成数据读取;load方法则可以从二级缓存中获取数据;从Hibernate3开始。get方法不再是对二级缓存只写不读,它也是可以访问二级缓存的。
81.阐述Session加载实体对象的过程。
Session加载实体对象的步骤是:
1)Session在调用数据库查询功能之前,首先会在一级缓存中通过实体类型和主键进行查找,如果一级缓存查找命中切数据状态合法,则直接返回;
2)如果一级缓存没有命中,接下来Session会在当前NonExists记录(相当于一个查询黑名单,如果出现重复的无效查询可以迅速做出判断,从而提升性能)中查找,如果NonExists中存在同样的查询条件,则返回null;
3)如果一级缓存查询失败则查询二级缓存,如果二级缓存命中则直接返回;
4)如果之前的查询都没有命中,则发出SQL语句,如果查询未发现对应记录则将此次查询添加到Session的NonExists中加以记录,并返回null;
5)根据映射配置和SQL语句得到ResultSet,并创建对应的实体对象;
6)将对象纳入Session的管理;
7)如果有对应的拦截器,则进行拦截器的onLoad方法;
8)如果开启设置了要使用二级缓存,则将数据对象纳入二级缓存;
9)返回数据对象
82.Hibernate如何实现分页查询?
通过Hibernate实现分页查询,开发人员只需要提供HQL语句(调用Session的createQuery()方法)或查询条件(调用Session的createCriteria()方法)、设置查询起始行数(调用Query或Criteria接口的setFirstResult()方法)和最大查询行数(调用Query或Criteria接口的setMaxResults()方法),并调用Query或Criteria接口的list()方法,Hibernate会自动生成分页查询的SQL语句。
83.锁机制有什么用?简述Hibernated额悲观锁和乐观锁机制
悲观锁,认为在数据处理过程中极有可能存在修改数据的并发事务,于是将处理的数据设置为锁定状态。
乐观锁,对并发事务持乐观态度(认为对数据的并发操作不会经常性的发生),通过更加宽松的锁机制来解决悲观锁排他性的数据访问对系统性能造成的严重影响。
84.阐述实体对象的三种状态以及转换关系
四种种状态分别是:瞬时态(new, or transient)、持久态(managed, or persistent)、游状态(detached)和移除态(removed,以前Hibernate文档中定义的三种状态中没有移除态):
这里写图片描述
图三:Hibernate实体对象状态转换图
瞬时态:当new一个实体对象后,这个对象处于瞬时态,即这个对象只是一个保存临时数据的内存区域,如果没有变量引用这个对象,则会被JVM的垃圾回收机制回收。这个对象所保存的数据与数据库没有任何关系,除非通过Session的save()、saveOrUpdate()、persist()、merge()方法把瞬时态对象与数据库关联,并把数据插入或者更新到数据库,这个对象才转换为持久态对象。
持久态:持久态对象的实例在数据库中有对应的记录,并拥有一个持久化标识(ID)。对持久态对象进行delete操作后,数据库中对应的记录将被删除,那么持久态对象与数据库记录不再存在对应关系,持久态对象变成移除态(可以视为瞬时态)。持久态对象被修改变更后,不会马上同步到数据库,直到数据库事务提交。
游离态:当Session进行了close()、clear()、evict()或flush()后,实体对象从持久态变成游离态,对象虽然拥有持久和与数据库对应记录一致的标识值,但是因为对象已经从会话中清除掉,对象不在持久化管理之内,所以处于游离态(也叫脱管态)。游离态的对象与临时状态对象是十分相似的,只是它还含有持久化标识。
85.如何理解Hibernate的延迟加载机制?在实际应用中,延迟加载与Session关闭的矛盾是如何处理的?
延迟加载就是并不是在读取的时候就把数据加载进来,而是等到使用时再加载。Hibernate使用了虚拟代理机制实现延迟加载,我们使用Session的load()方法加载数据或者一对多关联映射在使用延迟加载的情况下从一的一方加载多的一方,得到的都是虚拟代理,简单的说返回给用户的并不是实体本身,而是实体对象的代理。代理对象在用户调用getter方法时才会去数据库加载数据。但加载数据就需要数据库连接。而当我们把会话关闭时,数据库连接就同时关闭了。
延迟加载与session关闭的矛盾一般可以这样处理:
① 关闭延迟加载特性。这种方式操作起来比较简单,因为Hibernate的延迟加载特性是可以通过映射文件或者注解进行配置的,但这种解决方案存在明显的缺陷。首先,出现”no session or session was closed”通常说明系统中已经存在主外键关联,如果去掉延迟加载的话,每次查询的开销都会变得 很大。
② 在session关闭之前先获取需要查询的数据,可以使用工具方法Hibernate.isInitialized()判断对象是否被加载,如果没有被加载则可以使用Hibernate.initialize()方法加载对象。
③ 使用拦截器或过滤器延长Session的生命周期直到视图获得数据。Spring整合Hibernate提供的OpenSessionInViewFilter和OpenSessionInViewInterceptor就是这种做法。
86.谈一下你对继承映射的理解。
继承关系的映射策略有三种:
① 每个继承结构一张表(table per class hierarchy),不管多少个子类都用一张表。
② 每个子类一张表(table per subclass),公共信息放一张表,特有信息放单独的表。
③ 每个具体类一张表(table per concrete class),有多少个子类就有多少张表。
第一种方式属于单表策略,其优点在于查询子类对象的时候无需表连接,查询速度快,适合多态查询;缺点是可能导致表很大。后两种方式属于多表策略,其优点在于数据存储紧凑,其缺点是需要进行连接查询,不适合多态查询。
87.简述Hibernate常见优化策略。
① 制定合理的缓存策略(二级缓存、查询缓存)。
② 采用合理的Session管理机制。
③ 尽量使用延迟加载特性。
④ 设定合理的批处理参数。
⑤ 如果可以,选用UUID作为主键生成器。
⑥ 如果可以,选用基于版本号的乐观锁替代悲观锁。
⑦ 在开发过程中, 开启hibernate.show_sql选项查看生成的SQL,从而了解底层的状况;开发完成后关闭此选项。
88.谈一谈Hibernate的一级缓存、二级缓存和查询缓存。
Hibernate的Session提供了一级缓存的功能,默认总是有效的,当应用程序保存持久化实体、修改持久化实体时,Session并不会立即把这种改变提交到数据库,而是缓存在当前的Session中,除非显示调用了Session的flush()方法或通过close()方法关闭Session。通过一级缓存,可以减少程序与数据库的交互,从而提高数据库访问性能。SessionFactory级别的二级缓存是全局性的,所有的Session可以共享这个二级缓存。不过二级缓存默认是关闭的,需要显示开启并指定需要使用哪种二级缓存实现类(可以使用第三方提供的实现)。一旦开启了二级缓存并设置了需要使用二级缓存的实体类,SessionFactory就会缓存访问过的该实体类的每个对象,除非缓存的数据超出了指定的缓存空间。
一级缓存和二级缓存都是对整个实体进行缓存,不会缓存普通属性,如果希望对普通属性进行缓存,可以使用查询缓存。查询缓存是将HQL或SQL语句以及它们的查询结果作为键值对进行缓存,对于同样的查询可以直接从缓存中获取数据。查询缓存默认也是关闭的,需要显示开启。
89.什么是IoC和DI?DI是如何实现的?
IoC叫控制反转,是Inversion of Control的缩写,DI(Dependency Injection)叫依赖注入,是对IoC更简单的诠释。控制反转是把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。所谓的”控制反转”就是对组件对象控制权的转移,从程序代码本身转移到了外部容器,由容器来创建对象并管理对象之间的依赖关系。IoC体现了好莱坞原则 - “Don’t call me, we will call you”。依赖注入的基本原则是应用组件不应该负责查找资源或者其他依赖的协作对象。配置对象的工作应该由容器负责,查找资源的逻辑应该从应用组件的代码中抽取出来,交给容器来完成。DI是对IoC更准确的描述,即组件之间的依赖关系由容器在运行期决定,形象的来说,即由容器动态的将某种依赖关系注入到组件之中。
依赖注入可以通过setter方法注入(设值注入)、构造器注入和接口注入三种方式来实现,Spring支持setter注入和构造器注入,通常使用构造器注入来注入必须的依赖关系,对于可选的依赖关系,则setter注入是更好的选择,setter注入需要类提供无参构造器或者无参的静态工厂方法来创建对象。
90.解释一下什么叫AOP(面向切面编程)?
AOP(Aspect-Oriented Programming)指一种程序设计范型,该范型以一种称为切面(aspect)的语言构造为基础,切面是一种新的模块化机制,用来描述分散在对象、类或方法中的横切关注点(crosscutting concern)。
91.你是如何理解”横切关注”这个概念的?
“横切关注”是会影响到整个应用程序的关注功能,它跟正常的业务逻辑是正交的,没有必然的联系,但是几乎所有的业务逻辑都会涉及到这些关注功能。通常,事务、日志、安全性等关注就是应用中的横切关注功能。
92.你如何理解AOP中的连接点(Joinpoint)、切点(Pointcut)、增强(Advice)、引介(Introduction)、织入(Weaving)、切面(Aspect)这些概念?
连接点(Joinpoint):程序执行的某个特定位置(如:某个方法调用前、调用后,方法抛出异常后)。一个类或一段程序代码拥有一些具有边界性质的特定点,这些代码中的特定点就是连接点。Spring仅支持方法的连接点。
切点(Pointcut):如果连接点相当于数据中的记录,那么切点相当于查询条件,一个切点可以匹配多个连接点。Spring AOP的规则解析引擎负责解析切点所设定的查询条件,找到对应的连接点。
增强(Advice):增强是织入到目标类连接点上的一段程序代码。Spring提供的增强接口都是带方位名的,如:BeforeAdvice、AfterReturningAdvice、ThrowsAdvice等。很多资料上将增强译为“通知”,这明显是个词不达意的翻译,让很多程序员困惑了许久。
引介(Introduction):引介是一种特殊的增强,它为类添加一些属性和方法。这样,即使一个业务类原本没有实现某个接口,通过引介功能,可以动态的未该业务类添加接口的实现逻辑,让业务类成为这个接口的实现类。
织入(Weaving):织入是将增强添加到目标类具体连接点上的过程,AOP有三种织入方式:①编译期织入:需要特殊的Java编译期(例如AspectJ的ajc);②装载期织入:要求使用特殊的类加载器,在装载类的时候对类进行增强;③运行时织入:在运行时为目标类生成代理实现增强。Spring采用了动态代理的方式实现了运行时织入,而AspectJ采用了编译期织入和装载期织入的方式
切面(Aspect):切面是由切点和增强(引介)组成的,它包括了对横切关注功能的定义,也包括了对连接点的定义。
93.Spring中自动装配的方式有哪些?
no:不进行自动装配,手动设置Bean的依赖关系。
byName:根据Bean的名字进行自动装配。
byType:根据Bean的类型进行自动装配。
constructor:类似于byType,不过是应用于构造器的参数,如果正好有一个Bean与构造器的参数类型相同则可以自动装配,否则会导致错误。
autodetect:如果有默认的构造器,则通过constructor的方式进行自动装配,否则使用byType的方式进行自动装配。
94.Spring中如何使用注解来配置Bean?有哪些相关的注解?
首先需要在Spring配置文件中增加如下配置:

然后可以用@Component、@Controller、@Service、@Repository注解来标注需要由Spring IoC容器进行对象托管的类。这几个注解没有本质区别,只不过@Controller通常用于控制器,@Service通常用于业务逻辑类,@Repository通常用于仓储类(例如我们的DAO实现类),普通的类用@Component来标注。
95.Spring支持的事务管理类型有哪些?你在项目中使用哪种方式?
Spring支持编程式事务管理和声明式事务管理。许多Spring框架的用户选择声明式事务管理,因为这种方式和应用程序的关联较少,因此更加符合轻量级容器的概念。声明式事务管理要优于编程式事务管理,尽管在灵活性方面它弱于编程式事务管理,因为编程式事务允许你通过代码控制业务。
事务分为全局事务和局部事务。全局事务由应用服务器管理,需要底层服务器JTA支持(如WebLogic、WildFly等)。局部事务和底层采用的持久化方案有关,例如使用JDBC进行持久化时,需要使用Connetion对象来操作事务;而采用Hibernate进行持久化时,需要使用Session对象来操作事务。
Spring提供了如下所示的事务管理器。
这里写图片描述
96.Spring MVC的工作原理是怎样的?
Spring MVC的工作原理如下图所示:
这里写图片描述
① 客户端的所有请求都交给前端控制器DispatcherServlet来处理,它会负责调用系统的其他模块来真正处理用户的请求。
② DispatcherServlet收到请求后,将根据请求的信息(包括URL、HTTP协议方法、请求头、请求参数、Cookie等)以及HandlerMapping的配置找到处理该请求的Handler(任何一个对象都可以作为请求的Handler)。
③在这个地方Spring会通过HandlerAdapter对该处理器进行封装。
④ HandlerAdapter是一个适配器,它用统一的接口对各种Handler中的方法进行调用。
⑤ Handler完成对用户请求的处理后,会返回一个ModelAndView对象给DispatcherServlet,ModelAndView顾名思义,包含了数据模型以及相应的视图的信息。
⑥ ModelAndView的视图是逻辑视图,DispatcherServlet还要借助ViewResolver完成从逻辑视图到真实视图对象的解析工作。
⑦ 当得到真正的视图对象后,DispatcherServlet会利用视图对象对模型数据进行渲染。
⑧ 客户端得到响应,可能是一个普通的HTML页面,也可以是XML或JSON字符串,还可以是一张图片或者一个PDF文件。
97.选择使用Spring框架的原因(Spring框架为企业级开发带来的好处有哪些)?
非侵入式:支持基于POJO的编程模式,不强制性的要求实现Spring框架中的接口或继承Spring框架中的类。
IoC容器:IoC容器帮助应用程序管理对象以及对象之间的依赖关系,对象之间的依赖关系如果发生了改变只需要修改配置文件而不是修改代码,因为代码的修改可能意味着项目的重新构建和完整的回归测试。有了IoC容器,程序员再也不需要自己编写工厂、单例,这一点特别符合Spring的精神”不要重复的发明轮子”。
AOP(面向切面编程):将所有的横切关注功能封装到切面(aspect)中,通过配置的方式将横切关注功能动态添加到目标代码上,进一步实现了业务逻辑和系统服务之间的分离。另一方面,有了AOP程序员可以省去很多自己写代理类的工作。
MVC:Spring的MVC框架是非常优秀的,从各个方面都可以甩Struts 2几条街,为Web表示层提供了更好的解决方案。
事务管理:Spring以宽广的胸怀接纳多种持久层技术,并且为其提供了声明式的事务管理,在不需要任何一行代码的情况下就能够完成事务管理。
其他:选择Spring框架的原因还远不止于此,Spring为Java企业级开发提供了一站式选择,你可以在需要的时候使用它的部分和全部,更重要的是,你甚至可以在感觉不到Spring存在的情况下,在你的项目中使用Spring提供的各种优秀的功能。
98.Spring IoC容器配置Bean的方式?
基于XML文件进行配置。
基于注解进行配置。
基于Java程序进行配置(Spring 3+)
99.阐述Spring框架中Bean的生命周期?
① Spring IoC容器找到关于Bean的定义并实例化该Bean。
② Spring IoC容器对Bean进行依赖注入。
③ 如果Bean实现了BeanNameAware接口,则将该Bean的id传给setBeanName方法。
④ 如果Bean实现了BeanFactoryAware接口,则将BeanFactory对象传给setBeanFactory方法。
⑤ 如果Bean实现了BeanPostProcessor接口,则调用其postProcessBeforeInitialization方法。
⑥ 如果Bean实现了InitializingBean接口,则调用其afterPropertySet方法。
⑦ 如果有和Bean关联的BeanPostProcessors对象,则这些对象的postProcessAfterInitialization方法被调用。
⑧ 当销毁Bean实例时,如果Bean实现了DisposableBean接口,则调用其destroy方法。
100.依赖注入时如何注入集合属性?
可以在定义Bean属性时,通过 / / / 分别为其注入列表、集合、映射和键值都是字符串的映射属性。
101.Spring中的自动装配有哪些限制?
如果使用了构造器注入或者setter注入,那么将覆盖自动装配的依赖关系。
基本数据类型的值、字符串字面量、类字面量无法使用自动装配来注入。
优先考虑使用显式的装配来进行更精确的依赖注入而不是使用自动装配。
102.在Web项目中如何获得Spring的IoC容器?
WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(servletContext);
103. 大型网站在架构上应当考虑哪些问题?
分层:分层是处理任何复杂系统最常见的手段之一,将系统横向切分成若干个层面,每个层面只承担单一的职责,然后通过下层为上层提供的基础设施和服务以及上层对下层的调用来形成一个完整的复杂的系统。计算机网络的开放系统互联参考模型(OSI/RM)和Internet的TCP/IP模型都是分层结构,大型网站的软件系统也可以使用分层的理念将其分为持久层(提供数据存储和访问服务)、业务层(处理业务逻辑,系统中最核心的部分)和表示层(系统交互、视图展示)。需要指出的是:(1)分层是逻辑上的划分,在物理上可以位于同一设备上也可以在不同的设备上部署不同的功能模块,这样可以使用更多的计算资源来应对用户的并发访问;(2)层与层之间应当有清晰的边界,这样分层才有意义,才更利于软件的开发和维护。
分割:分割是对软件的纵向切分。我们可以将大型网站的不同功能和服务分割开,形成高内聚低耦合的功能模块(单元)。在设计初期可以做一个粗粒度的分割,将网站分割为若干个功能模块,后期还可以进一步对每个模块进行细粒度的分割,这样一方面有助于软件的开发和维护,另一方面有助于分布式的部署,提供网站的并发处理能力和功能的扩展。
分布式:除了上面提到的内容,网站的静态资源(JavaScript、CSS、图片等)也可以采用独立分布式部署并采用独立的域名,这样可以减轻应用服务器的负载压力,也使得浏览器对资源的加载更快。数据的存取也应该是分布式的,传统的商业级关系型数据库产品基本上都支持分布式部署,而新生的NoSQL产品几乎都是分布式的。当然,网站后台的业务处理也要使用分布式技术,例如查询索引的构建、数据分析等,这些业务计算规模庞大,可以使用Hadoop以及MapReduce分布式计算框架来处理。
集群:集群使得有更多的服务器提供相同的服务,可以更好的提供对并发的支持。
缓存:所谓缓存就是用空间换取时间的技术,将数据尽可能放在距离计算最近的位置。使用缓存是网站优化的第一定律。我们通常说的CDN、反向代理、热点数据都是对缓存技术的使用。
异步:异步是实现软件实体之间解耦合的又一重要手段。异步架构是典型的生产者消费者模式,二者之间没有直接的调用关系,只要保持数据结构不变,彼此功能实现可以随意变化而不互相影响,这对网站的扩展非常有利。使用异步处理还可以提高系统可用性,加快网站的响应速度(用Ajax加载数据就是一种异步技术),同时还可以起到削峰作用(应对瞬时高并发)。&quot;能推迟处理的都要推迟处理”是网站优化的第二定律,而异步是践行网站优化第二定律的重要手段。
冗余:各种服务器都要提供相应的冗余服务器以便在某台或某些服务器宕机时还能保证网站可以正常工作,同时也提供了灾难恢复的可能性。冗余是网站高可用性的重要保证。
104.你用过的网站前端优化的技术有哪些?
① 浏览器访问优化:
减少HTTP请求数量:合并CSS、合并JavaScript、合并图片(CSS Sprite)
使用浏览器缓存:通过设置HTTP响应头中的Cache-Control和Expires属性,将CSS、JavaScript、图片等在浏览器中缓存,当这些静态资源需要更新时,可以更新HTML文件中的引用来让浏览器重新请求新的资源
启用压缩
CSS前置,JavaScript后置
减少Cookie传输
② CDN加速:CDN(Content Distribute Network)的本质仍然是缓存,将数据缓存在离用户最近的地方,CDN通常部署在网络运营商的机房,不仅可以提升响应速度,还可以减少应用服务器的压力。当然,CDN缓存的通常都是静态资源。
③ 反向代理:反向代理相当于应用服务器的一个门面,可以保护网站的安全性,也可以实现负载均衡的功能,当然最重要的是它缓存了用户访问的热点资源,可以直接从反向代理将某些内容返回给用户浏览器。
105.你使用过的应用服务器优化技术有哪些?
① 分布式缓存:缓存的本质就是内存中的哈希表,如果设计一个优质的哈希函数,那么理论上哈希表读写的渐近时间复杂度为O(1)。缓存主要用来存放那些读写比很高、变化很少的数据,这样应用程序读取数据时先到缓存中读取,如果没有或者数据已经失效再去访问数据库或文件系统,并根据拟定的规则将数据写入缓存。对网站数据的访问也符合二八定律(Pareto分布,幂律分布),即80%的访问都集中在20%的数据上,如果能够将这20%的数据缓存起来,那么系统的性能将得到显著的改善。当然,使用缓存需要解决以下几个问题:
频繁修改的数据;
数据不一致与脏读;
缓存雪崩(可以采用分布式缓存服务器集群加以解决,memcached是广泛采用的解决方案);
缓存预热;
缓存穿透(恶意持续请求不存在的数据)。
② 异步操作:可以使用消息队列将调用异步化,通过异步处理将短时间高并发产生的事件消息存储在消息队列中,从而起到削峰作用。电商网站在进行促销活动时,可以将用户的订单请求存入消息队列,这样可以抵御大量的并发订单请求对系统和数据库的冲击。目前,绝大多数的电商网站即便不进行促销活动,订单系统都采用了消息队列来处理。
③ 使用集群。
④ 代码优化:
多线程:基于Java的Web开发基本上都通过多线程的方式响应用户的并发请求,使用多线程技术在编程上要解决线程安全问题,主要可以考虑以下几个方面:A. 将对象设计为无状态对象(这和面向对象的编程观点是矛盾的,在面向对象的世界中被视为不良设计),这样就不会存在并发访问时对象状态不一致的问题。B. 在方法内部创建对象,这样对象由进入方法的线程创建,不会出现多个线程访问同一对象的问题。使用ThreadLocal将对象与线程绑定也是很好的做法,这一点在前面已经探讨过了。C. 对资源进行并发访问时应当使用合理的锁机制。
非阻塞I/O: 使用单线程和非阻塞I/O是目前公认的比多线程的方式更能充分发挥服务器性能的应用模式,基于Node.js构建的服务器就采用了这样的方式。Java在JDK 1.4中就引入了NIO(Non-blocking I/O),在Servlet 3规范中又引入了异步Servlet的概念,这些都为在服务器端采用非阻塞I/O提供了必要的基础。
资源复用:资源复用主要有两种方式,一是单例,二是对象池,我们使用的数据库连接池、线程池都是对象池化技术,这是典型的用空间换取时间的策略,另一方面也实现对资源的复用,从而避免了不必要的创建和释放资源所带来的开销。

0 0
原创粉丝点击