servlet & jsp
servlet
像普通java代码,更加原始。
package ${enclosing_package};
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//servlet模板
public class ${primary_type_name} extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
JSP
像HTML,用标签开发,配合JSP表达式(写java代码) + EL表达式(传参)+ JSTL标签库(和EL配合使用可以取代JSP中大部分的Java代码)。每个JSP页面在第一次被访问时,WEB容器都会把请求交给JSP引擎(即一个Java程序)去处理。JSP引擎先将JSP翻译成一个jspServlet(实质上也是一个servlet),然后按照servlet的调用方式进行调用。
什么是内置对象:
在jsp开发中会频繁使用到一些对象,如ServletContext HttpSession PageContext等。如果每次我们在jsp页面中需要使用这些对象都要自己亲自动手创建就会特别的繁琐。SUN公司因此在设计jsp时,在jsp页面加载完毕之后自动帮开发者创建好了这些对象,开发者只需要使用相应的对象调用相应的方法即可。这些系统创建好的对象就叫做内置对象。
在servlet程序中,如果开发者希望使用session对象,必须通过request.getSession()来得到session对象;
而在jsp程序中,开发中可直接使用session(系统帮我们创建好的session对象的名字就叫session)。调用相应的方法即可,如:session.getId().
什么是隐式对象:
在编写JSP时,不需要声明(创建)就可以直接使用的对象称为隐式对象。
每个JSP页面在第一次被访问时,WEB容器都会把请求交给JSP引擎(即一个Java程序)去处理。JSP引擎先将JSP翻译成一个jspServlet(实质上也是一个servlet),然后按照servlet的调用方式进行调用。
由于JSP第一次访问时会翻译成servlet,所以第一次访问通常会比较慢,但第二次访问,JSP引擎如果发现JSP没有变化,就不再翻译,而是直接调用,所以程序的执行效率不会受到影响。
JSP引擎在调用JSP对应的jspServlet时,会传递或创建9个与web开发相关的对象供jspServlet使用。JSP技术的设计者为便于开发人员在编写JSP页面时获得这些web对象的引用,特意定义了9个相应的变量,开发人员在JSP页面中通过这些变量就可以快速获得这9大对象的引用
域对象
域对象的作用:保存数据,获取数据,共享数据.
-
ServletContext context域 只能在同一个web应用中使用 (全局的)
-
HttpServletRequet request域 只能在同一个请求中使用 (转发)
-
HttpSession session域 只能在同一个会话(session对象)中使用 (私有的)
-
PageContext page域 只能在当前jsp页面使用 (当前页面)
session和cookies
cookies
- Cookie是将会话中产生的数据保存在客户端,是客户端技术。
- Cookie是基于两个头进行工作的:分别是Set-Cookie响应头和Cookie请求头
- 通过Set-Cookie响应头将cookie从服务器端发送给浏览器,让浏览器保存到内部;而浏览器一旦保存了cookie,以后浏览器每次访问服务器时,都会通过cookie请求头,将cookie信息再带回服务器中。在需要时,在服务器端可以获取请求中的cookie中的数据,从而实现某些功能。
session
- Session是将会话中产生的数据保存在服务器端,是服务器端技术
- Session是一个域对象,session中也保存了一个map集合,往session中存数据,其实就是将数据保存到session的map集合中。
- 通过session.setAttribute()方法可以将数据保存到session中,通过session.getAttribute()方法可以将数据从session中取出来。
springmvc工作原理
- 客户端发出一个http请求给web服务器,web服务器对http请求进行解析,如果匹配前端控制器(DispatcherServlet)的请求映射路径,web容器将请求转交给DispatcherServlet.
- DipatcherServlet接收到这个请求之后将根据请求的信息以及处理器映射器(HandlerMapping)的配置找到处理请求的处理器(Handler)。
- 由具体的处理器适配器(HandlerAdapter)对Handler进行具体的调用。
- Handler对数据处理完成以后将返回一个ModelAndView( ) 对象给DispatcherServlet。
- DispatcherSevlet通过视图解析器(ViewResolver)将ModelAndView( )转化为真正的视图View。
- Dispatcher通过model解析出ModelAndView()中的参数进行解析最终展现出完整的view并返回给客户端。
spring和springmvc的区别
SpringMVC是一个MVC模式的WEB开发框架;
Spring是一个通用解决方案, 最大的用处就是通过Ioc/AOP解耦, 降低软件复杂性, 所以Spring可以结合SpringMVC等很多其他解决方案一起使用, 不仅仅只适用于WEB开发
泛型
为了提高可读性,大家还是用有意义的字母比较好,一般来讲,在不同的情境下使用的字母意义如下:
- E—— Element,常用在java Collection里,如:List,Iterator,Set
- K,V —— Key,Value,代表Map的键值对
- N —— Number,数字
- T —— Type,类型,如String,Integer等等
泛型类
class Point{ }
即在类名后面加一个尖括号,括号里是一个大写字母。这里写的是T,其实这个字母可以是任何大写字母
这个T表示派生自Object类的任何类,比如String,Integer,Double等等。这里要注意的是,T一定是派生于Object类的
泛型函数
在返回值前加 来表示泛型变量
public void toStr(String json,class target){ }
LRU和LFU
LRU: Least Recently Used 最近最少使用
选择最近最久未使用的页面予以淘汰。
该算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间 t,当淘汰页面时,选择现有页面中其 t 值最大的。
LFU: least frequently used 最不经常使用
选择最不经常使用的页面进行淘汰。
该算法赋予每个页面一个调用次数,记录从页面放入内存之后的所有调用次数,当淘汰页面时,选择调用次数最少的。
HashMap和concurrentHashMap
HashMap的底层主要是基于数组和链表来实现的,主要是通过key的hashCode来计算hash值的,若hash值相同,会出现hash冲突,HashMap底层是通过链表来解决hash冲突的。jdk1.8中,使用一个Node数组来存储数据,但这个Node可能是链表结构,也可能是红黑树结构,如果同一个格子里的key不超过8个,使用链表结构存储。如果超过了8个,那么会调用treeifyBin函数,将链表转换为红黑树。
在并发编程中使用线程不安全的HashMap可能导致死循环。而使用线程安全的HashTable效率又非常低下,基于以上两个原因,便有了ConcurrentHashMap的登场机会。
ConcurrentHashMap是由Segment数组和HashEntry数组组成。Segment是一种可重用的锁(ReetrantLock),在ConCurrentHashMap中应用,HashEntry用于存储键值对数据,一个ConCurrentHashMap里面包含一个Segment数组,Segment数组是一种数组和链表结构,一个Segment节点包含一个HashEntry数组,每个HasEntry都是一个链表结构,每个Segment守护一个HashEntry数组,每当对HashEntry数组进行修改时,必须先获得对应的Segment锁。锁分段技术:将数据分成一段一段地存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效提高并发访问效率。
jdk 1.8的concurrentHashMap
首先,取消了Segment分段锁的数据结构,取而代之的是**数组+链表(红黑树)**的结构。而对于锁的粒度,调整为对每个数组元素加锁(Node)。然后是定位节点的hash算法被简化了,这样带来的弊端是Hash冲突会加剧。因此在链表节点数量大于8时,会将链表转化为红黑树进行存储。这样一来,查询的时间复杂度就会由原先的O(n)变为O(logN)。
1.8中放弃了Segment臃肿的设计,取而代之的是采用Node + CAS + Synchronized来保证并发安全进行实现
sleep()和wait()
sleep() 方法是线程类(Thread)的静态方法,让调用线程进入睡眠状态,让出执行机会给其他线程,等到休眠时间结束后,线程进入就绪状态和其他线程一起竞争cpu的执行时间。
因为sleep() 是static静态的方法,他不能改变对象的机锁,当一个synchronized块中调用了sleep() 方法,线程虽然进入休眠,但是对象的锁没有被释放,其他线程依然无法访问这个对象。
wait()是Object类的方法,当一个线程执行到 wait() 方法时,它就进入到一个和该对象相关的等待池,同时释放对象的机锁,使得其他线程能够访问,可以通过notify,notifyAll方法来唤醒等待的线程
wait要捕获异常interruptException