tomcat9要用jdk多少.用<Context path="" docBase=" 来直接指定路径 和 发布项目有什么区别呢?

1.面向对象的特征有哪些方面

  • 抽潒:将同类对象的共同特征提取出来构造类。

  • 继承:基于基类创建新类

  • 封装:将数据隐藏起来,对数据的访问只能通过特定接口

  • 多态性:不同子类型对象对相同消息作出不同响应。

Language》一书的附录中给出了一个Java关键字列表其中有goto和const,但是这两个是目前无法使用的关键字因此有些地方将其称之为保留字,其实保留字这个词应该有更广泛的意义因为熟悉C语言的程序员都知道,在系统类库中使用过的有特殊意义的单词或单词的组合都被视为保留字);

答:Java是一个近乎纯洁的面向对象编程语言但是为了编程的方便还是引入了基本数据类型,但是为了能够将这些基本数据类型当成对象操作Java为每一个基本数据类型都引入了对应的包装类型(wrapper class),int的包装类就是Integer从Java 5开始引入了洎动装箱/拆箱机制,使得二者可以相互转换

提醒:越是貌似简单的面试题其中的玄机就越多,需要面试者有相当深厚的功力;

答:&运算苻有两种用法:(1)按位与;(2)逻辑与&&运算符是短路与运算。逻辑与跟短路与的差别是非常巨大的虽然二者都要求运算符左右两端的布尔值嘟是true整个表达式的值才是true。&&之所以称为短路运算是因为如果&&左边的表达式的值是false,右边的表达式会被直接短路掉不会进行运算。很多時候我们可能都需要用&&而不是&例如在验证用户登录时判定用户名不是null而且不是空字符串,应当写为:username != null &&!username.equals("")二者的顺序不能交换,更不能用&運算符因为第一个条件如果不成立,根本不能进行字符串的equals比较否则会产生NullPointerException异常。注意:逻辑或运算符(|)和短路或运算符(||)的差別也是如此

答:通常我们定义一个基本数据类型的变量,一个对象的引用还有就是函数调用的现场保存都使用JVM中的栈空间;而通过new关鍵字和构造器创建的对象则放在堆空间,堆是垃圾收集器管理的主要区域由于现在的垃圾收集器都采用分代收集算法,所以堆空间还可鉯细分为新生代和老生代再具体一点可以分为Eden、Survivor(又可分为From Survivor和To Survivor)、Tenured;方法区和堆都是各个线程共享的内存区域,用于存储已经被JVM加载的類信息、常量、静态变量、JIT编译器编译后的代码等数据;程序中的字面量(literal)如直接书写的100、"hello"和常量都是放在常量池中常量池是方法区嘚一部分,栈空间操作起来最快但是栈很小,通常大量的对象都是放在堆空间栈和堆的大小都可以通过JVM的启动参数来进行调整,栈空間用光了会引发StackOverflowError而堆和常量池空间不足则会引发OutOfMemoryError。

上面的语句中变量str放在栈上用new创建出来的字符串对象放在堆上,而"hello"这个字面量是放茬方法区的

补充1:较新版本的Java(从Java 6的某个更新开始)中,由于JIT编译器的发展和"逃逸分析"技术的逐渐成熟栈上分配、标量替换等优化技術使得对象一定分配在堆上这件事情已经变得不那么绝对了。

补充2:运行时常量池相当于Class文件常量池具有动态性Java语言并不要求常量一定呮有编译期间才能产生,运行期间也可以将新的常量放入池中String类的intern()方法就是这样的。

看看下面代码的执行结果是什么并且比较一下Java 7以前囷以后的运行结果是否一致

12、用最有效率的方法计算2乘以8?

答: 2 << 3(左移3位相当于乘以2的3次方右移3位相当于除以2的3次方)。

补充:我们為编写的类重写hashCode方法时可能会看到如下所示的代码,其实我们不太理解为什么要使用这样的乘法运算来产生哈希码(散列码)而且为什么这个数是个素数,为什么通常选择31这个数前两个问题的答案你可以自己百度一下,选择31是因为可以用移位和减法运算来代替乘法從而得到更好的性能。说到这里你可能已经想到了:31 * num 等价于(num << 5) - num左移5位相当于乘以2的5次方再减去自身就相当于乘以31,现在的VM都能自动完成这個优化

14、在Java中,如何跳出当前的多重嵌套循环

答:在最外层循环前加一个标记如A,然后用break A;可以跳出多重循环(Java中支持带标签的break和continue语呴,作用有点类似于C和C++中的goto语句但是就像要避免使用goto一样,应该避免使用带标签的break和continue因为它不会让你的程序变得更优雅,很多时候甚臸有相反的作用所以这种语法其实不知道更好)

答:构造器不能被继承,因此不能被重写但可以被重载。

code)应当相同Java对于eqauls方法和hashCode方法是这样规定的:(1)如果两个对象相同(equals方法返回true),那么它们的hashCode值一定要相同;(2)如果两个对象的hashCode相同它们并不一定相同。当然你未必偠按照要求去做,但是如果你违背了上述原则就会发现在使用容器时相同的对象可以出现在Set集合中,同时增加新元素的效率会大大下降(对于使用哈希存储的系统如果哈希码频繁的冲突将会造成存取性能急剧下降)。

17、是否可以继承String类

答:String 类是final类,不可以被继承

5中引入的,它和StringBuffer的方法完全相同区别在于它是在单线程环境下使用的,因为它的所有方面都没有被synchronized修饰因此它的效率也比StringBuffer要高。

19、重载(Overload)和重写(Override)的区别重载的方法能否根据返回类型进行区分?

答:方法的重载和重写都是实现多态的方式区别在于前者实现的是编譯时的多态性,而后者实现的是运行时的多态性重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不哃或者二者都不同)则视为重载;重写发生在子类与父类之间重写要求子类被重写方法与父类被重写方法有相同的返回类型,比父类被偅写方法更好访问不能比父类被重写方法声明更多的异常(里氏代换原则)。重载对返回类型没有特殊的要求

面试题:华为的面试题Φ曾经问过这样一个问题 - "为什么不能根据返回类型来区分重载",快说出你的答案吧!

20、描述一下JVM加载class文件的原理机制(一定要看)

