赞
踩
区别:
应用场景:
转发:典型的MVC模式
重定向:一般用于避免用户的非正常访问
IOC容器的初始化是有refresh()方法来启动的,这个方法标志着IOC容器的正式启动
初始化过程包括三个基本过程
Spring事务是SpringAOP的一种实现,本质上是基于动态代理技术对所需要管理的Bean进行加载
并在方法调用的前后加入合适的事务管理代码实现事物的提交以及产生异常时的回滚
实现:
Spring的事务声明有两种方式,编程式和声明式。
Spring主要通过声明式事务的方式对事物进行管理,即在配置文件中进行声明,通过AOP将事务切入程序,最大的好处是大量减少了代码量
四大金刚 数据库类型 路径 账号密码
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/test"></property>
<property name="username" value="root"></property>
IOC控制反转是Spring和核心,由Spring管理创建响应的对象创建,即由IOC容器帮对象管理相应的依赖关系,并在运行时将对象注入,而不是通过传统的new来主动创建对象。而DI则是实现IOC注入关联对象的方式有三种,set方法注入 构造函数注入 参数
BeanFactory:产生一个新的实例,可以实现单例模式
BeanWrapper:提供统一的get及set方法
ApplicationContext:提供框架的实现,包括BeanFactory的所有功能
面向切面编程,AOP允许程序员模块化横向业务逻辑,将系统中非核心的业务提取出来,进行单独处理,解决系统代码耦合度过高的问题。
使代码重用度高、易于维护。例如权限认证、日志管理和事务管理。
三种创建方式:①构造器注入创建 ②工厂方法(静态工厂) ③工厂类(实例工厂)
1) Bean实例化 :Bean的默认构造函数。
2) Bean的初始化:Init()方法中可以进行初始化。
3) Bean的使用 :getBean()方法可以获取当前的Bean,从而做相对应的业务操作。
4) Bean的销毁 :destroy()方法执行bean的销毁。
Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。
spring mvc类似于struts的一个MVC开框架,其实都是属于spring,spring mvc需要有spring的架包作为支撑才能跑起来。
BeanFactory提供了配制框架及基本功能,负责对象实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。而ApplicationContext则增加了更多支持企业核心内容的功 能。比如更易与Spring AOP集成、消息资源处理(国际化处理)、事件传递及各种不同应用层的context实现(如针对web应用的WebApplicationContext)。
HashMap: key:value
底层使用数组(table)+链表(entry)结构,通过key进行二次hash计算出的hashCode%table.length确定对应的数组下标的位置存放value。
HashTable:key:value
Hashtable 继承于Dictionary,实现了Map、Cloneable、Java.io.Serializable接口,Hashtable 的函数都是同步的,这意味着它是线程安全的。它的key、value都不可以为null。此外,Hashtable中的映射不是有序的。
底层使用数组(table)+链表(entry)结构,hash计算方法是直接使用key的hashcode对table数组的长度直接进行取模。
ArrayList:线性链表(线程不安全),最核心的两个成员变量是存储数据的数组和数组大小。
a. ArrayList 是通过将底层 Object 数组复制的方式(System.arraycopy方法)来处理数组的增长;
b. 当ArrayList 的容量不足时,其扩充容量的方式:先将容量扩充至当前容量的1.5倍,若还不够,则将容量扩充至当前需要的数量。
GET一般用于获取/查询资源信息,而POST一般用于更新资源信息。
get是把参数数据队列加到提交表单的ACTION属性所指的URL中,值和表单内各个字段一一对应,在URL中可以看到。post是通过HTTP post机制,将表单内各个字段与其内容放置在HTML HEADER内一起传送到ACTION属性所指的URL地址。用户看不到这个过程。
对于get方式,服务器端用doGet获取变量的值,对于post方式,服务器端用doPost获取提交的数据。
get传送的数据量较小,不能大于2KB。post传送的数据量较大,一般被默认为不受限制。
get安全性非常低,post安全性较高。但是执行效率却比Post方法好。
session和cookie都是会话(session)跟踪技术.cookie通过在客户端记录信息确定用户身份,而session是通过在服务器端记录信息确定用户身份.但是session的实现依赖于cookie机制来保存JESESSIONID(session的唯一标识,需要存在客户端)
区别
(1)cookie的数据存储在客户端,session的数据存储在服务器上
(2)cookie不是很安全,别人可以通过分析存放在本地的cookie并进行cookie欺骗,考虑到安全应该使用session
(3)session会在一定时间内保存在服务器上,当访问增多时,会影响服务器的性能.考虑到服务器性能,应当使用cookie
(4)单个cookie保存数据不能超过4k,很多浏览器显示一个站点最多保存20个cookie
使用场景
将重要信息保存在session中(登陆),将其他需要保留的信心存放在cookie中(购物车,cookie是可以在客户端禁用的,这时候要使用cookie+数据库的方式实现购物车,当cookie中不能取出数据,就从数据库中取)
Singleton是一种创建型模式,指某个类采用Singleton模式,则在这个类被创建后,只可能产生一个实例供外部访问,并且提供一个全局的访问点。
第一种(懒汉,线程不安全):略(参考第二种)
第二种(懒汉,线程安全):
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
这种写法能够在多线程中很好的工作,而且看起来它也具备很好的lazy loading,但是,遗憾的是,效率很低,99%情况下不需要同步。
第三种(饿汉):
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
第四种(静态内部类):
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
这种方式同样利用了classloder的机制来保证初始化instance时只有一个线程,它跟第三种方式不同的是(很细微的差别):第三种是只要Singleton类被装载了,那么instance就会被实例化(没有达到lazy loading效果),而这种方式是Singleton类被装载了,instance不一定被初始化。因为SingletonHolder类没有被主动使用,只有显示通过调用getInstance方法时,才会显示装载SingletonHolder类,从而实例化instance。想象一下,如果实例化instance很消耗资源,我想让他延迟加载,另外一方面,我不希望在Singleton类加载时就实例化,因为我不能确保Singleton类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化instance显然是不合适的。这个时候,这种方式相比第三方式就显得很合理。
第五种(枚举):
public enum Singleton {
INSTANCE;
public void instance() {
}
}
这种方式是Effective Java作者Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象,可谓是很坚强的壁垒啊,不过,个人认为由于1.5中才加入enum特性,用这种方式写不免让人感觉生疏,在实际工作中,我也很少看见有人这么写过。
第六种(双重校验锁):
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
} } }
return singleton;
}
}
这个是第二种方式的升级版,俗称双重检查锁定,但仅在JDK1.5之后有效。
单例模式(略):
工厂模式(普通、多方法和静态工厂方法、抽象工厂):该模式主要功能是统一提供实例对象的引用
建造者模式:一个对象的组成可能有很多其他的对象一起组成的,比如说,一个对象的实现非常复杂,有很多的属性,而这些属性又是其他对象的引用,可能这些对象的引用又包括很多的对象引用。封装这些复杂性,就可以使用建造模式。
策略模式:这个模式是将行为的抽象,即当有几个类有相似的方法,将其中通用的部分都提取出来,从而使扩展更容易。
门面模式:这个模式个人感觉像是Service层的一个翻版。比如Dao我们定义了很多持久化方法,我们通过Service层将Dao的原子方法组成业务逻辑,再通过方法向上层提供服务。门面模式道理其实是一样的。
代理模式:其实每个模式名称就表明了该模式的作用,代理模式就是多一个代理类出来,替原对象进行一些操作,比如我们在租房子的时候回去找中介,为什么呢?因为你对该地区房屋的信息掌握的不够全面,希望找一个更熟悉的人去帮你做,此处的代理就是这个意思。
①对象冒充
function Parent(username){...}
function Child(username,password){
//第一步:this.method是作为一个临时的属性,并且指向Parent所指向的对象,
this.method = Parent;
//第二步:执行this.method方法,即执行Parent所指向的对象函数
this.method(username);//最关键的一行
//第三步:销毁this.method属性,即此时Child就已经拥有了Parent的所有属性和方法
delete this.method;
...
}
②call方法
call方法是Function类中的方法
call方法的第一个参数的值赋值给类(即方法)中出现的this
call方法的第二个参数开始依次赋值给类(即方法)所接受的参数
function Parent(username){...}
function Child(username,password){
Parent.call(this,username);
...
}
③apply()方法方式
apply方法接受2个参数,
A、第一个参数与call方法的第一个参数一样,即赋值给类(即方法)中出现的this
B、第二个参数为数组类型,这个数组中的每个元素依次赋值给类(即方法)所接受的参数
function Parent(username){...}
function Child(username,password){
Parent.apply(this,new Array(username));
...
}
④原型链方式,即子类通过prototype将所有在父类中通过prototype追加的属性和方法都追加到Child,从而实现了继承。
function Person(){}
Person.prototype.hello = "hello";
Person.prototype.sayHello = function(){alert(this.hello);}
function Child(){}
Child.prototype = new Person();
//这行的作用是:将Parent中将所有通过prototype追加的属性和方法都追加到Child,从而实现了继承
Child.prototype.world = "world";
Child.prototype.sayWorld = function(){alert(this.world);}
⑤混合方式(略):混合了call方式、原型链方式
Hibernate中的缓存分一级缓存和二级缓存。
一级缓存就是Session级别的缓存,在事务范围内有效是,内置的不能被卸载。二级缓存是SesionFactory级别的缓存,从应用启动到应用结束有效。是可选的,默认没有二级缓存,需要手动开启。
保存数据库后,在内存中保存一份,如果更新了数据库就要同步更新。
什么样的数据适合存放到第二级缓存中?
1)很少被修改的数据 帖子的最后回复时间
2)经常被查询的数据 电商的地点
2) 不是很重要的数据,允许出现偶尔并发的数据
3) 不会被并发访问的数据
4) 常量数据
扩展:hibernate的二级缓存默认是不支持分布式缓存的。使用memcahe,redis等中央缓存来代替二级缓存。
String(JDK1.0时代) 不可变字符序列
StringBuffer(JDK1.0时代) 线程安全的可变字符序列
StringBuilder(JDK1.5时代) 非线程安全的可变字符序列
①String和StringBuffer中的value[]都用于存储字符序列,String中的是常量(final)数组,只能被赋值一次。 StringBuffer中的value[]就是一个很普通的数组,而且可以通过append()方法将新字符串加入value[]末尾。
②StringBuffer线程安全,而StringBuilder不是。
③StringBuilder的效率比StringBuffer稍高,如果不考虑线程安全,StringBuilder应该是首选。
④StringBuffer对象的append效率要高于String对象的"+"连接操作。
StringBuffer:线程安全,方法都有同步修饰
StringBuilder:线程不安全,效率高
String:一旦创建 长度固定不变
StringBuffer/StringBuilder都是要变化
①int 是基本数据类型,Integer是其包装类,注意是一个类。
②Integer默认值是null,而int默认值是0;
③声明为Integer的变量需要实例化,而声明为int的变量不需要实例化;
④Integer是对象,用一个引用指向这个对象,而int是基本类型,直接存储数值。
序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决对象流读写操作时可能引发的问题(如果不进行序列化可能会存在数据乱序的问题)。
要实现序列化,需要让一个类实现Serializable接口,该接口是一个标识性接口,标注该类对象是可被序列化的,然后使用一个输出流来构造一个对象输出流并通过writeObject(Object)方法就可以将实现对象写出(即保存其状态);如果需要反序列化则可以用一个输入流建立对象输入流,然后通过readObject方法从流中读取对象。序列化除了能够实现对象的持久化之外,还能够用于对象的深度克隆。
只有实现了 serializable和Externalizable接口的类的对象才能被序列化 后者是前者的子类 实现这个借口的类完全由自身来控制序列化的行为,而仅仅实现前者的类可以采用默认的序列化方式。实现这两个接口 标志着对象可以被序列化了
Java 串行化技术可以使你将一个对象的状态写入一个Byte 流里,并且可以从其它地方把该Byte 流里的数据读出来,重新构造一个相同的对象。这种机制允许你将对象通过网络进行传播,并可以随时把对象持久化到数据库、文件等系统里。Java的串行化机制是RMI、EJB等技术的技术基础。用途:利用对象的串行化实现保存应用程序的当前工作状态,下次再启动的时候将自动地恢复到上次执行的状态。
①加载数据库驱动 Class.forName("com.mysql.jdbc.Driver") ;
②创建数据库连接 Connection con = DriverManager.getConnection(url , username , password ) ;
③创建一个Statement
1、执行静态SQL语句。通常通过Statement实例实现。
2、执行动态SQL语句。通常通过PreparedStatement实例实现。
3、执行数据库存储过程。通常通过CallableStatement实例实现。
④执行SQL语句
Statement接口提供了三种执行SQL语句的方法:executeQuery 、executeUpdate和execute方法。
⑤处理结果ResultSet
⑥关闭JDBC对象 关闭记录集ResultSet、声明Statement和连接Connection
#{}语法,MyBatis会产生PreparedStatement语句中,并且安全的设置PreparedStatement参数,这个过程中MyBatis会进行必要的安全检查和转义。
${}是直接输出变量的值,未经过预编译的,仅仅是取变量的值,是非安全的,存在sql注入.
尽量使用#,但是${}在什么情况下使用呢?
有时候可能需要直接插入一个不做任何修改的字符串到SQL语句中。这时候应该使用${}语法。
比如,动态SQL中的字段名,如:ORDER BY ${columnName}
悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。开始改变对象时锁住直到完成所有操作后才释放。
乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。修改过程不锁定对象,直到提交所做更改时才将对象锁住。读取时不加锁,因此可能会造成脏读。
乐观锁的实现方式
①使用自增长的整数表示数据版本号。更新时检查版本号是否一致,比如数据库中数据版本为6,更新提交时version=6+1,使用该version值(=7)与数据库version+1(=7)作比较,如果相等,则可以更新,如果不等则有可能其他程序已更新该记录,所以返回错误。
②使用时间戳来实现.
注:对于以上两种方式,Hibernate自带实现方式:在使用乐观锁的字段前加annotation: @Version, Hibernate在更新时自动校验该字段。
在实际生产环境里边,如果并发量不大且不允许脏读,可以使用悲观锁解决并发问题;但如果系统的并发非常大的话,悲观锁定会带来非常大的性能问题,所以我们就要选择乐观锁定的方法.
这三者都实现了List 接口.所有使用方式也很相似,主要区别在于因为实现方式的不同,所以对不同的操作具有不同的效率。
ArrayList 是一个可改变大小的数组.当更多的元素加入到ArrayList中时,其大小将会动态地增长.内部的元素可以直接通过get与set方法进行访问,因为ArrayList本质上就是一个数组.
LinkedList 是一个双链表,在添加和删除元素时具有比ArrayList更好的性能.但在get与set方面弱于ArrayList.
当然,这些对比都是指数据量很大或者操作很频繁的情况下的对比,如果数据和运算量很小,那么对比将失去意义.
Vector 和ArrayList类似,但属于强同步类。如果你的程序本身是线程安全的(thread-safe,没有在多个线程之间共享同一个集合/对象),那么使用ArrayList是更好的选择。
Vector和ArrayList在更多元素添加进来时会请求更大的空间。Vector每次请求其大小的双倍空间,而ArrayList每次对size增长50%.
而 LinkedList 还实现了 Queue 接口,该接口比List提供了更多的方法,包括 offer(),peek(),poll()等.
注意: 默认情况下ArrayList的初始容量非常小,所以如果可以预估数据量的话,分配一个较大的初始值属于最佳实践,这样可以减少调整大小的开销。
Hashmap 是一个最常用的Map,它根据键的HashCode 值存储数据,根据键可以直接获取它的值,具有很快的访问速度。HashMap最多只允许一条记录的键为Null;允许多条记录的值为Null;HashMap不支持线程的同步,即任一时刻可以有多个线程同时写HashMap;可能会导致数据的不一致。如果需要同步,可以用Collections的synchronizedMap方法使HashMap具有同步的能力.
Hashtable 与 HashMap类似,但是主要有6点不同。
1.HashTable的方法是同步的,HashMap未经同步,所以在多线程场合要手动同步HashMap这个区别就像Vector和ArrayList一样。
2.HashTable不允许null值,key和value都不可以,HashMap允许null值,key和value都可以。HashMap允许key值只能由一个null值,因为hashmap如果key值相同,新的key, value将替代旧的。
3.HashTable有一个contains(Object value)功能和containsValue(Object value)功能一样。
4.HashTable使用Enumeration,HashMap使用Iterator。
5.HashTable中hash数组默认大小是11,增加的方式是 old*2+1。HashMap中hash数组的默认大小是
Apache:全球应用最广泛的http服务器,免费,出自apache基金组织
Tomcat:应用也算非常广泛的web服务器,支持部分j2ee,免费,出自apache基金组织
JBoss:开源的应用服务器,比较受人喜爱,免费(文档要收费)
Weblogic:应该说算是业界第一的app server,全部支持j2ee1.4, 对于开发者,有免费使用一年的许可证。
Apache支持静态页,Tomcat支持动态的,比如Servlet等,
一般使用Apache+Tomcat的话,Apache只是作为一个转发,对JSP的处理是由Tomcat来处理的。
Apche可以支持PHPcgiperl,但是要使用Java的话,你需要Tomcat在Apache后台支撑,将Java请求由Apache转发给Tomcat处理。
Apache是Web服务器,Tomcat是应用(Java)服务器,它只是一个Servlet(JSP也翻译成Servlet)容器,可以认为是Apache的扩展,但是可以独立于Apache运行。
JBoss和WebLogic都含有Jsp和Servlet容器,也就可以做web容器,也包含EJB容器,是完整的J2EE应用服务器。
Tomcat 只能做jsp和servlet的container
①cookie数据存放在客户的浏览器上,session数据放在服务器上。
②cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗考虑到安全应当使用session。
③session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能
考虑到减轻服务器性能方面,应当使用COOKIE。
④单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
JDBC -> Mybatis -> Hibernate : 原生 -> 半自动化 -> 全自动化
1)从层次上看,JDBC是较底层的持久层操作方式,而Hibernate和MyBatis都是在JDBC的基础上进行了封装使其更加方便程序员对持久层的操作。
2)从功能上看,JDBC就是简单的建立数据库连接,然后创建statement,将sql语句传给statement去执行,如果是有返回结果的查询语句,会将
查询结果放到ResultSet对象中,通过对ResultSet对象的遍历操作来获取数据;Hibernate是将数据库中的数据表映射为持久层的Java对象,实现
数据表的完整性控制;MyBatis是将sql语句中的输入参数和输出参数映射为java对象,放弃了对数据表的完整性控制,但是获得了更灵活和响应
性能更快的优势。
3)从使用上看,如果进行底层编程,而且对性能要求极高的话,应该采用JDBC的方式;如果要对数据库进行完整性控制的话建议使用Hibernate;
如果要灵活使用sql语句的话建议采用MyBatis框架。
目前企业中使用SpringMvc的比例已经远远超过Struts2,那么两者到底有什么区别,是很多初学者比较关注的问题,下面我们就来对SpringMvc和Struts2进行各方面的比较:
1. 核 心控制器(前端控制器、预处理控制器):对于使用过mvc框架的人来说这个词应该不会陌生,核心控制器的主要用途是处理所有的请求,然后对那些特殊的请求 (控制器)统一的进行处理(字符编码、文件上传、参数接受、异常处理等等),spring mvc核心控制器是Servlet,而Struts2是Filter。
2.控制器实例:Spring Mvc会比Struts快一些(理论上)。Spring Mvc是基于方法设计,而Sturts是基于对象,每次发一次请求都会实例一个action,每个action都会被注入 属性,而Spring更像Servlet一样,只有一个实例,每次请求执行对应的方法即可(注意:由于是单例实例,所以应当避免全局变量的修改,这样会产生线程安全问题)。
3. 管理方式:大部分的公司的核心架构中,就会使用到spring,而spring mvc又是spring中的一个模块,所以spring对于spring mvc的控制器管理更加简单方便,而且提供了全 注解方式进行管理,各种功能的注解都比较全面,使用简单,而struts2需要采用XML很多的配置参数来管理(虽然也可以采用注解,但是几乎没有公司那 样使用)。
4.参数传递:Struts2中自身提供多种参数接受,其实都是通过(ValueStack)进行传递和赋值,而SpringMvc是通过方法的参数进行接收。
5.学习难度:Struts更加很多新的技术点,比如拦截器、值栈及OGNL表达式,学习成本较高,springmvc 比较简单,很较少的时间都能上手。
6.intercepter 的实现机制:struts有以自己的interceptor机制,spring mvc用的是独立的AOP方式。这样导致struts的配置文件量还是比spring mvc大,虽然struts的配置能继承,所以我觉得论使用上来讲,spring mvc使用更加简洁,开发效率Spring MVC确实比struts2高。spring mvc是方法级别的拦截,一个方法对应一个request上下文,而方法同时又跟一个url对应,所以说从架构本身上spring3 mvc就容易实现restful url。struts2是类级别的拦截,一个类对应一个request上下文;实现restful url要费劲,因为struts2 action的一个方法可以对应一个url;而其类属性却被所有方法共享,这也就无法用注解或其他方式标识其所属方法了。spring3 mvc的方法之间基本上独立的,独享request response数据,请求数据通过参数获取,处理结果通过ModelMap交回给框架方法之间不共享变量,而struts2搞的就比较乱,虽然方法之间 也是独立的,但其所有Action变量是共享的,这不会影响程序运行,却给我们编码,读程序时带来麻烦。
7.spring mvc处理ajax请求,直接通过返回数据,方法中使用注解@ResponseBody,spring mvc自动帮我们对象转换为JSON数据。而struts2是通过插件的方式进行处理
在SpringMVC流行起来之前,Struts2在MVC框架中占核心地位,随着SpringMVC的出现,SpringMVC慢慢的取代struts2,但是很多企业都是原来搭建的框架,使用Struts2较多。
1、用户向服务器发送请求,请求被Spring 前端控制Servelt DispatcherServlet捕获(捕获)
2、 DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回;(查找handler)
3、 DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller), Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象(执行handler)
4、DispatcherServlet 根据返回的ModelAndView,选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver) (选择ViewResolver)
5、通过ViewResolver 结合Model和View,来渲染视图,DispatcherServlet 将渲染结果返回给客户端。(渲染返回)
先写实体类entity,定义对象的属性,(可以参照数据库中表的字段来设置,数据库的设计应该在所有编码开始之前)。
写Mapper.xml(Mybatis),其中定义你的功能,对应要对数据库进行的那些操作,比如 insert、selectAll、selectByKey、delete、update等。
写Mapper.java,将Mapper.xml中的操作按照id映射成Java函数。
写Service.java,为控制层提供服务,接受控制层的参数,完成相应的功能,并返回给控制层。
写Controller.java,连接页面请求和服务层,获取页面请求的参数,通过自动装配,映射不同的URL到相应的处理函数,并获取参数,对参数进行处理,之后传给服务层。
写JSP页面调用,请求哪些参数,需要获取什么数据
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。
应用:①获取某个对象的属性 ②获取类的静态属性 ③执行某对象方法 ④执行类的静态方法 ⑤创建某个类的实例 ⑥判断对象是否是某个类的实例
Servlet 生命周期:Servlet 加载--->实例化--->服务--->销毁。
init:在Servlet的生命周期中,仅执行一次init()方法。它是在服务器装入Servlet时执行的,负责初始化Servlet对象。可以配置服务器,以在启动服务器或客户机首次访问Servlet时装入Servlet。无论有多少客户机访问Servlet,都不会重复执行init()。
service:它是Servlet的核心,负责响应客户的请求。每当一个客户请求一个HttpServlet对象,该对象的Service()方法就要调用,而且传递给这个方法一个“请求”(ServletRequest)对象和一个“响应”(ServletResponse)对象作为参数。在HttpServlet中已存在Service()方法。默认的服务功能是调用与HTTP请求的方法相应的do功能。
destroy: 仅执行一次,在服务器端停止且卸载Servlet时执行该方法。当Servlet对象退出生命周期时,负责释放占用的资源。一个Servlet在运行service()方法时可能会产生其他的线程,因此需要确认在调用destroy()方法时,这些线程已经终止或完成。
创建Servlet对象的时机:
Servlet容器启动时:读取web.xml配置文件中的信息,构造指定的Servlet对象,创建ServletConfig对象,同时将ServletConfig对象作为参数来调用Servlet对象的init方法。
在Servlet容器启动后:客户首次向Servlet发出请求,Servlet容器会判断内存中是否存在指定的Servlet对象,如果没有则创建它,然后根据客户的请求创建HttpRequest、HttpResponse对象,从而调用Servlet 对象的service方法。
Servlet Servlet容器在启动时自动创建Servlet,这是由在web.xml文件中为Servlet设置的<load-on-startup>属性决定的。从中我们也能看到同一个类型的Servlet对象在Servlet容器中以单例的形式存在。
Java中equals和==的区别是什么?
相等的理解(==和equals)
相等: 传统的理解一般都是数字值是否相等;
在程序中任何东西都是数据,都会比较是否相等
==
基本数据类型: 比较的就是值是否相等;
引用数据类型: 比较的是对象的地址是否一样;
equals (最初定义在根类Object中的)
基本数据类型 : 不能够使用! 基本数据类型不是对象,不能够调用Object中的方法
引用数据类型 : 在Object的源码中定义的就是==进行比较比较
如果我们没有去覆写过equals方法而是直接调用到了Object中的此方法,那么结果和==比较应用数据类型一样的;
在实际开发中,我们一般比较对象都是通过对象的属性值进行比较(一般比较对象的地址没有多大用处),所以我们会经常覆写Object中的此方法,把自己的规则写在方法里面;
覆写equals方法必须覆写hashCode方法吗?你的理解是什么?
不是必须。但是假如一个类要创建很多对象,而这些对象要存储集合不确定,有可能是hashSet,也有可能是TreeSet,为了保证唯一性,所以最好复写hashCode方法,因为对象存入带hash的集合,如hashSet,hashMap,都要基于hashCode和equals方法,当hashCode方法返回的值一样时,还会调用equals方法判断,如果两个方法返回的都是一致,才判断两个对象是同一个对象,不存入集合(带hash的集合都保证数据是唯一的!)
分布式是一个非常广泛的概念,从系统的角度来说,可以理解为,一个业务分拆多个子业务,部署在不同的服务器上,集群则是同一个业务部署在多个服务器上。
JavaEE开发过程中,常见的分布式框架有:Dubbo、Hadoop、Elasticsearch
数据库集群:MySQL集群是一个无共享的(shared-nothing)、分布式节点架构的存储方案,其目的是提供容错性和高性能。通过多个MySQL服务器分配负载,从而最大程序地达到高性能,通过在不同位置存储数据保证高可用性和冗余。一般由一个主(写)+一个备(写)和N个从(读)库组成。
类变量也叫静态变量,也就是在变量前加了static 的变量;
实例变量也叫对象变量,即没加static 的变量;
区别在于:
类变量是所有对象共有,其中一个对象将它值改变,其他对象得到的就是改变后的结果;
而实例变量则属对象私有,某一个对象将其值改变,不影响其他对象
方法重载和方法重写
①更新最新的服务器代码下来
②打开冲突的文件进行对比
③简单冲突直接修改,复杂冲突找到上个提交人协助修改,修改完成后标记为“已解决”
④提交修改完成的文件
进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位.
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.
关系
一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行.
相对进程而言,线程是一个更加接近于执行体的概念,它可以与同进程中的其他线程共享数据,但拥有自己的栈空间,拥有独立的执行序列。
区别
进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。
1) 简而言之,一个程序至少有一个进程,一个进程至少有一个线程.
2) 线程的划分尺度小于进程,使得多线程程序的并发性高。
3) 另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
4) 线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
5) 从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。
ThreadPool中的线程不用手动开始,也不用手动取消,要做的只是把工作函数排入线程池,剩下的工作由系统自动完成,不能控制线程池中的线程。以下情况不适宜用ThreadPool:线程执行时间长、线程需要制定不同的优先级、执行过程中需要控制线程的睡眠和挂起等操作。所以ThreadPool适合并发运行若干个运行时间不长且互不干扰的函数。
①ThreadPoolExecutor作为java.util.concurrent包对外提供基础实现,以内部线程池的形式对外提供管理任务执行,线程调度,线程池管理等等服务;
②Executors方法提供的线程服务,都是通过参数设置来实现不同的线程池机制。
①、ReentrantLock 拥有Synchronized相同的并发性和内存语义,此外还多了锁投票,定时锁等候和中断锁等候
线程A和B都要获取对象O的锁定,假设A获取了对象O锁,B将等待A释放对O的锁定,
如果使用 synchronized ,如果A不释放,B将一直等下去,不能被中断
如果 使用ReentrantLock,如果A不释放,可以使B在等待了足够长的时间以后,中断等待,而干别的事情
ReentrantLock获取锁定与三种方式:
a) lock(), 如果获取了锁立即返回,如果别的线程持有锁,当前线程则一直处于休眠状态,直到获取锁
b) tryLock(), 如果获取了锁立即返回true,如果别的线程正持有锁,立即返回false;
c)tryLock(long timeout,TimeUnit unit), 如果获取了锁定立即返回true,如果别的线程正持有锁,会等待参数给定的时间,在等待的过程中,如果获取了锁定,就返回true,如果等待超时,返回false;
d) lockInterruptibly:如果获取了锁定立即返回,如果没有获取锁定,当前线程处于休眠状态,直到或者锁定,或者当前线程被别的线程中断
②、synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动释放锁定,但是使用Lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就必须将unLock()放到finally{}中
③、在资源竞争不是很激烈的情况下,Synchronized的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下,Synchronized的性能会下降几十倍,但是ReetrantLock的性能能维持常态;
synchronized关键字主要解决多线程共享数据同步问题。
ThreadLocal使用场合主要解决多线程中数据因并发产生不一致问题。
ThreadLocal和Synchonized都用于解决多线程并发访问。但是ThreadLocal与synchronized有本质的区别:
synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多个线程间通信时能够获得数据共享。
Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。当然ThreadLocal并不能替代synchronized,它们处理不同的问题域。Synchronized用于实现同步机制,比ThreadLocal更加复杂。
sleep指线程被调用时,占着CPU不工作,形象地说明为“占着CPU睡觉”,此时,系统的CPU部分资源被占用,其他线程无法进入,会增加时间限制。
wait指线程处于进入等待状态,形象地说明为“等待使用CPU”,此时线程不占用任何资源,不增加时间限制。
所以
sleep(100L)意思为:占用CPU,线程休眠100毫秒
wait(100L)意思为:不占用CPU,线程等待100毫秒
Java中实现多线程有两种途径:继承Thread类或者实现Runnable接口。Runnable是接口,建议用接口的方式生成线程,因为接口可以实现多继承,况且Runnable只有一个run方法,很适合继承。
在使用Thread的时候只需继承Thread,并且new一个实例出来,调用start()方法即可以启动一个线程。
在使用Runnable的时候需要先new一个实现Runnable的实例,之后启动Thread即可。
SOAP比较复杂,基于XML,有对应规范;REST利用HTTP请请求方式GET,POST,PUT约定事务操作。
简单的说,SOAP通过传输XML,XML定义了请求和响应的具体数据,要进行的操作等等;而REST则是另一种约定,比如请求/user/1001这个RUL,GET方式返回id为1001的user信息,POST方式则是更新id为1001的user信息,DELETE删除等。
数据库连接池(Connection pooling)是程序启动时建立足够的数据库连接,并将这些连接组成一个连接池,由程序动态地对池中的连接进行申请,使用,释放。简单来说,就是创建数据库连接是一个很耗时的操作,也容易对数据库造成安全隐患。所以,在程序初始化的时候,集中创建多个数据库连接,并把他们集中管理,供程序使用,可以保证较快的数据库读写速度,还更加安全可靠。
常见的连接池:DBCP C3P0 DRUID PROXOOL
9个内置的对象:
request 用户端请求,此请求会包含来自GET/POST请求的参数
response 网页传回用户端的回应
pageContext 网页的属性是在这里管理
session 与请求有关的会话期
application servlet正在执行的内容
out 用来传送回应的输出
config servlet的构架部件
page JSP网页本身
exception 针对错误网页,未捕捉的例外
四大作用域:pageContext request session application 可以通过jstl从四大作用域中取值.
Jsp传递值request session application cookie也能传值
①强制转码:new String(request.getParameter("name").getBytes("ISO-8859-1"),"gb2312");
②设置 request 和 response 的编码 [ 页面编码必须为 u8 ]
request.setCharacterEncoding("gb2312");//传值编码
response.setContentType("text/html;charset=gb2312");//设置传输编码
数据库事务的隔离级别有4个,由低到高依次为Read uncommitted、Read committed、Repeatable read、Serializable,这四个级别可以逐个解决脏读、不可重复读、幻读这几类问题。
√: 可能出现 ×: 不会出现
| 脏读 | 不可重复读 | 幻读 |
Read uncommitted | √ | √ | √ |
Read committed | × | √ | √ |
Repeatable read | × | × | √ |
概念:堆栈是两种数据结构,是一种数据项按序排列的数据结构,只能在一端进行插入和删除操作。
堆为队列优先,先进先出(FIFO)。栈为先进后出(FILO)
空间分配,
堆:一般有程序员分配释放,若程序员不释放,程序结束时可能由OS回收,分配方式类似于链表
栈:由操作系统自动分配释放,存放函数的参数值,局部变量等,操作方式与数据结构中的栈相类似
缓存方式
堆:使用二级缓存,生命周期与虚拟机的的GC算法有关,调用速度相对较低
栈:使用一级缓存,被调用时通常处于储存空间中,调用后立即释放
数据结构
堆;类似于树形结构,可以类比于堆排序
栈:先进后出
Java中的区别
堆和栈都是Java在RAM中用来存放存放数据的地方,与C++不同的是,
Java自动管理堆和栈,程序员不能直接的设置堆和栈
堆:对内存用来存放由new创建的对象和数组
栈:基本类型的变量和对象的引用变量
5.扩展:Java中变量在内存中的分配
1.类变量:在程序加载时系统就为他在队中开辟了内存,堆中的内存地址存放于栈以便于高速访问。静态变量的生命周期——一直到系统关闭。
2.实例变量:使用关键字new时,系统在堆中开辟并不一定是连续的空间分配给变量,通过哈希算法换算为一长串数字以表征这个变量在堆中的“物理位置”。实例变量的生命周期——实例变量的引用丢失后,将被GC列入到可回收名单中,但不是马上回收释放。
3.局部变量:
生命在某个方法或者某段代码里面,执行到他的时候在栈中开辟内存,局部变量一旦脱离作用域,内存立即释放。
存储结构:
hashMap和hashtable都实现了Map接口
(hashMap可以接受为null的键值对key和值value,而hashtable则不行)
可以共享一个hahstable,而如果没有正确的同步的话,多个线程是不能共享hashMap的,hashtable的扩展性更好
如果你不需要同步,只需要单一线程,那么使用hashMap性能要比hahsTable好
脏读:当事务读取还未被提交的数据时,就会发生这种事情
虚读:如果符合搜索条件的一行数据在后面的读取操作中出现,单该行数据却不属于最初的数据,
不可重复读:当事务两次读取同一行数据,但是每次得到的数据都不一样时,就会发生这种情况
通过服务器设置接口响应头Header允许接口被跨域请求,那么服务端既允许接口被跨域访问,不同源
的前端页面也就调用该接口
使用Spring的注解@CrossOrigin
自定义拦截器,对每个请求的response header进行设置
Spring自带的cors标签进行html设置
Web.xml中通过filter设置
浏览器的同源策略限制默认情况下前端页面和后端页面在不同服务器时,前端页面js无法请求到后端接口服务,寄存在跨域问题
Nginx 代理解决跨域原理其实很简单,从浏览器同源策略的限制角度考虑,及浏览器访问前端页面和后端接口的IP主机相同,poot端口相同,这样前端页面请求接口时就不会因为同源策略限制出现跨域问题
代理方式应该是解决跨域问题的最优方案,开发中应该优先采用该方式处理跨域问题
In应该使用到了索引,具体可以设置参数,5.6默认是10个,5.7默认是200,超出之后
因为很多底层类都实现了ThreadLocal方法,使用此方法让线程不安全的变为线程安全的。
我们知道在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域。就是因为Spring对一些Bean(如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等)中非线程安全状态采用ThreadLocal进行处理,让它们也成为线程安全的状态,因为有状态的Bean就可以在多线程中共享了。
一般使用的是对应的集合类,数组使用Arrays,集合使用Conllections,都有排序的的方法
并且java8以后的list对象是有sout方法,可以让集合元素的类实现Comparable接口或者
Sort方法传入一个Comparator
Lanbda表达式 Stream函数式操作流元素集合 接口新增:默认方法和静态方法
方法的引用和Lambda表达式联合使用 引入重复注解 类型注解 最新的Data?Time API
新增base64加解密API 数组并行操作 Metaspace取代JVM的PermGen
可以使用exists代替in写法
关系型数据库的最大优势在于它支持事务控制,并且标准化,就是行和列,一个表里的
数据都是一个样子,然后还可以支持多表关联查询或者简单的进行高级查询
Clean compile install package 部署应该是deploy
Cookie可以做购物车,但是没人这么做,一般来记住当前登陆的账号密码以便下次访问的
时候不用再次输入或者某个网站的一个个人设置,
Session在单击项目中可以用来保存当前登录的信息,用来做登陆认证
Jsp编译好以后。会编译成一个servlet的字节码文件,然后再项目运行的时候加载到虚拟机,作为一个Servlet
运行,在访问这个页面的时候,所有编写内容,就会通过response写到一个空载页面,呈现出预先编写的效果
hashSet就是基于hahsMap实现的,只把值作为key存下去
Redis可以做缓存,过滤重复的东西,统计,地图附近的人,位图存储,分布式锁
有很多种方法可以有效地解决缓存穿透问题,最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被 这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。另外也有一个更为简单粗暴的方法(我们采用的就是这种),如果一个查询返回的数据为空(不管是数 据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。
Redis缓存穿透不只是缓存中不存在,命中了数据库,并且数据库中也不存在,这就导致了这个key的查询会一直穿透到数据库。最简单的处理方式是如果数据库没有,我们就还是在缓存里面加一个这个key,值就为null。还有一个比较常用的方式是使用Redis的布隆过滤器
缓存失效时的雪崩效应对底层系统的冲击非常可怕。大多数系统设计者考虑用加锁或者队列的方式保证缓存的单线 程(进程)写,从而避免失效时大量的并发请求落到底层存储系统上。这里分享一个简单方案就时讲缓存失效时间分散开,比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。
在设置过期时间时,不要统一设置为相同的时间,应该在指定的时间上加上一个随机数,保证key过期时间点错开
session设置有tomcat,web.xml,java代码三种方式。
1.在web容器中设置(以tomcat为例)
2.在工程的web.xml中设置
3.通过java代码设置
三种方式优先等级:1 < 2 < 3
cd 进去路径 Pwd 获取当前路径 Ls ls 列举目录
cat 查看文件内容
tail 查看文件内容,可以加上-f 持续输出,做出一个控制台的效果,持续打印日志
vim 如果安装了vim可以用于文本编辑
rm 删除一个文件,加上-rf 是递归强制删除
基本要做查看日志以及部署项目的操作就这些。其他可以使用Xftp等工具进行上传
1.基于数据库。
2.基于缓存环境,redis,memcache等。
3.基于zookeeper。
SET lockKey value NX EX 30
如果key不存在,则Set一个key和value,并且过期时间设置为30秒,成功会返回一个OK,表示加锁成功,如果不为成功,则表示锁已经被其他持有了。
String基本常用的就是split分割,trim去空格,matches根据提供的正则做匹配,subString截取字符串这些,还有toLowerCase和toUpperCase就是转小写或转大写。
Sorted set是一个key对应两个值,一个是需要存的value,另外一个是score,sorted set就是通过score来进行排序的
导入的时候转csv格式,导出的时候用SXXFWorkBook,这在官网上有解决方案
查询时间,影响行数,走了哪些索引,还有哪些可用索引
使用双检锁加上volatile关键字
相同点:
都是key-value类型Nosql,都存放数据到内存中,读写效率高,而且都支持存储过期.
不同点:
redis相较于Memcached还支持持久化到磁盘,数据安全更高.
redis相较于Memcached支持value类型更多.
中央缓存(常用) 计数器的应用 实时防攻击系统 排行榜
设定有效期的应用 自动去重应用 队列 消息订阅系统
RDB模式
持久化可以在指定的时间间隔内生成数据集的时间点快照,默认开启改模式
AOF
AOF 持久化记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集,默认关闭该模式
继承 封装 继承 多态
封装:在面向对象的语言中,封装特性有类来体现,我们将现实生活中的一类实体定义成类,其中包括属性和行为
抽象:抽象就是将一类实体的共同特征抽象出来,封装在一个抽象类中,所以抽象在面向对象语言是由抽类来体现的
继承:继承就像是我们现实生活中的父子关系,儿子可以遗传父亲的一些特性,在面向对象语言中,就是一个类可以继承另一个类的一些特性,从而可以代码重用.
多态:多态就是通过传递给父类对象引用不同的子类对象从而表现出不同的行为
关于==
1.基本数据类型,也称原始数据类型。byte,short,char,int,long,float,double,boolean 他们之间的比较,应用双等号(==),比较的是他们的值。
2.复合数据类型(类) 当他们用(==)进行比较的时候,比较的是他们在内存中的存放地
equals
Java 语言里的 equals方法其实是交给开发者去覆写的,让开发者自己去定义满足什么条件的两个Object是equal的。
运行速度:StringBuilder >StringBuffer >String
String为字符串常量,而StringBuilder和StringBuffer均为字符串变量,即String对象一旦创建之后该对象是不可更改的,但后两者的对象是变量,是可以更改的。Java中对String对象进行的操作实际上是一个不断创建新的对象并且将旧的对象回收的一个过程,所以执行速度很慢。而StringBuilder和StringBuffer的对象是变量,对变量进行操作就是直接对该对象进行更改,而不进行创建和回收的操作,所以速度要比String快很多。
线程安全:StringBuilder是线程不安全的,而StringBuffer是线程安全的
如果一个StringBuffer对象在字符串缓冲区被多个线程使用时,StringBuffer中很多方法可以带有synchronized关键字,所以可以保证线程是安全的,但StringBuilder的方法则没有该关键字,所以不能保证线程安全,有可能会出现一些错误的操作。所以如果要进行的操作是多线程的,那么就要使用StringBuffer,但是在单线程的情况下,还是建议使用速度比较快的StringBuilder。
使用场景
String:适用于少量的字符串操作的情况
StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况
StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况
java中的集合分为value(Collection),和key-value(Map)两种;
存储value的有list和set两种:
list是有序的,可重复的
set是无序的,不可重复的
存储为key-value是map:HashMap,Hashtable,CurrentHashMap
Vector、ArrayList都是以类似数组的形式存储在内存中,LinkedList则以链表的形式进行存储。
Vector线程同步,ArrayList、LinkedList线程不同步。
LinkedList适合指定位置插入、删除操作,不适合查找;ArrayList、Vector适合查找,不适合指定位置的插入、删除操作。
Vector默认扩充为原来的两倍,(每次扩充空间的大小是可以设置的),而ArratList默认扩充为原来的1.5倍(查看之前的文章),因此ArrayList更节省空间。
2.联系
ArrayList,Vector、LinkedList类均在java.util包中都是可改变大小的.
ArrayList和Vector都是基于存储元素的Object[ ] array 来实现的,他们会在内存中开辟一块连续的空间来存储,由于数据存储是连续的,因此,他们支持用索引来访问元素,同时索引数据的速度比较快。但是在插入元素时需要移动容器中的元素,所以对数据的插入操作执行的比较慢。ArrayList和Vector都有一个初始化的容量大小,当里边存储的元素超过这个大小时就需要动态地扩充他们的存储空间。
相同:HashMap和Hashtable都可以使用来存储key-value的数据
区别:
基类不同:HashTable基于Dictionary类,而HashMap是基于AbstractMap。Dictionary是什么?它是任何可将键映射到相应值的类的抽象父类,而AbstractMap是基于Map接口的骨干实现,它以最大限度地减少实现此接口所需的工作。
线程安全:HashMap时单线程安全的,Hashtable是多线程安全的。
遍历不同:HashMap仅支持Iterator的遍历方式,Hashtable支持Iterator和Enumeration两种遍历方式。
null不同:HashMap可以允许存在一个为null的key和任意个为null的value,但是HashTable中的key和value都不允许为null。
多线程时,如何保障线程安全的同时也能保证效率?ConcurrentHashMap
通过把整个Map分为N个segment(类似Hashtable),这样既可以保障线程安全,也能使效率提高N倍,默认是16倍.
ConcurrentHashMap当中每个Segment各自持有一把锁。在保证线程安全的同时降低了锁的粒度,让并发操作效率更高。
实现
继承Thread类,不推荐
实现Runnable 接口
实现java.util.concurrent下的Callable接口
线程启动:调用start()方法;(调用start()方法,是使得线程处于可运行状态,线程并不一定会执行.如果start()方法是在main方法中调用的话,run()会执行.如果是在junit4下的话,线程不一定会执行)
怎么区分线程:给线程设置名字
简单了解过,JDK5中增加了并发库,java.util.concurrent中提供了对线程优化.管理的各项操作,该包提供了线程的运行,线程池的创建,线程生命周期的控制.
线程池:java.util.concurrent.Executors创建四种线程池
newCachedThreadPool 创建非固定数量,可缓存的线程池,若线程池超过处理需要,可灵活回收空线程,若没有线程可回收,则建新线程
newFixedThreadPool固定线程池,底层是无界队列,可控制最大并发数,超出的线程会在队列中等待
newScheduledThreadPool定时执行线程池,支持定时及周期性任务执行
newSingleThreadExecutor单线程化的线程池,只会用唯一的工作线程来执行任务,保证所有任务按照顺序执行
线程池的好处:
限定线程的个数,不会导致由于线程过多导致系统运行缓慢或崩溃
线程池每次都不需要去创建和销毁,节约了资源
线程池不需要每次都去创建,相应时间更快.
因此,GET请求的数据会暴露在地址栏中,而POST请求则不会。
Get大小有限制,post大小没有限制
Post的安全性比get高
就是一个运行在WEB服务器上的小的java程序,用来接收和响应从客户端发送来的请求,通常使用Http协议
使用:
按照一种约定俗成的称呼习惯,通常把我们的实现了Servlet接口的java程序,称职为Servlet
声明周期:
第一次访问的时候 创建
Destroy方法 执行
关闭服务器 销毁
相同点:
JSP是Servlet技术扩展,本质上是Servlet的简易方式,更应强调应用的外表表达式
JSP编译后是“类servlet”
不同点:
Servlet的应用逻辑是在Java文件中,并且完全从表示层中的Html里分离出来
JSP的情况是Java和Html可以组合成一个扩展名为.jsp的文件。作业面展示比较方便,二嵌入逻辑复杂
JSP侧重于视图,Servlet主要用于控制逻辑
Session和Cookie都是会话跟踪技术,cookie通过在客户端的记录信息确定用户身份,而Session是通过在
服务端的记录信息确定用户的身份,单Session依赖于Cookie机制来保存Jesessionid
区别:
登陆信息Cookie 购物车Session
事务是并发控制的单元,是用户定义的一个操作序列,这些操作这些操作要么全部成功,要么全部失败
贾琏欲执事
加载驱动 获取连接 设置参数 执行 释放连接
HTML:超文本标记语言,定义网页的结构
CSS:层叠样式表,用来美化页面
Javascript:主要用来验证表单,做动态交互
是什么:异步的Javascript和xml
作用:通过ajax与服务器进行数据交换,ajax可以使网页实现局部更新,这意味着可以在不重新加载整个网页
的情况下,对网页的某部分进行更新
实现;ajax xmlhttpRrqueset对象,使用这个对象可以异步向服务器发送请求,获取响应,完成局部更新
Open send responseTest/responseXml局部响应
使用场景:登录失败不跳转页面,注册时提示用户名是否存在,二级联动
JQuery是一个js框架,封装了js的属性和方法,并且增强了js的功能,使用户用起来更加遍历,并且增强了
Js的功能
原来是使用js是要处理很多兼容性问题,由JQuery封装了底层,就不用处理兼容性问题,原生js的
Dome和事件的绑定和ajax等操作非常麻烦,jQuery封装了以后,操作非常方便
ID Class 标签 通用 层次 属性
框架(Framework)是一个框子—–具有约束性,也是一个架子—-具有支撑性.
IT语境中的框架,特支为解决一个开放性问题而设计的具有一定约束性的支撑架构.在此结构上可以根据具体问题扩展.安插更多的组成部分.从而更迅速和更方便的构建完整的解决问题的方案.
框架本身一般不完整到可以解决特定问题,但是可以帮助我们快速解决特定问题
框架天生就是为了扩展而设计的
框架里面可以为后续扩展的组件提供很多辅助性,支撑性的方便易用的使用工具.也就是说框架时常配套; 一些帮助解决某类问题的库或工具.
MVC全名是model view Controller,是模型(model)—视图(view)—控制器(Controller)的缩写,是一种软件设计典范.
最简单的,最经典的就是jsp(view)+servlet(Controller)+javabean(model)
1.当控制器收到来自用户的请求
2.控制器调用javabean完成业务
3.完成业务后通过控制器跳转jsp页面的方式给用户反馈信息
4.Jsp给用户做出响应
是为了解决传统的MVC模式(jsp+servlet+javabean)问题而出现的框架.
传统MVC模式问题
1.所有的servlet和servlet映射都要配置在web.xml中,如果项目太大,web.xml就太庞大,并且不能实现模块化管理.
2.Servlet的主要功能就是接受参数,调用逻辑,跳转页面,比如像其他字符编码,文件上传等功能也要写在servlet中,不能让servlet功能单一.
3.接受参数比较麻烦,不能通过model接收,只能单个接收,接收完成后转换封装进model.
4.跳转页面方式比较单一(forward,redirect),并且当页面名称发生变化时,需要修改servlet源代码.
常用的MVC框架:struts2,springMVC
1.浏览器发送请求,经过一系列的过filter,到达strutsPrepareAndExecuteFilter
2.strutsPrepareAndExecuteFilter通过ActionMapper判断当前的请求是否需要某个Action处理,如果不需要,则走原来的流程.如果需要,把请求交个ActionProxy来处理
3.ActionProxy通过Configuration Manager 询问框架的配置文件struts.xml,找到需要调用的Action类;
4.创建一个ActionInvocation实例,来调用Action的对应方法来获取结果集的name,在调用前后会执行相关拦截器
5/通过结果集的name找到对应的结果集来对浏览器进行响应
通过动态配置方式,可以在执行Action的方法前后,加入相关逻辑,完成业务 .struts2中的功能, 都是通过系统拦截器实现的.比如:参数处理,文件上传,字符编码.当然,我们也可以自定义拦截器
使用场景:用户登陆判断,在执行Action的前面判断是否已经登陆,如果没有登陆则跳转到登陆页面;用户权限的判断,在执行Action的前面判断是否具有权限,如果没有给出提示信息;
1.用户发送请求,被前端控制器(DispatcherServlet)捕获(捕获请求)
2.前端控制器进行解析,得到URI,通过URI调用HandlerMapping并获得该Handler配置的所有相关对象(查找Handler)
3.前端控制器根据得到的Handler,选择合适的HandlerAdapter,提取Request中的模型数据,填入Handler入参,开始执行Handler,最后返回一个ModelAndView对象.(执行Handler)
4.前端控制器根据返回的ModelAndViewm,选择合适的ViewResolver(选择ViewResolver)
5.通过ViewResolver结合Model和View来渲染视图,前端控制器将渲染结果返回给客户端(渲染并返回)
核心控制器不同:springmvc是servlet,struts2是filter
控制器实例:springmvc会比struts快(理论上),springmvc是基于方法设计,struts是基于对象,每发一次请求都会实例一个action.springmvc只有一个实例,每次请求执行对应的方法即可,简单来说,springmvc是单例,是trust是多例
管理方式:springmvc是spring的一个模块,所以spring对于springmvc的控制管理更加简单方便.而struts需要使用xml配置很多参数来管理
参数传递:struts2中自身提供多种参数接收,其实都是通过valuestack进行传递和赋值.而springmvc是通过方法参数进行接收.
interceptor的实现机制:struts有自己的interceptor机制,springmvc用的是独立的aop方式.
Springmvc处理ajax请求,直接返回数据,方法中使用注解@ResponseBody,springmvc自动帮我们将数据转成json数据,而struts2是通过插件的方式进行处理
Spring是什么?spring是j2ee应用程序框架,是轻量级的IOC和AOP的容器框架,主要针对javabean的生命周期进行管理的轻量级容器,可以单独使用,也可以跟其它框架组合使用.
IOC(inversion of control)或DI(dependency injection)控制反转
原来:我的service要调用Dao,我就在service中创建Dao对象,这时Dao对象的创建的控制权在我手中
Spring:spring发现我的service依赖于Dao,就给我的service注入Dao对象,这时Dao对象创建的控制权在spring手中
核心原理:工厂模式+反射+配置文件
AOP:面向切面编程
核心原理:使用动态代理的方式在执行前后或出现异常后做相关逻辑.
我们主要使用AOP来做:
事务处理
权限判断
日志记录
AOP:面向切面编程
核心原理:使用动态代理的方式在执行前后或出现异常后做加入相关逻辑.
我们主要使用AOP来做:
事务处理 执行方法前,开启事务,执行方法后提交事务,出现异常后回滚事务
权限判断 在执行方法前,判断是否具有权限
日志记录 在执行方法前执行日志
对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。简单来说,将程序中的兑现自动持久化到关系数据库中。那么,到底如何实现持久化呢?一种简单的反感是采用硬编码的方式(jdbc操作sql方式),为每一种可能的数据库访问操作提供单独的方法。这种方法存在很多缺陷,所以使用ORM框架(为了解决面型对象与关系数据库存在的互不匹配的现象的框架)来解决。
Java典型的ORM框架有:Hibernate,mybatits
瞬时态:刚new的,没有持久化,不在session中
持久态:session中的持久化对象
游离状态:
脱管态:不在session中的持久化对象
Linux是一个长时间运行比较稳定的操作系统,所以我们一般会拿它作为服务器(web,db.app等).
Linux本身具有c的编译环境.我们的一些软件是没有软件包的(redis,nginx),需要在linux编译得到软件包
使用过阿里云
云主机:就是一些云服务运营商(阿里,华为,新浪等)提供的远程服务器功能,我们公司只要付费就可以租用对应的服务器.
定位:查找,定位慢查询,并优化
优化
1.创建索引:创建合适的索引,我们就可以在索引中查询,查询到以后直接找对应的额记录
2,分表:当一张表的数据比较多或者一张表的某些字段的值比较多并且很少使用时,采用水平分表或垂直分表来优化,比如spu表
3,读写分离:当一台服务器不能满足需要时,采用将读写分离的方式进行集群
4.缓存:使用redis来进行缓存
Redis是一个key-value的nosql数据库,先存到内存中,会根据一定的策略持久化到磁盘,即使断电也不会丢失数据,支持的数据类型比较多.
主要用来做缓存数据库的数据和web集群时当做中央缓存存放session
Json字符串:需要把对象转换成json字符串,当做字符串处理,直接使用set和get来设置或获取/
优点:设置和获取比较简单
缺点:没有提供专门的方法,需要把对象转换成json
字节:需要做序列号,就是把对象序列化为字节保存.
如果是担心json转对象会消耗资源的情况,这个问题需要考量几个地方,
1. 使用的json转换lib是否就会存在性能问题
2. 数据的数据量级别,如果是存储百万级的大数据对象,建议采用存储序列化对象方式.如果是少量的数据级对象,或者是数据对象字段不多,还是建议采用json转换成string方式.毕竟redis对存储字符类型这部分优化的非常好.具体采用的方式与方法,还要看你所使用的场景
在 redis 中,允许用户设置最大使用内存大小 server.maxmemory,在内存限定的情况下是很有用的。譬如,在一台 8G 机子上部署了 4 个 redis 服务点,每一个服务点分配 1.5G 的内存大小,减少内存紧张的情况,由此获取更为稳健的服务。
内存大小有限,需要保存有效的数据?
Redis内存数据集大小上升到一定大小的时候,就会施行平台策略.数据淘汰策略.redis提供6中数据淘汰策略:
1.volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
2.volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
3.volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
4.allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
5.allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
6.no-enviction(驱逐):禁止驱逐数据
1.需求:用户量,这个客户说了算,大概也就是1-5年内用户总量
2.根据pv(页面点击量,浏览量)和uv(ip数量)预估,大致能达到多大的并发量.我们的项目大概能达到1000-3000的并发量
3.确定我们的服务器数量,我们使用的是tomcat,tomcat的默认线程数150,我们可以将它优化调到400左右.而我们大致需要5台web服务器
4.重要的因素(硬件服务器水平—去IOE),我们没有做这个,因为我们没钱.
1.广播:会造成内网网络风暴,大量占用内网宽带
2.IP_hash:在nginx中配置和,相同的ip找固定的同一台服务器,这种方案会造成服务能力差
3.使用第三方中间件(数据库,redis),我们是使用redis
1.硬编码:在相应的代码中增加索引库同步的代码。不过,这种方法耦合度太高,将原本不相关的系统耦合在了一起,容易造成不可预估的错误,是电商项目的大忌。
2.spring的aop:编写一个索引库同步的方法,利用aop的形式,将它和数据库数据更新的方法联系起来。这种方式也会造成耦合。
3.消息队列:不过,这个方法会造成一个问题,那就是消息消费失败问题。
:解决两个系统间的通信问题。
消息消费失败:集中同步索引库,做一个定时任务。在消息队列所在的服务器上加一个数据库,我们使用的是redis缓存。消息队列中每发一条信息,就将这条信息持久化进redis中。接着定时(我们是在晚上,用户量少的时候)从redis中将消息列表取出来,批量同步索引库。
当商品规格出现不同组合时,它的价格势必会不一样,这时怎么在静态页面中处理价格这样的数据?
像价格这样的数据,只有我们在生成静态页面时才会和数据库交互一次,查出所有的sku,将这些sku存进集合中。接着,我们在前端js中定义一个变量来存储集合的值,当以后用户每一次来访问我们的静态页面时,他都是从静态页面的js变量中自动获取价格这样的数据。
需要什么样式的数据?接口的请求方式?返回值类型?
因为事务!如果是在controller层发送消息,那么controller层调用的service一定是完成了事务提交操作的。如果是在service层发送消息,那么事务可能会没有提交,会造成空指针异常。
传送商品id:
好处:传送的是商品id,传输的内容少,效率相对较高,不会产生消息阻塞。
缺点:消费方需要再次查询数据库取出商品信息,和数据库多了一次交互。
传送商品信息:
好处:这样消费者就不需要再次从数据库中查询商品信息数据,减少了与数据库的交互。
缺点:传输的是商品信息,传输内容相对较少(原因:文本信息在网络传输中占用的网络资源最少),可能会产生消息阻塞的问题,但是由于我们的消息的发送不是连续的,不会有太高的并发量(原因:消息的发送时需要运营商平台审核通过后才发送的。)
秒杀业务最主要的操作:减库存和添加订单
1.第一种方式:数据库(中小型网站)
Update goods set num=num-1 where id=id;
Insert orders values() where goods.id=goodsid
为了保持数据的一致性,需要使用事务
优化:
①数据库服务器和秒杀服务器在同一个机房
②避免使用事务,使用数据库的存储过程来完成业务单元
存储过程逻辑:避免使用事务
(1)判断库存(num)
(2)如果num>0,执行update和insert操作
(3)如果num<0,秒杀结束
2.第二种方式:缓存(redis)(中大型网站)
将秒杀商品和订单都存在redis中,用户下单时,num>0?下单(num-1):秒杀结束;
HashMap在JDK1.8及以后的版本中引入了红黑树结构,若桶中链表元素个数大于等于8时,链表转换成树结构;若桶中链表元素个数小于等于6时,树结构还原成链表。因为红黑树的平均查找长度是log(n),长度为8的时候,平均查找长度为3,如果继续使用链表,平均查找长度为8/2=4,这才有转换为树的必要。链表长度如果是小于等于6,6/2=3,虽然速度也很快的,但是转化为树结构和生成树的时间并不会太短。
还有选择6和8,中间有个差值7可以有效防止链表和树频繁转换。假设一下,如果设计成链表个数超过8则链表转换成树结构,链表个数小于8则树结构转换成链表,如果一个HashMap不停的插入、删除元素,链表个数在8左右徘徊,就会频繁的发生树转链表、链表转树,效率会很低
缓存架构(KyotoCabinet、Memcached等)的先进先出队列,
不能随便加锁,淘宝的双11活动。很明显的一点是商品没有提供一个非常即时的锁,即便商品实际没有了也是可以下单成功的。但是在支付的时候会提示你商品没有了。猜测只是在支付的时候才有即时的锁。
单点登录并不是为移动端准备的,移动端有自己的登录方式。单点登录是解决在同一个公司
内部多个互信网站之间进行跳转时不需要多次登录,多个系统统一登录入口。
单点登录的核心是如何在多个系统之间共享身份信息
首先 Solr 是不会丢失个别数据的。如果索引库中缺少数据,那就向索引库中添加
HTTP:是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少。
HTTPS:是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。
HTTPS协议的主要作用可以分为两种:一种是建立一个信息安全通道,来保证数据传输的安全;另一种就是确认网站的真实性。
区别:
1、https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
3、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
4、http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
序列化一般是指把结构化的对象变成无结构的字节流,便于存储、传输
首先序列化并不是JAVA所独有的,基本所有编程语言都提供了序列化的方式,序列化是编程的一种解决问题的方式。JAVA序列化就是将对象按照某种协议格式(某种约定方式)放入一个buffer中,其目的是便于网络传输或持久存储。反序列化,就是将序列化后的buffer按照序列化时还原成原来的对象,这样程序就能直接使用还原的对象了。
单位时间内请求次数超过某个阈值就让输入验证码,可以极大降低抓取的速度,如果多次超
过某个阀值可以加入黑名单。还有就是页面内容使用 json 返回,数据经常变一变格式,或
者 js 动态生成页面内容
分库情况下:可以使用 mycat 数据库中间件实现多个表的统一管理。虽然物理上是把一个表
中的数据保存到多个数据库中,但是逻辑上还是一个表,使用一条 sql 语句就可以把数据全
部查询出来。
单库情况下:需要动态生成 sql 语句。先查询订单相关的表,然后将查询多个表的 sql 语句
使用 union 连接即可
1.BeanFactory: BeanFactory采用了工厂设计模式,负责读取bean配置文档,管理bean的加载,实例化,维护bean之间的依赖关系,负责bean的生命周期。
2.ApplicationContext:除了提供上述BeanFactory所能提供的功能之外,还提供了更完整的框架功能:国际化支持、aop、事务等。
3.BeanFactory在解析配置文件时并不会初始化对象,只有在使用对象getBean()才会对该对象进行初始化,而ApplicationContext在解析配置文件时对配置文件中的所有对象都初始化了,getBean()方法只是获取对象的过程。
Spring 是一个“引擎”;
Spring MVC 是基于Spring的一个 MVC 框架 ;
Spring Boot 是基于Spring4的条件注册的一套快速开发整合包:
1. 创建独立的Spring应用程序
2. 嵌入的Tomcat,无需部署WAR文件
3. 简化Maven配置
4. 自动配置Spring
5. 提供生产就绪型功能,如指标,健康检查和外部配置
6. 绝对没有代码生成和对XML没有要求配置
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。