客户端cookie方式、利用redis、利用数据库、使用软负载nginx和硬负载F5做会话保持;
创建一个顶级filter,重新包装request和response,重新实现getSession或接管HttpSession;
首先集成一个SessionRepositoryFilter是一个优先级最高的javax.servlet.Filter,它使用了一个SessionRepositoryRequestWrapper类接管了Http Session的创建和管理工作。然后通过SessionRepositoryRequestWrapper与SessionRepositoryResponseWrapper,对原有的request和response进行一层装饰,通过SessionRepository去操纵session;
ArrayList:数组;寻址容易,插入和删除困难;
LinkedList:链表;寻址困难,插入和删除容易。
HashMap:哈希表,链表+数组;寻址容易,插入删除也容易。
1)Entry,属性有 key , value, next;存储的就是Entry[];
2)hash = key.hashCode();index = hash % Entry[].length;
3)位置相同的,通过Entry.next进行存储;
4)null存储在第一个位置;
5)当HashMap中的元素个数超过数组大小(16)*loadFactor(0.75)时,就会进行数组扩容;也就是当大于16*0.75=12就会,扩容重新计算,扩大一倍 2*16=32;所以如果我们已经预知HashMap中元素的个数,那么预设元素的个数能够有效的提高HashMap的性能。
1. 用数据库,在数据库建一张表,需要锁的节点都可以尝试用 select * from Lock where id=xx for update. 这个时候只有一个节点能拿到结果,其它的都会等待,就能实现一个简单的悲观锁。
2. 用 Zookeeper 来做分布式锁。
3. 通过redis实现同步锁。
4. 自己实现,搞个节点来做这个事情,所有要获取锁的都走 RPC 调用来请求锁,用完以后记得释放,不然其他的节点就会挂那里。自己实现很危险的。
1)客户端点击后,应该禁用按钮,避免重复发送;
2)token;在集群同步锁的作用下,请求是需要排队的;这个时候我们只需要通过token就能够解决这个问题;
3)请求加入随机数和时间戳,通过url重复验证也可以避免;只要做好锁和排队机制,这种方法也是可以的;
Java BIO : 同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。
Java NIO : 同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。
Java AIO(NIO.2) : 异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理;
---------------------------------------------------------
1)servlet 生命周期
Servlet被服务器实例化后,容器运行其init方法,请求到达时运行其service方法,service方法自动派遣运行与请求对应的doXXX方法(doGet,doPost)等,当服务器决定将实例销毁的时候调用其destroy方法。
2)spring ioc 生命周期
总结:
spring生命周期的过程为:
BeanFactoyPostProcessor实例化;先执行Bean的构造函数;通过XML配置文件注入相应的属性值;执行InitializingBean接口提供的afterPropertiesSet()方法;执行配置文件提供的init-method方法;使用已经初始化完毕的Bean对象;执行DisposableBean接口提供的destroy方法;执行配置文件提供的destroy-method方法
Spring的生命周期.
1.容器启动,实例化所有实现了BeanFactoyPostProcessor接口的类。他会在任何普通Bean实例化之前加载.
2.实例化剩下的Bean,对这些Bean进行依赖注入。
3.如果Bean有实现BeanNameAware的接口那么对这些Bean进行调用setBeanFactory()
4.如果Bean有实现BeanFactoryAware接口的那么对这些Bean进行调用
5.如果Bean有实现ApplicationContextAware接口的那么对这些Bean进行调用
6.如果配置有实现BeanPostProcessor的Bean,那么调用它的postProcessBeforeInitialization方法
7.如果Bean有实现InitializingBean接口的afterPropertiesSet(),那么对这些Bean进行调用
如果Bean类已实现org.springframework.beans.factory.InitializingBean接口,则执行他的afterProPertiesSet()方法
8.如果Bean配置有init属性(Bean定义文件中定义init-method),那么调用它属性中设置的方法
9.如果配置有实现BeanPostProcessor的Bean,那么调用它的postProcessAfterInitialization的ProcessaAfterInitialization()方法
10. Bean正常是使用
11. 调用DisposableBean接口的destory方法
在容器关闭时,如果Bean类有实现org.springframework.beans.factory.DisposableBean接口,则执行他的destroy()方法
12. 调用Bean定义的destory方法(Bean定义文件中定义destroy-method)
在容器关闭时,可以在Bean定义文件中使用"destroy-method"属性设定方法名称
3)线程实现方法
有三种:
(1)继承Thread类,重写run函数
class xx extends Thread{
public void run(){ Thread.sleep(1000)//线程休眠1000毫秒,sleep使线程进入Block状态,并释放资源
}}
开启线程:对象.start()//启动线程,run函数运行
(2)实现Runnable接口,重写run函数
开启线程:Thread t = new Thread(对象)//创建线程对象
调用:t.start()
(3)实现Callable接口,重写call函数
Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其它线程执行的任务。
Callable和Runnable有几点不同:
①Callable规定的方法是call(),而Runnable规定的方法是run().
②Callable的任务执行后可返回值,而Runnable的任务是不能返回值的
③call()方法可抛出异常,而run()方法是不能抛出异常的。
④运行Callable任务可拿到一个Future对象,Future表示异步计算的结果。它提供了检查计算是否完成的方法,以等
4)线程同步方法
分别是synchronized;wait、notify、notifyAll、sleep;
5)创建对象方法:
一、使用new创建对象。
二、调用Class类的newInstance方法,利用反射机制创建对象。
6)集群session如何共享?
session共享
session不可跨服务器而存在.下面给出几种session共享的解决方案.
第一种:客户端解决方法.把session加密后存在cookie中,每次session信息被写在客服端,然后经浏览器再次提交到服务器.即使两次请求在集群中的两台服务器上完成,也可以到达session共享.这种解决方法的优点是session信息不用存放在服务器端,大大减轻了服务器的压力.另一个优点是一个session中的两次或多次请求可以在一个群集中的多个服务器上完成,可以避免单端故障.目前,淘宝是采用的这种解决方案.
第二种:提供一个群集保存session共享信息.其他应用统统把自己的session信息存放到session群集服务器组.当应用系统需要session信息的时候直接到session群集服务器上读取.这种方式具有第一种方式的第二个优点.
第三种:配置负载均衡服务器,让用户的一个session在一个服务器完成.定时的备份session信息到salve上面.一台服务器down掉后,通过均衡服务器透明把用户的请求转发到群集中的其他服务器上,此时需要从salve上读取备份的session信息.
7)单例
第一种形式
public class Singleton {
private Singleton(){}
private static Singleton singleton =new Singleton();
public static Singleton getInstance(){
return singleton;
}
}
第二种形式:
public class Singleton {
private static Singleton instance = null;
public static synchronized Singleton getInstance() {
// 这个方法比上面有所改进,不用每次都进行生成对象,只是第一次
// 使用时生成实例,提高了效率!
if (instance == null)
instance = new Singleton();
return instance;
}
}
第三种:
public class Singleton {
private static class SingletonHolder{
private static Singleton instance = new Singleton();
}
private Singleton() {
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
}
第四种:
public enum Singleton {
INSTANCE;
public static Singleton getInstance(){ return INSTANCE; }
}
8)说出ArrayList,Vector, LinkedList的存储性能和特性
ArrayList和Vector都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢,Vector由于使用了synchronized方法(线程安全),通常性能上较ArrayList差,而LinkedList使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。
-------------------------------------------------------------------------------------------------
我们常用的创建一个类的实例(对象)的方法有以下两种:
一、使用new创建对象。
二、调用Class类的newInstance方法,利用反射机制创建对象。
如果字符串池有就获取,如果没有就创建。new一定会创建对象。
1)String s=new String("abc")创建了几个对象?2个。
2)String str="abc"; 毫无疑问,这行代码创建了一个String对象。
3)String a="abc"; String b="abc"; 那这里呢?答案还是一个。
4)String a="ab"+"cd"; 再看看这里呢?答案是三个。