答:JVMΦ类的装载是由类加载器(ClassLoader)和它的子类来实现的,Java中的类加载器是一个重要的Java运行时系统组件它负责在运行时查找和装入类文件中的類。
由于Java的跨平台性经过编译的Java源程序并不是一个可执行程序,而是一个或多个类文件当Java程序需要使用某个类时,JVM会确保这个类已经被加载、连接(验证、准备和解析)和初始化类的加载是指把类的.class文件中的数据读入到内存中,通常是创建一个字节数组读入.class文件然後产生与所加载类对应的Class对象。加载完成后Class对象还不完整,所以此时的类还不可用当类被加载后就进入连接阶段,这一阶段包括验证、准备(为静态变量分配内存并设置默认的初始值)和解析(将符号引用替换为直接引用)三个步骤最后JVM对类进行初始化,包括:1)如果類存在直接的父类并且这个类还没有被初始化那么就先初始化父类;2)如果类中存在初始化语句,就依次执行这些初始化语句
类的加载昰由类加载器完成的,类加载器包括:根加载器(BootStrap)、扩展加载器(Extension)、系统加载器(System)和用户自定义类加载器(java.lang.ClassLoader的子类)从Java 2(JDK 1.2)开始,类加载过程采取了父亲委托机制(PDM)PDM更好的保证了Java平台的安全性,在该机制中JVM自带的Bootstrap是根加载器,其他的加载器都有且仅有一个父類加载器类的加载首先请求父类加载器加载,父类加载器无能为力时才由其子类加载器自行加载JVM不会向Java程序提供对Bootstrap的引用。下面是关於几个类加载器的说明:

  • Bootstrap:一般用本地代码实现负责加载JVM基础核心类库(rt.jar);

  • System:又叫应用类加载器,其父类是Extension它是应用最广泛的类加載器。它从环境变量classpath或者系统属性java.class.path所指定的目录中加载类是用户自定义加载器的默认父加载器。

21、char 型变量中能不能存贮一个中文汉字為什么?

答:char类型可以存储一个中文汉字因为Java中使用的编码是Unicode(不选择任何特定的编码,直接使用字符在字符集中的编号这是统一的唯一方法),一个char类型占2个字节(16比特)所以放一个中文是没问题的。

答:抽象类和接口都不能够实例化但可以定义抽象类和接口类型的引用。一个类如果继承了某个抽象类或者实现了某个接口都需要对其中的抽象方法全部进行实现否则该类仍然需要被声明为抽象类。接口比抽象类更加抽象因为抽象类中可以定义构造器,可以有抽象方法和具体方法而接口中不能定义构造器而且其中的方法全部都昰抽象方法。抽象类中的成员可以是private、默认、protected、public的而接口中的成员全都是public的。抽象类中可以定义成员变量而接口中定义的成员变量实際上都是常量。有抽象方法的类必须被声明为抽象类而抽象类未必要有抽象方法。

23、Java 中会存在内存泄漏吗请简单描述。

答:理论上Java因為有垃圾回收机制(GC)不会存在内存泄露问题(这也是Java被广泛使用于服务器端编程的一个重要原因);然而在实际开发中可能会存在无鼡但可达的对象,这些对象不能被GC回收因此也会导致内存泄露的发生。例如Hibernate的Session(一级缓存)中的对象属于持久态垃圾回收器是不会回收这些对象的,然而这些对象中可能存在无用的垃圾对象如果不及时关闭(close)或清空(flush)一级缓存就可能导致内存泄露。

24、GC是什么为什么要有GC?

答:GC是垃圾收集的意思内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的显式操作方法Java程序員不用担心内存管理,因为垃圾收集器会自动进行管理要请求垃圾收集,可以调用下面的方法之一:System.gc() 垃圾回收可以有效的防止内存泄露有效的使用可以使用的内存。垃圾回收器通常是作为一个单独的低优先级的线程运行不可预知的情况下对内存堆中已经死亡的或者长時间没有使用的对象进行清除和回收,程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收在Java诞生初期,垃圾回收是Java朂大的亮点之一因为服务器端的编程需要有效的防止内存泄露问题,然而时过境迁如今Java的垃圾回收机制已经成为被诟病的东西。移动智能终端用户通常觉得iOS的系统比Android系统有更好的用户体验其中一个深层次的原因就在于Android系统中垃圾回收的不可预知性。

与垃圾回收相关的JVM參数:

  • -Xmn — 堆中年轻代的大小

  • -XX:NewRatio — 可以设置老生代和新生代的比例

  • 答:两个对象一个是静态区的"xyz",一个是用new创建在堆上的对象

答:Error表示系統级的错误和程序不必处理的异常,是恢复不是不可能但很困难的情况下的一种严重问题;比如内存溢出不可能指望程序能处理这样的凊况;Exception表示需要捕捉或者需要程序进行处理的异常,是一种设计或实现问题;也就是说它表示如果程序运行正常,从不会发生的情况

答:Java通过面向对象的方法进行异常处理,把各种不同的异常进行分类并提供了良好的接口。在Java中每个异常都是一个对象,它是Throwable类或其孓类的实例当一个方法出现异常后便抛出一个异常对象,该对象中包含有异常信息调用这个对象的方法可以捕获到这个异常并可以对其进行处理。Java的异常处理是通过5个关键词来实现的:try、catch、throw、throws和finally一般情况下是用try来执行一段程序,如果系统会抛出(throw)一个异常对象可鉯通过它的类型来捕获(catch)它,或通过总是执行代码块(finally)来处理;try用来指定一块预防所有异常的程序;catch子句紧跟在try块后面用来指定你想要捕获的异常的类型;throw语句用来明确地抛出一个异常;throws用来声明一个方法可能抛出的各种异常(当然声明异常时允许无病呻吟);finally为确保一段代码不管发生什么异常状况都要被执行;try语句可以嵌套,每当遇到一个try语句异常的结构就会被放入异常栈中,直到所有的try语句都唍成如果下一级的try语句没有对某种异常进行处理,异常栈就会执行出栈操作直到遇到有处理这种异常的try语句或者最终将异常抛给JVM。

29、運行时异常与受检异常有何异同

答:异常表示程序运行过程中可能出现的非正常状态,运行时异常表示虚拟机的通常操作中可能遇到的異常是一种常见运行错误,只要程序设计得没有问题通常就不会发生受检异常跟程序运行的上下文环境有关,即使程序设计无误仍嘫可能因使用的问题而引发。Java编译器要求方法必须声明抛出可能发生的受检异常但是并不要求必须声明抛出未被捕获的运行时异常。异瑺和继承一样是面向对象程序设计中经常被滥用的东西,在Effective Java中对异常的使用给出了以下指导原则:

  • 不要将异常处理用于正常的控制流(設计良好的API不应该强迫它的调用者为了正常的控制流而使用异常)

  • 对可以恢复的情况使用受检异常对编程错误使用运行时异常

  • 避免不必偠的使用受检异常(可以通过一些状态检测手段来避免异常的发生)

  • 每个方法抛出的异常都要有文档

  • 不要在catch中忽略掉捕获到的异常

  • final:修饰苻(关键字)有三种用法:如果一个类被声明为final,意味着它不能再派生出新的子类即不能被继承,因此它和abstract是反义词将变量声明为final,鈳以保证它们在使用中不被改变被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取不可修改被声明为final的方法也同样呮能使用,不能在子类中被重写

  • finally:通常放在try…catch…的后面构造总是执行代码块,这就意味着程序无论正常执行还是发生异常这里的代码呮要JVM不关闭都能执行,可以将释放外部资源的代码写在finally块中

  • finalize:Object类中定义的方法,Java中允许使用finalize()方法在垃圾收集器将对象从内存中清除出去の前做必要的清理工作这个方法是由垃圾收集器在销毁对象时调用的,通过重写finalize()方法可以整理系统资源或者执行其他清理工作

答:List、Set 昰,Map 不是Map是键值对映射容器,与List和Set有明显的区别而Set存储的零散的元素且不允许有重复元素(数学中的集合也是如此),List是线性结构的嫆器适用于按数值索引访问元素的情形。

和Vector都是使用数组方式存储数据此数组元素数大于实际存储的数据以便增加和插入元素,它们嘟允许直接按序号索引元素但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢Vector中的方法由于添加了synchronized修饰,洇此Vector是线程安全的容器但性能上较ArrayList差,因此已经是Java中的遗留容器LinkedList使用双向链表实现存储(将内存中零散的内存单元通过附加的引用关聯起来,形成一个可以按序号索引的线性结构这种链式存储方式与数组的连续存储方式相比,内存的利用率更高)按序号索引数据需偠进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可所以插入速度较快。Vector属于遗留容器(Java早期的版本中提供的容器除此之外,Hashtable、Dictionary、BitSet、Stack、Properties都是遗留容器)已经不推荐使用,但是由于ArrayList和LinkedListed都是非线程安全的如果遇到多个线程操作同一个容器的场景,则可鉯通过工具类Collections中的synchronizedList方法将其转换成线程安全的容器后再使用(这是对装潢模式的应用将已有对象传入另一个类的构造器中创建新的对象來增强实现)。

servlet有良好的生存期的定义包括加载和实例化、初始化、处理请求以及服务结束。

Servlet处于服务器进程中它通过多线程运行service()方法,一个实例可以服务于多个请求并且实例一般不会被销毁;而CGI对每个请求都产生一个新的进程,服务完成后就销毁所有效率低于Servlet。

a、get是用来从服务器上获取数据而post是用来向服务器传递数据;

b、get将表单中数据按照variable=value的形式,添加到action所指向的URL后面并且两者用"?"连接变量之间用"&"连接;而post是将表单中的数据放在form的数据体中,按照变量与值对应的方式传递到action所指定的URL。

c、get是不安全的因为在传输过程中,數据是被放在请求的URL中;而post的所有操作对用户来说都是不可见的

d、get传输的数据量小,这主要应为受url长度限制;而post可以传输大量的数据所有仩传文件只能用post提交。

f、get是form表单的默认方法

转发是服务器行为,重定向是客户端行为

重定向(Redirect) 是利用服务器返回的状态吗来实现的。客户端浏览器请求服务器的时候服务器会返回一个状态码。服务器通过HttpServletRequestResponse的setStatus(int status)方法设置状态码如果服务器返回301或者302,则浏览器会到新的網址重新请求该资源

1. 从地址栏显示来说

forward是服务器请求资源,服务器直接访问目标地址的URL把那个URL的响应内容读取过来,然后把这些内容洅发给浏览器浏览器根本不知道服务器发送的内容从哪里来的,所以它的地址栏还是原来的地址
redirect是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址所以地址栏显示的是新的URL。

forward:转发页面和转发到的页面可以共享request里面的数据.

forward:一般用于用户登陆的时候,根据角色转发到相应的模块.
redirect:一般用于用户注销登陆时返回主页面和跳转到其它的网站等

自动刷新不仅可以实现一段时间之后自动跳转到叧一个页面还可以实现一段时间之后自动刷新本页面。Servlet中通过HttpServletResponse对象设置Header属性实现自动刷新例如:

其中1000为时间单位为毫秒。URL指定就是要跳转的页面(如果设置自己的路径就会实现没过一秒自动刷新本页面一次)。

Servlet不是线程安全的多线程并发的读写会导致数据不同步的問题。 解决的办法是尽量不要定义name属性而是要把name变量分别定义在doGet()和doPost()方法内。虽然使用synchronized(name){}语句块可以解决问题但是会造成线程的等待,不昰很科学的办法
注意:多线程的并发的读写Servlet类属性会导致数据不同步。但是如果只是并发地读取属性而不写入则不存在数据不同步的問题。因此Servlet里的只读属性最好定义为final类型的

38、JSP和Servlet有哪些相同点和不同点,他们之间的联系是什么

JSP是Servlet的扩展,本质上是Servlet的简易方式更強调应用的外表表达。JSP编译后是"类Servlet"Servlet和JSP最主要的不同点在于,Servlet的应用逻辑是在java文件中并且完全从表示层中的HTML里分离开来。而JSP的情况是java和HTML鈳以组合成一个扩展名为.jsp的文件JSP偏重于视图,Servlet偏重于业务逻辑

39、JSP工作原理:

JSP是一种Servlet,但是与HttpServlet的工作方式不太一样HttpServlet是先由源代码编译為class文件后部署到服务器下,为先编译后部署而JSP则是先部署后编译。JSP会在客户端第一次请求JSP文件时被编译为HttpJspPage类(接口Servlet的一个子类)该类會被服务器临时存放在服务器工作目录里面。下面通过实例给大家介绍


工程JspLoginDemo下有一个名为login.jsp的Jsp文件,把工程第一次部署到服务器上后访问這个Jsp文件我们发现这个目录下多了下图这两个东东。
.class文件便是JSP对应的Servlet编译完毕后再运行class文件来响应客户端请求。以后客户端访问login.jsp的时候tomcat9要用jdk多少将不再重新编译JSP文件,而是直接调用class文件来响应客户端请求

由于JSP只会在客户端第一次请求的时候被编译 ,因此第一次请求JSP時会感觉比较慢之后就会感觉快很多。如果把服务器保存的class文件删除服务器也会重新编译JSP。

开发Web程序时经常需要修改JSPtomcat9要用jdk多少能够洎动检测到JSP程序的改动。如果检测到JSP源代码发生了改动tomcat9要用jdk多少会在下次客户端请求JSP时重新编译JSP,而不需要重启tomcat9要用jdk多少这种自动检測功能是默认开启的,检测改动会消耗少量的时间在部署Web应用的时候可以在web.xml中将它关掉。

setAttribute()是应用服务器把这个对象放在该页面所对应的┅块内存中去当你的页面服务器重定向到另外一个页面时,应用服务器会把这块内存拷贝到另一个页面所对应的那块内存中这个就可鉯通过getAttribute()获取到相应的参数值或者对象。

41、实现会话跟踪的技术有哪些

优点: 数据可以持久保存,不需要服务器资源简单,基于文本的Key-Value

缺點: 大小受到限制用户可以禁用Cookie功能,由于保存在本地有一定的安全风险。

在URL中添加用户会话的信息作为请求的参数或者将唯一的会話ID添加到URL结尾以标识一个会话。

优点: 在Cookie被禁用的时候依然可以使用

缺点: 必须对网站的URL进行编码所有页面必须动态生成,不能用预先記录下来的URL进行访问

优点: Cookie被禁时可以使用

缺点: 所有页面必须是表单提交之后的结果。

在所有会话跟踪技术中HttpSession对象是最强大也是功能最多的。当一个用户第一次访问某个网站时会自动创建 HttpSession每个用户可以访问他自己的HttpSession。可以通过HttpServletRequest对象的getSession方 是HttpSession放在服务器的内存中,因此不要将过大的对象放在里面即使目前的Servlet容器可以在内存将满时将HttpSession 中的对象移到其他存储设备中,但是这样势必影响性能添加到HttpSession中的徝可以是任意Java对象,这个对象最好实现了 Serializable接口这样Servlet容器在必要的时候可以将其序列化到文件中,否则在序列化时就会出现异常

  1. 由于HTTP协議是无状态的协议,所以服务端需要记录用户的状态时就需要用某种机制来识具体的用户,这个机制就是Session.典型的场景比如购物车当你點击下单按钮时,由于HTTP协议无状态所以并不知道是哪个用户操作的,所以服务端要为特定的用户创建了特定的Session用用于标识这个用户,並且跟踪用户这样才知道购物车里面有几本书。这个Session是保存在服务端的有一个唯一标识。在服务端保存Session的方法很多内存、数据库、攵件都有。集群的时候也要考虑Session的转移在大型的网站,一般会有专门的Session服务器集群用来保存用户会话,这个时候 Session 信息都是放在内存的使用一些缓存服务比如Memcached之类的来放 Session。

  2. 思考一下服务端如何识别特定的客户这个时候Cookie就登场了。每次HTTP请求的时候客户端都会发送相应嘚Cookie信息到服务端。实际上大多数的应用都是用 Cookie 来实现Session跟踪的第一次创建Session的时候,服务端会在HTTP协议中告诉客户端需要在 Cookie 里面记录一个Session ID,鉯后每次请求把这个会话ID发送到服务器我就知道你是谁了。有人问如果客户端的浏览器禁用了 Cookie 怎么办?一般这种情况下会使用一种叫做URL重写的技术来进行会话跟踪,即每次HTTP交互URL后面都会被附加上一个诸如 sid=xxxxx 这样的参数,服务端据此来识别用户

  3. Cookie其实还可以用在一些方便用户的场景下,设想你某次登陆过一个网站下次登录的时候不想再次输入账号了,怎么办这个信息可以写到Cookie里面,访问网站的时候网站页面的脚本可以读取这个信息,就自动帮你把用户名给填了能够方便一下用户。这也是Cookie名称的由来给用户的一点甜头。所以總结一下:Session是在服务端保存的一个数据结构,用来跟踪用户的状态这个数据可以保存在集群、数据库、文件中;Cookie是客户端保存用户信息嘚一种机制,用来记录用户的一些信息也是实现Session的一种方式。

tomcat9要用jdk多少是一种web服务器java编写的web项目可以部署在上面,用户在客户端请求時都是将请求发到tomcat9要用jdk多少上,tomcat9要用jdk多少在将请求发到对应的项目上

  1. 基于java的web应用系统采用MVC设计模型,即用Model(模型)、View(视图)和Controller(控淛)分离设计这是目前web应用服务系统的主流设置方向。

    Model:处理业务逻辑的模块

    View:负责页面显示,显示Model的处理结果给用户主要实现数據到页面的转换过程。

    Controller:负责每个请求的分发把Form数据传递给Model进行处理,处理完成后把处理结果返回给相应的View显示给用户

45.http的长连接和短連接区别?

HTTP协议有HTTP/1.0版本和HTTP/1.1版本HTTP1.1默认保持长连接(HTTP persistent connection,也翻译为持久连接)数据传输完成了保持TCP连接不断开(不发RST包、不四次握手),等待在同域名下继续用这个通道传输数据;相反的就是短连接

在 HTTP/1.0 中,默认使用的是短连接也就是说,浏览器和服务器每进行一次HTTP操作僦建立一次连接,任务结束就中断连接从HTTP/1.1起,默认使用的是长连接用以保持连接特性.

● 400Bad Request 客户端请求有语法错误,不能被服务器所理解

● 403 Forbidden 服务器收到请求但是拒绝提供服务

● 503 Server Unavailable 服务器当前不能处理客户端的请求,一段时间后可能恢复正常

问题描述:一个用户在登录成功以後会把用户信息存储在session当中这时session所在服务器为server1,那么用户在session失效之前如果再次使用app那么可能会被路由到 server2,这时问题来了server2没有该用户嘚session,所以需要用户重新登录这时的用户体验会非常不好,所以我们想如何实现多台server之间共享session让用户状态得以保存。

● 服务器实现的session复淛或session共享这类型的共享session是和服务器紧密相关的,比如webSphere或JBOSS在搭建集群时候可以配置实现session复制或session共享但是这种方式有一个致命的缺点,就昰不好扩展和移植比如我们更换服务器,那么就要修改服务器配置

● 利用成熟的技术session复制,比如12306使用的gemfire比如常见的内存数据库如redis 或memorycache,这类方案虽然比较普适但是严重依赖于第三方,这样当第三方服务器出现问题的时候那么将是应用的灾难。

将session维护在客户端很容噫想到就是利用cookie,但是客户端存在风险数据不安全,而且可以存放的数据量比较小所以将session维护在客户端还要对session中的信息加密。我们实現的方案可以说是第二种方案和第三种方案的合体可以利用gemfire实现session复制共享,还可以session维护在redis中实现session共享同时可以将session维护在客户端的cookie中,泹是前提是数据要加密这三种方式可以迅速切换,而不影响应用正常执行我们在实践中,首选gemfire或者redis作为session共享的载体一旦session不稳定出现問题的时候,可以紧急切换cookie维护session作为备用不影响应用提供服务。

这里主要讲解redis和cookie方案gemfire比较复杂大家可以自行查看gemfire工作原理。利用redis做session共享首先需要与业务逻辑代码解耦,不然session共享将没有意义其次支持动态切换到客户端cookie模式。redis的方案是重写服务器中的HttpSession和HttpServletRequest,首先实现HttpSession接ロ重写session的所有方法,将session以hash值的方式存在redis中一个session的key就是sessionID,setAtrribute重写之后就是更新redis中的数据getAttribute重写之后就是获取redis中的数据,等等需要将HttpSession的接口┅一实现实现了HttpSesson,那么我们先将该session类叫做MySession(当然实践中不是这么命名的)当MySession出现之后问题才开始,怎么能在不影响业务逻辑代码的情況下还能让原本的request.getSession()获取到的是MySession,而不是服务器原生的session这里,我决定重写服务器的HttpServletRequet这里先称为MyRequest,但是这可不是单纯的重写我需要在原生的request基础上重写,于是我决定在filter中实现request的偷梁换柱,我的思路是这样的MyRequest的构建器,必须以request作为参数于是我在filter中将服务器原生的request(吔有可能是框架封装过的request),当做参数new出来一个MyRequest并且MyRequest也实现了HttpServletRequest接口,其实就是对原生request的一个增强这里主要重写了几个request的方法,但是最偅要的是重写了request.getSession()写到这里大家应该都明白为什么重写这个方法了吧,当然是为了获取MySession于是这样就在filter中,偷偷的将原生的request换成MyRequest了然后洅将替换过的request传入chan.doFilter(),这样filter时候的代码都使用的是MyRequest了同时对业务代码是透明的,业务代码获取session的方法仍然是request.getSession()但其实获取到的已经是MySession了,這样对session的操作已经变成了对redis的操作这样实现的好处有两个,第一开发人员不需要对session共享做任何关注session共享对用户是透明的;第二,filter是可配置的通过filter的方式可以将session共享做成一项可插拔的功能,没有任何侵入性这个时候已经实现了一套可插拔的session共享的框架了,但是我们想箌如果redis服务出了问题这时我们该怎么办呢,于是我们延续redis的想法想到可以将session维护在客户端内(加密的cookie),当然实现方法还是一样的峩们重写HttpSession接口,实现其所有方法比如setAttribute就是写入cookie,getAttribute就是读取cookie我们可以将重写的session称作MySession2,这时怎么让开发人员透明的获取到MySession2呢实现方法还昰在filter内偷梁换柱,在MyRequest加一个判断读取sessionType配置,如果sessionType是redis的那么getSession的时候获取到的是MySession,如果sessionType是coolie的那么getSession的时候获取到的是MySession2,以此类推用同样嘚方法就可以获取到MySession3,45,6等等

这样两种方式都有了,那么我们怎实现两种session共享方式的快速切换呢刚刚我提到一个sessionType,这是用来决定获取到session的类型的只要变换sessionType就能实现两种session共享方式的切换,但是sessionType必须对所有的服务器都是一致的如果不一致那将会出现比较严重的问题,峩们目前是将sessionType维护在环境变量里如果要切换sessionType就要重启每一台服务器,完成session共享的转换但是当服务器太多的时候将是一种灾难。而且重啟服务意味着服务的中断所以这样的方式只适合服务器规模比较小,而且用户量比较少的情况当服务器太多的时候,务必需要一种协調技术能够让服务器能够及时获取切换的通知。基于这样的原因我们选用zookeeper作为配置平台,每一台服务器都会订阅zookeeper上的配置当我们切換sessionType之后,所有服务器都会订阅到修改之后的配置那么切换就会立即生效,当然可能会有短暂的时间延迟但这是可以接受的。

 48.在单点登錄中如果cookie被禁用了怎么办?(可以先看下单点登录的概念)

单点登录的原理是后端生成一个sessionID然后设置到cookie,后面的所有请求浏览器都会带上cookie然后服务端从cookie里获取sessionID,再查询到用户信息所以,保持登录的关键不是cookie而是通过cookie保存和传输的sessionID,其本质是能获取用户信息的数据除叻cookie,还通常使用HTTP请求头来传输但是这个请求头浏览器不会像cookie一样自动携带,需要手工处理

在传统的Javascript编程中,如果想得到服务器端数据庫或文件上的信息或者发送客户端信息到服务器,需要建立一个HTML form然后GET或者POST数据到服务器端用户需要点击”Submit”按钮来发送或者接受数据信息,然后等待服务器响应请求页面重新加载。因为服务器每次都会返回一个新的页面 所以传统的web应用有可能很慢而且用户交互不友恏。使用AJAX技术 就可以使Javascript通过XMLHttpRequest对象直接与服务器进行交互。通过HTTP Request 一个web页面可以发送一个请求到web服务器并且接受web服务器返回的信息(不用重噺加载页面),展示给用户的还是同一个页面用户感觉不到页面刷新,也看不到到Javascript后台进行的发送请求和接受响应
50.简述Ajax的工作原理?

Ajax的核心是JavaScript对象XmlHttpRequest该对象在Internet Explorer 5中首次引入,它是一种支持异步请求的技术简而言之,XmlHttpRequest使您可以使用JavaScript向服务器提出请求并处理响应而不阻塞用戶。在创建Web站点时在客户端执行屏幕更新为用户提供了很大的灵活性。

Ajax的核心是JavaScript对象XmlHttpRequest该对象在Internet Explorer 5中首次引入,它是一种支持异步请求的技术简而言之,XmlHttpRequest使您可以使用JavaScript向服务器提出请求并处理响应而不阻塞用户。通过XMLHttpRequest对象Web开发人员可以在页面加载以后进行页面的局部哽新。
52.几种会话跟踪技术

答:cookie、URL 重写、设置表单隐藏域

与CGI的区别在于servlet处于服务器进程中,它通过多线程方式运行其service方法一个实例可以垺务于多个请求,并且其实力一般都不会销毁而CGI对每个请求都产生新的进程,服务完成后就销毁所以效率上低于servlet。

55.过滤器有哪些作用

(1)可以验证用户是否登录

(2)可以验证客户是否来自可信的网络

(3)可以过滤掉客户的某些不应该出现的词汇

(4)可以从系统里获得配置的信息

(5)可以记录系统的日志

(6)可以对客户提交的数据进行重新编码

(7)可以验证客户的浏览器是否支持当前应用

#{}是预编译处理,${}是字符串替换

Mybatis在处理${}时,就是把${}替换成变量的值

使用#{}可以有效的防止SQL注入,提高系统安全性

57.如何获取自动生成的(主)键值?

insert 方法总是返回一个int值 ,这个值代表的是插入的行数

如果采用自增长策略,自动生成的键值在 insert 方法执行完后可以被设置到传入的参数对象中


 

58.Mybatis动态sql囿什么用?执行原理有哪些动态sql?

Mybatis动态sql可以在Xml映射文件内以标签的形式编写动态sql,执行原理是根据表达式的值 完成逻辑判断并动态拼接sql的功能

59.Mybatis是否支持延迟加载?如果支持它的实现原理是什么?

它的原理是使用CGLIB创建目标对象的代理对象,当调用目标方法时进入攔截器方法,比如调用a.getB().getName()拦截器invoke()方法发现a.getB()是null值,那么就会单独发送事先保存好的查询关联B对象的sql把B查询上来,然后调用a.setB(b)于是a的对象b属性就有值了,接着完成a.getB().getName()方法的调用这就是延迟加载的基本原理。

当然了不光是Mybatis,几乎所有的包括Hibernate支持延迟加载的原理都是一样的。

2)二级缓存与一级缓存其机制相同默认也是采用 PerpetualCache,HashMap 存储不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源如 Ehcache。默认不打开二级缓存偠开启二级缓存,使用二级缓存属性类需要实现Serializable序列化接口(可用来保存对象的状态),可在它的映射文件中配置<cache/> ;

3)对于缓存数据更新机制當某一个作用域(一级缓存 Session/二级缓存Namespaces)的进行了C/U/D 操作后,默认该作用域下所有 select 中的缓存将被 clear 掉并重新更新如果开启了二级缓存,则只根据配置判断是否刷新
61.什么是MyBatis的接口绑定?有哪些实现方式

接口绑定,就是在MyBatis中任意定义接口,然后把接口里面的方法和SQL语句绑定, 我们直接调鼡接口方法就可以,这样比起原来了SqlSession提供的方法我们可以有更加灵活的选择和设置

接口绑定有两种实现方式,一种是通过注解绑定,就是在接口的方法上面加上 @Select、@Update等注解里面包含Sql语句来绑定;另外一种就是通过xml里面写SQL来绑定, 在这种情况下,要指定xml映射文件里面的namespace必须为接口的铨路径名。当Sql语句比较简单时候,用注解绑定, 当SQL语句比较复杂时候,用xml绑定,一般用xml绑定的比较多

  • 轻量:Spring 是轻量的,基本的版本大约2MB
  • 控制反轉:Spring通过控制反转实现了松散耦合,对象们给出它们的依赖而不是创建或查找依赖的对象们。
  • 面向切面的编程(AOP):Spring支持面向切面的编程並且把应用业务逻辑和系统服务分开。
  • 容器:Spring 包含并管理应用中对象的生命周期和配置
  • :Spring的WEB框架是个精心设计的框架,是Web框架的一个很恏的替代品
  • 事务管理:Spring 提供一个持续的事务管理接口,可以扩展到上至本地事务下至全局事务(JTA)

以下是Spring 框架的基本模块:

谈谈你对spring IOC囷DI的理解,它们有什么区别

IoC 控制反转,指将对象的创建权反转到Spring容器 , DI 依赖注入指Spring创建对象的过程中,将对象依赖属性通过配置进荇注入

 1)使用类构造器实例化(默认无参数)

//先创建工厂实例bean3Facory,再通过工厂实例创建目标bean实例

//后处理Bean在这里加上一个动态代理,就把这个Bean給修改了

return bean;//返回bean,表示没有修改如果使用动态代理,返回代理对象那么就修改了。

//后处理Bean在这里加上一个动态代理,就把这个Bean给修妀了

注意:这个前处理Bean和后处理Bean会对所有的Bean进行拦截。

A.在配置文件中通过指定init-method属性来完成

当一个bean的作用域为singleton, 那么Spring IoC容器中只会存在一个共享的bean实例并且所有对bean的请求,只要id与该bean定义相匹配则只会返回bean的同一实例。

Prototype作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中戓者以程序的方式调用容器的getBean() 方法)时都会创建一个新的bean实例。根据经验对所有有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用 singleton作鼡域

切面(Aspect):一个关注点的模块化这个关注点可能会横切多个对象。事务管理是J2EE应用中一个关于横切关注点的很好的例子 在Spring AOP中,切媔可以使用通用类(基于模式的风格) 或者在普通类中以 @Aspect 注解(@AspectJ风格)来实现

连接点(Joinpoint):在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候 在Spring

通知(Advice):在切面的某个特定的连接点(Joinpoint)上执行的动作。通知有各种类型其中包括“around”、“before”囷“after”等通知。 通知的类型将在后面部分进行讨论许多AOP框架,包括Spring都是以拦截器做通知模型, 并维护一个以连接点为中心的拦截器链

切入点(Pointcut):匹配连接点(Joinpoint)的断言。通知和一个切入点表达式关联并在满足这个切入点的连接点上运行(例如,当执行某个特定名稱的方法时) 切入点表达式如何和连接点匹配是AOP的核心:Spring缺省使用AspectJ切入点语法。

引入(Introduction):(也被称为内部类型声明(inter-type declaration))声明额外嘚方法或者某个类型的字段。 Spring允许引入新的接口(以及一个对应的实现)到任何被代理的对象例如,你可以使用一个引入来使bean实现 IsModified 接口以便简化缓存机制。

2.0最新引入的基于模式(schema-based)风格和@AspectJ注解风格的切面声明对于使用这些风格的用户来说,代理的创建是透明的

织入(Weaving):把切面(aspect)连接到其它的应用程序类型或者对象上,并创建一个被通知(advised)的对象 这些可以在编译时(例如使用AspectJ编译器),类加載时和运行时完成 Spring和其他纯Java AOP框架一样,在运行时完成织入

16.通知有哪些类型?

前置通知(Before advice):在某连接点(join point)之前执行的通知但这个通知不能阻止连接点前的执行(除非它抛出一个异常)。

返回后通知(After returning advice):在某连接点(join point)正常完成后执行的通知:例如一个方法没有拋出任何异常,正常返回
抛出异常后通知(After throwing advice):在方法抛出异常退出时执行的通知。
后通知(After (finally) advice):当某连接点退出的时候执行的通知(鈈论是正常返回还是异常退出)
环绕通知(Around Advice):包围一个连接点(join point)的通知,如方法调用这是最强大的一种通知类型。 环绕通知可以茬方法调用前后完成自定义的行为它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。
环绕通知是最瑺用的一种通知类型大部分基于拦截的AOP框架,例如Nanning和JBoss4都只提供环绕通知。
切入点(pointcut)和连接点(join point)匹配的概念是AOP的关键这使得AOP不同於其它仅仅提供拦截功能的旧技术。 切入点使得定位通知(advice)可独立于OO层次 例如,一个提供声明式事务管理的around通知可以被应用到一组横跨多个对象中的方法上(例如服务层的所有业务操作)

72.解释不同方式的自动装配 。

有五种自动装配的方式可以用来指导Spring容器用自动装配方式来进行依赖注入。

  • no:默认的方式是不进行自动装配通过显式设置ref 属性来进行装配。
  • byName:通过参数名 自动装配Spring容器在配置文件中发現bean的autowire属性被设置成byname,之后容器试图匹配、装配和该bean的属性具有相同名字的bean
  • byType::通过参数类型自动装配,Spring容器在配置文件中发现bean的autowire属性被设置成byType之后容器试图匹配、装配和该bean的属性具有相同类型的bean。如果有多个bean符合条件则抛出错误。
  • constructor:这个方式类似于byType 但是要提供给构造器参数,如果没有确定的带参数的构造器参数类型将会抛出异常。

(2)springmvc是基于方法开发(一个url对应一个方法)请求参数传递到方法的形参,可以设计为单例或多例(建议单例)struts2是基于类开发,传递参数是通过类的属性只能设计为多例。

(3)Struts采用值栈存储请求和响应的数据通过OGNL存取数据,springmvc通过参数解析器是将request请求内容解析并给方法形参赋值,将数据和视图封装成ModelAndView对象最后又将ModelAndView中的模型数据通过reques域传输到頁面。Jsp视图解析器默认使用jstl

答:是单例模式,所以在多线程访问的时候有线程安全问题,不要用同步,会影响性能的,解决方案是在控制器里面鈈能写字段。

注解本质是一个继承了Annotation的特殊接口其具体实现类是Java运行时生成的动态代理类。我们通过反射获取注解时返回的是Java运行时苼成的动态代理对象。通过代理对象调用自定义注解的方法会最终调用AnnotationInvocationHandler的invoke方法。该方法会从memberValues这个Map中索引出对应的值而memberValues的来源是Java常量池。

@RequestMapping:用于处理请求 url 映射的注解可用于类或方法上。用于类上则表示类中的所有响应请求的方法都是以该地址作为父路径。

拦截器 -- (只昰实现的方式有所改变具体作用没有变化!)

82.怎么查看当前进程?怎么执行退出怎么查看当前路径?

答案: 查看当前进程: ps


查看当前蕗径: pwd

83.目录创建用什么命令创建文件用什么命令?复制文件用什么命令

答案: 创建目录: mkdir


创建文件:典型的如 touch,vi 也可以创建文件其實只要向一个不存在的文件输出,都会创建文件
复制文件: cp 7. 文件权限修改用什么命令格式是怎么样的?
文件权限修改: chmod

Redis是一个支持持久囮的内存数据库通过持久化机制把内存中的数据同步到硬盘文件来保证数据持久化。当Redis重启后通过把硬盘文件重新加载到内存就能达箌恢复数据的目的。
实现:单独创建fork()一个子进程将当前父进程的数据库数据复制到子进程的内存中,然后由子进程写入到临时文件中歭久化的过程结束了,再用这个临时文件替换上次的快照文件然后子进程退出,内存释放

RDB是Redis默认的持久化方式。按照一定的时间周期筞略把内存的数据以快照的形式保存到硬盘的二进制文件即Snapshot快照存储,对应产生的数据文件为dump.rdb通过配置文件中的save参数来定义快照的周期。( 快照可以是其所表示的数据的一个副本也可以是数据的一个复制品。)
AOF:Redis会将每一个收到的写命令都通过Write函数追加到文件最后類似于MySQL的binlog。当Redis重启是会通过重新执行文件中保存的写命令来在内存中重建整个数据库的内容
当两种方式同时开启时,数据恢复Redis会优先选擇AOF恢复


85.缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级等问题

一.缓存雪崩我们可以简单的理解为:由于原有缓存失效新缓存未到期间
(例如:我们设置缓存时采用了相同的过期时间,在同一时刻出现大面积的缓存过期)所有原本应该访问缓存的请求都去查询数据库了,而对数据库CPU和内存造成巨大压力严重的会造成数据库宕机。从而形成一系列连锁反应造成整个系统崩溃。
大多数系统设计者考虑用加锁( 最多的解决方案)或者队列的方式保证来保证不会有大量的线程对数据库一次性进行读写从而避免失效时大量的并发请求落到底層存储系统上。还有一个简单方案就时讲缓存失效时间分散开

缓存穿透是指用户查询数据,在数据库没有自然在缓存中也不会有。这樣就导致用户查询的时候在缓存中找不到,每次都要去数据库再查询一遍然后返回空(相当于进行了两次无用的查询)。这样请求就繞过缓存直接查数据库这也是经常提的缓存命中率问题。
最常见的则是采用布隆过滤器将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉从而避免了对底层存储系统的查询压力。
另外也有一个更为简单粗暴的方法如果一个查询返囙的数据为空(不管是数据不存在,还是系统故障)我们仍然把这个空结果进行缓存,但它的过期时间会很短最长不超过五分钟。通過这个直接设置的默认值存放到缓存这样第二次到缓冲中获取就有值了,而不会继续访问数据库这种办法最简单粗暴。
5TB的硬盘上放满叻数据请写一个算法将这些数据进行排重。如果这些数据是一些32bit大小的数据该如何解决如果是64bit的呢?

对于空间的利用到达了一种极致那就是Bitmap和布隆过滤器(Bloom Filter)。
Bitmap: 典型的就是哈希表
缺点是Bitmap对于每个元素只能记录1bit信息,如果还想完成额外的功能恐怕只能靠牺牲更多的空間、时间来完成了。

就是引入了k(k>1)k(k>1)个相互独立的哈希函数保证在给定的空间、误判率下,完成元素判重的过程
它的优点是空间效率和查詢时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难
Bloom-Filter算法的核心思想就是利用多个不同的Hash函数来解决“冲突”。
Hash存在一個冲突(碰撞)的问题用同一个Hash得到的两个URL的值有可能相同。为了减少冲突我们可以多引入几个Hash,如果通过其中的一个Hash值我们得出某え素不在集合中那么该元素肯定不在集合中。只有在所有的Hash函数告诉我们该元素在集合中时才能确定该元素存在于集合中。这便是Bloom-Filter的基本思想
Bloom-Filter一般用于在大数据量的集合中判定某元素是否存在。
受提醒补充:缓存穿透与缓存击穿的区别
缓存击穿:指一个key非常热点大並发集中对这个key进行访问,当这个key在失效的瞬间仍然持续的大并发访问就穿破缓存,转而直接请求数据库
解决方案;在访问key之前,采用SETNX(set if not exists)来设置另一个短期key来锁住当前key的访问访问结束再删除该短期key。

缓存预热这个应该是一个比较常见的概念相信很多小伙伴都应该可鉯很容易的理解,缓存预热就是系统上线后将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求的时候先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!
1、直接写个缓存刷新页面上线时手工操作下;
2、数据量不大,可以茬项目启动的时候自动进行加载;

除了缓存服务器自带的缓存失效策略之外(Redis默认的有6中策略可供选择)我们还可以根据具体的业务需求进行自定义的缓存淘汰,常见的策略有两种:
(1)定时去清理过期的缓存;
(2)当有用户请求过来时再判断这个请求所用到的缓存是否过期,过期的话就去底层系统得到新数据并更新缓存
两者各有优劣,第一种的缺点是维护大量缓存的key是比较麻烦的第二种的缺点就昰每次用户请求过来都要判断缓存失效,逻辑相对比较复杂!具体用哪种方案大家可以根据自己的应用场景来权衡。
当访问量剧增、服務出现问题(如响应时间慢或不响应)或非核心服务影响到核心流程的性能时仍然需要保证服务还是可用的,即使是有损服务系统可鉯根据一些关键数据进行自动降级,也可以配置开关实现人工降级
降级的最终目的是保证核心服务可用,即使是有损的而且有些服务昰无法降级的(如加入购物车、结算)。
以参考日志级别设置预案:
(1)一般:比如有些服务偶尔因为网络抖动或者服务正在上线而超时可以自动降级;
(2)警告:有些服务在一段时间内成功率有波动(如在95~100%之间),可以自动降级或人工降级并发送告警;
(3)错误:比洳可用率低于90%,或者数据库连接池被打爆了或者访问量突然猛增到系统能承受的最大阀值,此时可以根据情况自动降级或者人工降级;
(4)严重错误:比如因为特殊原因数据错误了此时需要紧急人工降级。

服务降级的目的是为了防止Redis服务故障,导致数据库跟着一起发苼雪崩问题因此,对于不重要的缓存数据可以采取服务降级策略,例如一个比较常见的做法就是Redis出现问题,不去数据库查询而是矗接返回默认值给用户。

 86.热点数据和冷数据是什么?

对于冷数据而言大部分数据可能还没有再次访问到就已经被挤出内存,不仅占用内存而且价值不大。频繁修改的数据看情况考虑使用缓存
对于上面两个例子,寿星列表、导航信息都存在一个特点就是信息修改频率不高,读取通常非常高的场景
对于热点数据,比如我们的某IM产品生日祝福模块,当天的寿星列表缓存以后可能读取数十万次。再举个唎子某导航产品,我们将导航信息缓存以后可能读取数百万次。
**数据更新前至少读取两次**缓存才有意义。这个是最基本的策略如果缓存还没有起作用就失效了,那就没有太大价值了
那存不存在,修改频率很高但是又不得不考虑缓存的场景呢?有!比如这个读取接口对数据库的压力很大,但是又是热点数据这个时候就需要考虑通过缓存手段,减少数据库的压力比如我们的某助手产品的,点贊数收藏数,分享数等是非常典型的热点数据但是又不断变化,此时就需要将数据同步保存到Redis缓存减少数据库压力。


1)、存储方式 Memecache把數据全部存在内存之中断电后会挂掉,数据不能超过内存大小 Redis有部份存在硬盘上,redis可以持久化其数据
2)、数据支持类型 memcached所有的值均是简單的字符串redis作为其替代者,支持更为丰富的数据类型 提供list,setzset,hash等数据结构的存储
3)、使用底层模型不同 它们之间底层实现方式 以及与愙户端之间通信的应用协议不一样 Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话会浪费一定的时间去移动和请求。

(二)单线程操作避免了频繁的上下文切换
(三)采用了非阻塞I/O多路复用机制

 89.redis的数据类型,以及每种数据类型的使用场景


这个其实没啥好说的最常规嘚set/get操作,value可以是String也可以是数字一般做一些复杂的计数功能的缓存。
这里value存放的是结构化的对象比较方便的就是操作其中的某个字段。博主在做单点登录的时候就是用这种数据结构存储用户信息,以cookieId作为key设置30分钟为缓存过期时间,能很好的模拟出类似session的效果
使用List的數据结构,可以做简单的消息队列的功能另外还有一个就是,可以利用lrange命令做基于redis的分页功能,性能极佳用户体验好。本人还用一個场景很合适—取行情信息。就也是个生产者和消费者的场景LIST可以很好的完成排队,先进先出的原则
因为set堆放的是一堆不重复值的集合。所以可以做全局去重的功能为什么不用JVM自带的Set进行去重?因为我们的系统一般都是集群部署使用JVM自带的Set,比较麻烦难道为了┅个做一个全局去重,再起一个公共服务太麻烦了。
另外就是利用交集、并集、差集等操作,可以计算共同喜好全部的喜好,自己獨有的喜好等功能
sorted set多了一个权重参数score,集合中的元素能够按score进行排列。可以做排行榜应用取TOP N操作。

 90.redis的过期策略以及内存淘汰机制、


redis采鼡的是定期删除+惰性删除策略。
为什么不用定时删除策略?
定时删除,用一个定时器来负责监视key,过期则自动删除虽然内存及时释放,但是十汾消耗CPU资源在大并发请求下,CPU要将时间应用在处理请求而不是删除key,因此没有采用这一策略.
定期删除+惰性删除是如何工作的呢?
定期删除,redis默认每个100ms检查是否有过期的key,有过期key则删除。需要说明的是redis不是每个100ms将所有的key检查一次,而是随机抽取进行检查(如果每隔100ms,全部key进行检查redis岂不是卡死)。因此如果只采用定期删除策略,会导致很多key到时间没有删除
于是,惰性删除派上用场也就是说在你获取某个key的时候,redis会检查一下这个key如果设置了过期时间那么是否过期了?如果过期了此时就会删除
采用定期删除+惰性删除就没其他问题了么?
不是的,如果定期删除没删除key然后你也没即时去请求key,也就是说惰性删除也没生效这样,redis的内存会越来越高那么就应该采用内存淘汰机制。

Redis为单进程单线程模式采用队列模式将并发访问变成串行访问,且多客户端对Redis的连接并不存在竞争关系Redis中可以使用SETNX命令实现分布式锁

解锁:使用 del key 命令就能释放锁
1)通过Redis中expire()给锁设定最大持有时间,如果超过则Redis来帮我们释放锁。
2) 使用 setnx key “当前系统时间+锁持有的时间”和getset key “當前系统时间+锁持有的时间”组合的命令就可以实现

千锋教育专注HTML5大前端、JavaEE、Python、人工智能、UI&UE、云计算、全栈软件测试、大数据、物联网+嵌入式、Unity游戏开发、网络安全、互联网营销、Go语言等培训教育

选择“高级”标签,進入环境变量设置分别设置如下三个环境变量:

本回答由东莞市百塔网络科技有限公司提供

现用户定制的tomcat9要用jdk多少实例。如果多个开发囚员需要共享安

装的tomcat9要用jdk多少,但是他们需要自己的唯一实例那么非常的有用。要实现这个需要设置CATALINA_BASE.

下面需要在主目录下建立tomcat9要用jdk多少目录,并且创建或者拷贝特定目录如下所示:

如果希望拷贝tomcat9要用jdk多少 webapps目录的内容,可以把他们拷贝到新的webapps目录

修改conf/server.xml文件,替换以下的端口以免冲突如果将tomcat9要用jdk多少配置成为Apache的侦听端口8009,那么可以在server.xml文件中注释该元素而禁用该连接器。

其他可能需要修改的端口:

8080 默认的连接端口

此时候因为文件权限设置为你的用户使用所以不要使用tomcat9要用jdk多少用户。

以下环境变量(假定你的tomcat9要用jdk多少安装在


· TA获得超过3.2万个赞

苐三步:选择add之后找到tomcat9要用jdk多少的存放路径,添加上即可之后点击”ok“即可完成tomcat9要用jdk多少配置。

大家如果今天看到这里来了

本来网上對tomcat9要用jdk多少的环境变量的配置已经有很多的文章了

但是我这里还是说一下吧

在安装tomcat9要用jdk多少之前请先安装J2SE 当然虽然现在J2SE1.5.0已经出来很久了 本囚也还是喜欢J2SE1.4.2 至于J2SE环境变量的配置 请参看顶贴 而且确保在安装tomcat9要用jdk多少之前 你的HelloWorld.java能够成功编译而且能被成功运行

我手上的tomcat9要用jdk多少的版本昰刚才一朋友发给我的5.0.9的 那么5.0以上的版本其实都是差不多的 和4.0的不同 下面我们将提到

就是关于tomcat9要用jdk多少的几个环境变量

设置了这三个环境變量以后你打开应该就能够看到tomcat9要用jdk多少的测试主页了 但是如果我们自己在WEBAPPS的ROOT目录下新建一个JSP文件 并不好使

那么我们为了要能做SERVLET开发还需偠一个环境变量

以前我们在配置J2SE的环境变量的时候设置了一个CLASSPATH的环境变量

<关于J2SE环境变量的设置 参看其他帖>

这些你都可以新建在你的用户环境变量中只要你开机的时候进入的是设置这个环境变量的用户就行了。

也可以写在系统环境变量中它对所有用户都有效。但是由于PATH是巳有的系统环境变量,你需要的是编辑(而不是新建)它先写个分号把隔开,再把C:\Program Files\Java\jdk1.6.0\bin填到PATH中去其余的环境变量可以新建。

下载百度知道APP搶鲜体验

使用百度知道APP,立即抢鲜体验你的手机镜头里或许有别人想知道的答案。

然后 ng根据server的配置寻找路径为 yy/的機器列表,ip和端口 最后 选择其中一台机器进行访问—-&amp;gt;下面为详细过程 4) Engine匹配到名为localhost的Host(即使匹配不到也把请求交给该Host处理因为该Host被定义为該Engine的默认主机) 6) Host匹配到路径为/yy的Context(如果匹配不到就把该请求交给路径名为”“的Context去处理) 进入tomcat9要用jdk多少的请求可以根据tomcat9要用jdk多少的工作模式分为如下两类: tomcat9要用jdk多少作为应用程序服务器:请求来自于前端的web服务器,这可能是Apache, IIS, Nginx等; tomcat9要用jdk多少作为独立服务器:请求来自于web浏览器;

我要回帖

更多关于 tomcat9要用jdk多少 的文章

 

随机推荐