1.HTTP协议? HTTP协议响应结果状态码?
HTTP协议:
超文本传送协议,是用于从WWW服务器传输超文本到本地浏览器的传输协议.
HTTP协议是建立在TCP协议上的一种应用.
HTTP特点:
客户端发送的每次请求都需要服务器回送响应,在请求结束后,会主动释放连接.
HTTP协议响应结果状态码:
1**:信息性状态码
2**:成功状态码
200:请求正常成功
204:请求成功但没有返回新信息
206:服务器已经完成对资源的本分GET请求
3**:重定向状态码
301:永久性重定向
302:临时性重定向
304:服务器端允许请求访问资源,但为满足条件
4**:客户端错误状态码
400:请求语法错误
401:发送的请求需要有通过HTTP认证的认证信息
403:请求资源的访问被服务器拒绝
404:请求参数有误
405:请求路径有误
5**:服务器错误状态码
500:服务器端在执行请求时发生错误
503:服务器暂时处于超负荷或正在进行停机维护,现在无法处理请求.
2.TCP和UDP的区别? TCP建立连接三次握手?
TCP的11种状态? 断开连接四次挥手?
TCP:
传输控制协议,是一种面向连接的,可靠的,基于字节流的传输层通信协议,.
UDP:
用户数据报协议,是OSI(开发式系统互联)参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传输服务.
TCP和UDP区别:
1.TCP面向连接的,可靠的数据流传输
UDP非面向连接的,不可靠的数据流传输.
2.TCP面向字节流,UDP面向报文.
3.TCP连接只是点到点的
UDP支持一对一,一对多,多对一和多对多的交互通信
4.TCP首部开销20字节 UDP首部开销8字节
5.TCP的逻辑通信信道是全双的可靠通道
UDP的逻辑通信信道是不可靠信道
TCP的状态:
1. closed:初始状态
2. listen: 服务器端的某个socket处于监听状态,可以接收客户端的连接
3. syn_rcvd:服务器接收客户端请求连接的syn报文
4. syn_send: 等待服务端发送三次握手中的第2个报文
5. establised: 表示TCP连接已经成功建立
6. fin-wait_1: 等待对方的fin报文,想主动关闭连接,向对方发送了fin报文.
7.fin-wait_2: 当对方回应ack报文后,进入此状态.
8. time_wait: 收到对方的fin报文,并发送ack报文
9. closing: 双方都正在关闭socket连接,双方同时发送fin报文,一方发送fin报文后没有收到对方的ack报文,反而收到对方的ack报文
10.close_wait: 对方close()一个SOCKET后发送FIN报文给自己,你的系统毫无疑问地将会回应一个ACK报文给对方,此时TCP连接则进入到CLOSE_WAIT状态
11. last_ack: 当被动关闭的一方在发送FIN报文后,等待对方的ACK报文的时候,就处于LAST_ACK 状态。当收到对方的ACK报文后,也就可以进入到CLOSED 可用状态了。
TCP建立连接三次握手:
客户端发送syn报文给服务器端,进入syn_send状态
服务器端收到syn报文,回应一个syn报文,进入syn_rcvd状态
客户端收到服务器端的syn报文,回应一个ack报文,进入establised状态
断开连接四次挥手:
1.某个应用程序首先执行close(主动关闭),该段的TCP发送fin分节
2.接收到这个fin的对端执行(passive close)被动关闭
3.接收到这个文件结束符的应用进程将调用close关闭它的套接字,它的TCP也发送一个fin
4.接收这个最终fin的原发送端TCP(即执行主动关闭的那一端)确认这个fin
既然每个方向都需要一个FIN和一个ACK,因此通常需要4个分节。
3. MyBatis中$和#在xml中取值有什么不同?
1.$和#都可以充当占位符
$符号的底层是由statement实现的, #底层是由ReparedStatement实现的
2.#是先编译sql语句在传值,传入的值都加上双引号
$是直接拼接字符串,不会给传入的值加上双引号
3.$会造成sql注入问题, #不会
4.只有在传入数据库对象时才会传入$
(1)按照某个表进行查询时传入表名
(2)按照某一列进行排序时传入列名
5.传入数据库对象时,做好都是用 #.
4. &和&&的区别? | 和 ||的区别?
&&:只执行一边,如果第一个条件为假,则不会走第二个条件
&: 会执行两边,不管第一个条件是否为假
||: 只要满足第一个条件,后面的条件就不在判断
|: 对所有的条件都进行判断
5.GET和POST的区别?
1.在服务器上获取数据,一般不能使用在写操作接口;
向服务器提交数据,一般处理些业务
2.GET传输的数据量有限制,不超过2KB;
POST不限制传输的数据量
3.GET安全性差,POST安全性好
4.GET请求的的数据会附加在URL之后,以?分隔URL和传输数据,多个参数用&连接
POST请求的数据内容放置在HTML,Header中
6.ArrayList和LinkedList的区别?
ArrayList为什么查询快? LinkedList为啥增删快?
List 有序的(存储顺序和取出顺序一致)可以通过下标获取,可重复
ArrayList:底层数据结构是数组,查询快。线程不安全,效率高
LinkedList:底层数据结构是链表,增删快。线程不安全,效率高
ArrayList中的数据是连续的,成块的,查找的时候直接遍历内存就可以了.
实现了长度可变的数组,在内存中分配连续的空间
LinkedList是一个由相互引用的节点组成的双向链表,把数据插入到该链表某个位置时,该数据就会被组装成一个新的节点,随后只需要改变链表中对应的两个节点之间的引用关系,使它们指向新节点,即可完成插入.
删除数据时们只需要删除对应节点的引用即可.
7.HashMap和HashTable的区别?
Map:采用健---值对的存储方式,是无序的
健和值都必须是对象,健是唯一的,值可以重复。健就等同于下标
HashMap:存储顺序和遍历顺序不一定一致,健和值都可以为null;
HashTable:和HashMap类似,健和值不可以为null,线程安全
LinkedHashMap:和HashMap类似,健和值不可以为null,线程安全
TreeMap:按照健升序排列
8.接口和抽象类有什么区别?
抽象类:
被abstract修饰的类称为抽象类
对于一个父类,如果它的某个方法在父类中实现出来没有任何意义,
必须根据子类的实际需求来进行不同的实现,那么就可以将这个方法声明为abstract类
接口(interface):
供别人调用的方法或者函数
接口的变量会被隐式的指定为 public static final变量
方法被隐式的指定为 public static 方法
抽象类和接口的区别:
1)抽象类可以提供成员方法的实现细节,而接口只能存在public abstract方法
2)抽象类的成员变量可以是多种类型的,而接口的成员变量只能是pubic static final类型
3)接口不能含有静态代码块和静态方法,而抽象类可以有静态代码块和静态方法
4)一个类只能继承一个抽象类,而一个类可以实现多个接口
抽象类和接口是解决单继承规定限制的重要手段
9.Cookie和Session的区别?
1.Cookie数据存放在浏览器上,session数据存储在服务器上。
2.cookie数据不是很安全,别人可以分析存放在本地cookie并进行cookie欺骗
3.cookie 最大存储是4KB内容,用户再次打开网页是会自动填充该信息。
session没有限制大小。
4.session为一个用户浏览器独享,cookie为多个浏览器
5.生命周期(session:30分钟,cookie:30天)
以20分钟为例:
cookie的生命周期是累计的,从创建开始及时,20分钟结束。
session的生命周期是间隔的,从创建开始计时,如果20分钟未访问session,那么 session的生命周期自动结束。
但是如果20分钟内fang访问过session,那么重新计算session生命周期
6.cookie只能保存字符串类型,以文本的方式,
session能支持任何类型的对象(session可以含有多个对象)
7.当访问增多,session会比较占用服务器性能,
考虑减轻服务器性能用cookie
8.关机会造成session生命周期结束,但是对cookie没影响
10.Spring SpringBuffer 和 SpringBuilder的区别? 使用场景?
(1)执行速度: SpringBuilder > SpringBuffer > Spring
Spring为字符串常量,SpringBuilder和SpringBuffer为字符串变量.
Spring一旦创建之后对象是不可更改的,后两者是可以更改的.
(2)线程安全:
SpringBuilder没有线程锁,是线程不安全的. Spring和SpringBuffer是线程安全的
多线程: 用StringBuffer
单线程: 用速度较快的StringBuilder
SpringBuffer和Spring的区别?
使用SpringBuffer类的时候,对内容进行了更改,对象不会发生更改,不会产生新的字符串
String当字符串的内容发生改变,就会产生新的字符串
使用场景:
String:用于少量的字符串操作的情况
StringBuffer: 多线程下在字符缓冲区进行大量操作的情况
StringBuilder: 单线程下在字符缓冲区进行大量操作的情况
11.直接赋值和new的区别?
直接赋值的话,值会在常量区中,
用new的话会在堆区开辟一块内存空间进行赋值,并且会去查找常量区有没有该值,没有的话添加进去.
字符串如果是直接赋值,先在字符串常量池中找有没有该值,如果有直接赋值,没有,在常量池中增加该值.是多个对象指向同一个内存空间
12.比较两个字符串是否相等?
s1==s2:比较的是连个字符串的内存地址
s1.equals(s2):比较的是两个字符串的一一内容
13.创建线程的方式? 进程? 线程? 单线程? 多线程?
并发? 同步? 异步? 多进程? 多线程?
线程锁? 线程池? 阻塞线程方法? 线程的生命周期?
线程死锁是如何产生的? 如何防止线程死锁?
多线程中run和start方法有什么区别?
进程和线程的区别?
创建方式:
1.继承Thread: 重写run()方法
有开辟线程的能力,资源共享方面不是方便.
2.实现 Runnable接口:实现该接口的run()方法
创建了一个任务对象,做到资源共享,多个线程可以执行同一个任务;
没有开辟线程的能力,要将创建的对象交给指定线程来执行
进程:
一个正在运行的程序,拥有该程序运行的所有资源,负责资源的分配和任务的调度
线程:
在进程中负责具体代码的执行,一个进程中至少有一个线程
1.单线程: 整个程序中只有一个线程,这个线程就是主线程.
2.多线程: 整个程序中不只有一个线程,除了主线程,剩余的线程就是子线程
当我们执行多个独立的任务时,为了效率更高,我们可以将多个任务分别让不同的线程来执行,多个线程之间并发执行.用内存空间换取高效率.
并发:
多个任务独立执行,一起执行
异步:
一个线程中,多个任务可以同时执行,互不影响
同步:
同一时刻只能执行一个任务,该任务执行完毕,才可以执行下一个任务.
多进程:
操作系统能同时运行多个任务(程序)
多线程:
在同一程序中有多个顺序流在执行
线程锁:
当多个线程访问资源时,为了数据安全,保证当一个线程正在访问该资源时,
其它线程就不能访问,等待上一个线程访问完毕,才能访问
同步锁:
<1>synchronized修饰方法时:
多个线程在调用 它修饰方法时,一次只能有一个线程在执行该方法
<2>synchronized(对象){
同步代码块:同一个对象锁下的所有线程,某个时间段内只能有一个线程在执行该代码块
如果多个线程要达到同步的目的,保证同步锁的对象时同一个对象
}
阻塞线程方法:
1. Thread.sleep(3000); //沉睡3秒
2.同步线程锁:
synchronized(slock) {
//当前线程执行到此处将同步锁权限让出,当同步锁中的其它线程唤醒之后,wait()线程接着往下执行
slock.wait();
//当前线程暂停运行,当操过时长时间之后,还没有被唤醒,就不等其它线程唤醒了,接着执行.
slock.wait(时长毫秒);
//唤醒同一个对象锁中其它线程中的某一个wait(),让其它线程接着往下执行.
slock.notify();
slock.notifyAll(); //全部唤醒
}
线程的生命周期:
创建状态(new)--->
就绪状态(start)--->
运行状态
(等待CPU调用run方法,如果在运行中发生阻塞,进入阻塞状态,线程进入阻塞状态 之后,又回到就绪状态,等待CPU再次调用)---->
结束状态(run方法执行完毕)
线程池:
帮助我们管理线程,我们只需要将需要执行的任务及交给线程池,线程池会根据任务的个数,执行时长等,会将不同的任务交给线程池中的线程执行
(1)缓存线程池:
默认给最大线程池参数赋值为Integer.MAX_Value,不限制开辟线程个数
任务来时,如果前面的线程有闲置的,就直接使用
如果没有闲置的线程,就开辟线程来执行任务
ExcutorService sc = Executors.newCachedThreadPool( );
for ( int i = 0; i < 20; i++ ) {
sc.execute ( new Runnable ) {
@Override
punlic void run( ) {
System.out.println( Thread.currentThread( ).getId( ) );
}
} );
if ( i == 10) {
//将现有任务执行完毕,新任务拒绝执行
sc.shutdown( );
}
sc.shutdownNow( ); //立即停止
(2)固定线程数线程池:
我们可以定义线程数量,如果新任务来时,所有线程都在使用中,新任务就等待线程闲置
ExecutorService sv = Executors.newFixedThreadPool(3)
(3) 周期性线程池:让多个任务周期性执行
ScheduledExecutorServic ss = Executors.newScheduledThreadPool(3);
ss.scheduleAtFixedRate ( new Runnable( ) {
@Override
public void run( ) {
System.out.println( new Date( ) );
try {
Thread.sleep(2000);
} catch(InterruptedException e) {
}
}
}, 3, 4, TimeUnit.SECONDS );
第一个参数: 要周期性执行的任务
第二个参数: 延时多久开始整个周期
第三个参数: 每个任务时间间隔
当任务时间间隔 > 任务执行时间 间隔时间就是我们制定的时间
当任务时间间隔 < 任务执行时间 用执行时间
第四个参数: 事件单位
ss.scheduleWithFixedDelay( new Runnable( ) {
}, 0 , 2, TimeUnit.SECONDS ) ;
不管任务执行的时长是否比制定的间隔时间大还是小,一个任务执行完成,等指定的间隔时间之后才能执行下一任务.
(4)单线程线程池:
等同于第二种线程池将线程的数量值指定为 1
ExecutorService sc = Executors.newSingleThreadExecutor();
for ( int i = 0; i < 10; i++) {
sc.execute ( new Runnable( ) {
@Override
public void run( ) {
System.out.println(Thread.currentThread( ).getId( ));
try {
System.out.println( new Date( ));
Thread.sleep(1000);
} catch (InterruptedExceotion e) {
}
}
} );
}
线程死锁:
多个线程因竞争资源而造成的相互等待,若无外力作用这些进程都将无法向前推进
线程死锁产生:
1.一个进程因请求发生阻塞,依然对已获得的资源保持不放
2.进程已经获得资源使用权,但是一直未使用
3.同一个进程,频繁的获取资源的使用权,一直未释放
4.系统资源的竞争
5.进程推进顺序非法,进程在运行过程中,请求和释放资源的顺序不当
防止线程死锁:
1. 加锁顺序(线程按照一定的顺序加载)
2.加锁时限(线程尝试获取锁的时候加上一定的时限,超过时限则放弃对该锁的请求,并释放资 源)
3.死锁检验(一般是将所有的锁存放在map对象中,检测map中的锁)
run和start方法的区别:
Thread的start才是正在开启线程
Run
只是调用了一个普通的方法,,并没有启动另一个线程,程序还会按照顺序执行响应代码
Start:
重新开启一个线程,不必等待其它线程运行完,只要得到cut就可以运行该线程
进程和线程的区别?
1.进程时资源的分配和调度的一个独立单元,而线程是CPU调度的基本单元
2.同一个进程中可以包括多个线程
3.进程结束后它拥有的线程都将销毁,而线程的结束不会影响同个进程中的其它线程的结束
4.线程共享整个进程的资源(寄存器,堆栈,上下文),一个进程至少包括一个线程
5.进程的创建调用fork或者vfork,而线程的创建调用pthread_create
6.线程中执行时一般都要进行同步和互斥,因为它们共享进程的所有资源
14.MyBatis接口映射规则?
MyBatis是面向接口的编程:
可以将配置文件当成是接口的实现类,最终会根据该配置文件生成对应接口的实现类
1.namespace: 需要写成接口的完整类名(包名+ 接口名)
2.sql语句的id必须是对应的方法名
3.parameterType: 必须和方法的参数的类型保持一致
4.resultType: 必须和方法的返回值保持一致
15. MyBatis多表联查:
一对多步骤:
(1): 一方: 定义和多方相关联的属性 List<Room> rooms;
多方: 定义和一方相关量的属性 private Store store;
(2)多方表: 多一个字段作为外键,此外键是和一方的主键关联
create table if not exists student
(sid Integer primary key auto_increment,
sname varchar(20),
sage Integer,
s_t_id Integer,
constraint student_teacher_foreign foreign key(s_t_id) references teacher(tid)) charset=utf8;
(3)一方的配置文件
<!-- namespase要写成接口的完整类名+包名 -->
<mapper namespace="com.yangsheng.dao.StoreDao">
<!--建立多表的关联-->
<resultMap type="实体包名+类名" id = "StoreMap">
<!-- 一方的属性映射文件 -->
<id column="sid" property="sid"/>
<result column="" property=""/>
------
<!--多方实体和查询出来的字段的匹配-->
<collection property="集合的属性名称" ofType="集合中元素的类型">
<!-- 多方的属性映射文件 -->
<id column="rid" property="rid"/>
<result column="" property=""/>
------
</collection>
</resultMap>
</mapper>
(4)多方的配置文件
<!--多方的配置文件中的resultMap中-->
<association property="一方的属性名" javaType="属性类型">
</association>
多对多步骤:
(1)中间表: 其中一个字段为表一的外键,另一个字段为表二的外键
//建立中间表
create table if not exists p_h_rel
(rid Integer key auto_increment,
p_f_id Integer,
h_f_id Integer,
constraint player_rel_foreign foreign key(p_f_id)references player(pid),
constraint hero_rel_foreign foreign key(h_f_id) references hero (hid))charset=utf8;
(2)在各自的resultMap中<collection></collection>
一对一步骤:
(1)在表2中增加一个字段是表1的外键,并且加唯一约束
create table if not exists employee
(eid Integer primary key auto_increment,
ename varchar(20) ) charset = utf8;
//在表2中增加一个字段是表1的外键,并且加唯一约束
create table if not exists computer
(cid integer primary key auto_increment,
cname varchar(26),
c_e_id Integer unique, //建立约束
constraint computer_employee_foreign foreign key (c_e_id) references employee (eid))charset=utf8;
(2)在各自的resultMap中<association></association>
16.Hibernate一级缓存和二级缓存区别:
一级缓存:
session级别缓存,一级缓存不可卸载,只要使用了session,肯定用到了session的缓存机制,不能手动配置
当使用get load find query等查询出来的数据,默认在session中有一份缓存数据,缓存数据是在数据库中将一些数据拷贝一份放到对应地方.
清理一级缓存: close clear(全部清理)
二级缓存:
sessionFactory级别的缓存,可以做到多个session共享此信息
适合放在一级缓存的数据:
(1)经常被修改的数据
(2)财务数据,决不允许出现并发
(3)与其它应用共享的数据
适合放在二级缓存的数据:
(1)经常被修改的数据
(2)不是很重要的数据,允许出现偶尔并发的数据
(3)不会被并发访问的数据
(4)参考数据
查询缓存:
Hibernate的二级缓存策略是针对ID查询的缓存策略,对于条件查询则无用.
Hibernate提供了条件查询的query缓存.
开启查询缓存,如果不开启,每次查询只存主键,开启后可以存其它字段,拿到一条完成的记录.
<!-- 二级缓存配置 -->
<!--指定使用哪一个缓存框架(默认提供的) -->
<property name="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property>
<!-- 开启查询缓存 -->
<property name="hibernate.cache.use_query_cache">true</property>
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.internal.NoCachingRegionFactory</property>
<!-- 设置使用二级缓存 -->
<property name="hibernate.cache.use_second_level_cache">true</property>
<!-- 引入映射文件 -->
<mapping resource="com/xalo/model/ClassRoom.hbm.xml"/>
<!-- 设置使用二级缓存的策略 -->
<class-cache usage="read-only" class="com.xalo.model.ClassRoom"></class-cache>
17.MyBatis查询缓存(一级缓存和二级缓存)
MyBatis默认支持一级缓存,不需要任何的配置
一级缓存:
是SqlSession级别的缓存,在操作数据库时,需要构造SqlSession对象,在对象中有一个数据结构(HashMap)用于缓存存储数据.不同的SqlSession之间的缓存数据区域(HashMap)互相不影响.
二级缓存:
是mapper级别的缓存,多个SqlSession去操作同一个mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的.
18.Hibernate二级缓存和MyBatis二级缓存的区别?
相同点:
二者二级缓存除了采用系统默认的缓存机制外,都可以通过实现你自己的缓存或第三方缓存方案,创建适配器来完成覆盖缓存行为
不同点:
1).hibernate对查询有良好的管理机制,用户无需关系SQL,
在使用二级缓存如果存在脏数据,系统会自动报错.
Mybatis使用二级缓存需小心,脏数据的出现会对系统的正常运行带来很大隐患
2).Hibernate的二级缓存配置在sessionFactory生成的配置文件中进行详细的配置,
然后在具体的表一对象映射中配置时那种缓存
Mybatis二级缓存是在每个具体的表一对象映射中进行详细配置,
可以针对不同的表自定义不同的缓存机制
并且Mybatis 在命名空间中共享形同的缓存机制和实例.通过Cache-ref实现
19.面向对象的特征? 重写和重载的区别?
封装 继承 多态
封装:
将多次重复使用的功能或者模块,封装为类或者方法,在使用时直接调用方法即可.提高了代码的复用性
继承:
将一类事物共同的特征和行为定义在一个类中,这一类事物都继承自该类,共同的特征就不用多次书写.
类的继承都是单继承,继承具有传递性.
多态:
同一种事物或行为体现出来的不同状态
多态的体现: (1)方法的重写重载
(2)父类对象引用子类内存空间
重写和重载的区别:
重写(Override):
当从父类继承过来的方法不能满足我们的要求,我们就需要重写(覆盖)父类该方法
重写特征:
(1) 方法是从父类继承过来的
(2)方法的返回值,方法名,参数类型和参数个数必须和父类保持一致
(3)重写的修饰符范围 >= 父类的修饰符范围
重载(Overload):
(1)一般发生在本类中
(2)方法名必须一样,参数类型,参数个数必须不一样
(3)父类对象引用子类内存空间
父类名 对象名 = new 子类名();
20.Hibenate与Mybatis区别?
ORM? 常用的ORM框架?
ORM(Object Relational Mapping):
对象关系映射
在关系型数据库和业务实体对象之间作一个映射,这样,我们在具体的操作业务对象的时候,就不需要再去和复杂的sql语句打交道只需要简单的操作对象的属性和方法
用于实现面向对象语言里不同类型之间的转换,其实是创建了一个可编译里使用了"虚拟对象数据库"
面向对象是从软件工程基本原则(耦合,聚合,封装)的基础上发展起来的
关系型数据库则是数学理论发展而来的.ORM是一种为了解决面向对象与关系型数据库存在的不匹配的现象的技术
常用的ORM框架:
1)Hibernate全自动需要些hql语句
2)iBATIS半自动自己写sql语句,可操作性强,小巧
3)EclipseLink 一个可扩展的支持JPA的ORM框架,供强大的缓存功能,缓存支持集群。
4)Apache OJB等等
相同点:
1.Hibernate与MyBatis都是通过SessionFactoryBuilder由XML配置文件生成 SessionFactory,由SessionFactory生成Session,由session开启执行事务和sql语句
2.Hibernate和MyBatis都支持JDBC(java DataBase Connectivity,java数据库连接池)和 JTA(java Transaction API,java事务 API(Application Programming Interface, 应用程序编程接口) )事务处理
3.基于ORM(Object Relational Mapping,对象关系映射)思想解决了entity和数据库的映 射问题
不同点:
1.mybatis通过mapper.xml维护映射结果,程序员手动编写SQL相比
Hibernate自动生成hql(hibernate hql)更加了灵活.sql调优更加容易
2.Hibernate数据库移植性很好,
MyBatis的数据库移植性不好,不同的数据库需要写不同SQL。
3.Hibernate在数据量大,表多的时候,基于关系操作会变得复杂.
Hibernate在级联删除的时候效率低
4.Mybatis和Hibenate都可以使用第三方缓存,
而Hibernate相比Mybatis有更好的二级缓存机制
5.Hibernate自己提供分页功能,mybatis需要配置分页插件
21.SpringMVC的执行流程, Struts2和SpringMVC的区别?
执行流程:
1.用户向服务器发送请求,请求被DispatcherServlet捕获
2.DispatcherServlet根据捕获的URL,获取请求资源标识符URI,调用HandlerMapping(处理器映射器)
3.HandlerMapping获得Handler配置的相关对象
(Handler对象和Handler对应的拦截器),最后以HandlerExecutionChain的形式返回给DispatcherServlet
4.DispatcherServlet根据返回的Handler对象,选择合适的HandlerAdapter(处理器适配器)
5.HandlerAdapter经过适配调用具体的处理器(Controller),
Controller执行完返回ModelAndView,
HandlerAdapter将Contoller执行结果ModelAndView返回给DispaterServlet.
6.DispaterServlet将ModelAndView交给视图解析器(ViewReSolver),
ViewReSolver根据View找到对应的视图将model数据渲染到界面上.
7.ViewreSolver将结果(jsp/jsf.....视图)返回给DispaterServlet
8.DispatcherServlet将结果发返回给前端
SpringMVC和Struts2的区别?
1.加载机制不同:
Struts2的核心是一个基于Filter即StrutsPrepareAndExecuteFilter
SpringMVC的核心是一个基于Servlet即DispatcherServlet
2.SpringMVC在性能上比Struts2块些.
(1) Strruts2是类级别的拦截,每次来了请求之后都创建一个Action,
然后调用set get方法将request中的数据注入
(2) SpringMVC是方法级别的拦截,
过滤后去Controller中找对应与@RequestMapping注解URL绑定的方法
3.参数传递
Struts2接收参数时,可以用成员属性来接收参数,参数是可以让多个方法共享的
SpringMVC的方法基本上是独立的,独享request.response数据,
请求数据通过参数获取,处理结果通过ModelMap交回给框架,方法之间不共享变量.
4.Ajax交互
SpringMVC处理Ajax的请求十分方便只需要一个注解
@ResponseBody然后返回响应文本即可.
Struts2拦截器集成了ajax,在action处理时,
必须安装插件或者自己写代码进去,使用起来不方便.
5.拦截机制的实现
SpringMVC用的是独立的Aop方式实现
而Struts2有自己的拦截机制,导致Struts2的配置文件比SpringMVC大
22.字节流和字符流的区别? 缓冲区?
字节流:按字节读写
字符流: 按字符读写
通常在处理文本时优先使用字符流,其它使用字节流
字节流在操作时本身不会用到缓冲区(内存),是文件本身直接操作的.
字符流在操作时使用了缓冲区,通过缓冲区再操作为文件
缓冲区:
一个程序频繁的操作一个资源(文件或者数据库),性能就会降低,可以将一部分数据暂时的读入到内存的一块区域中,以后直接从区域中读取数据即可
23.Spring常用注解?
1.@Component: 标注一个spring Bean类
可以代替@Repository, @Service, @Controller. 因为这三个注解是被@Component标注的
2.@Repository(value="userDao"):标注一个dao组件类
在Spring的IOC容器中指定一个dao层的bean,如果value不指定默认该对象的类名,
如果指定,id为value的值
3.@Service(value="userSerivice"): 标注一个业务逻辑组件类
4.@Controller: 标注一个控制器组件类,表明当前类是有个处理器
将当前实体交给spring管理,等同于在IOC配置了
<bean id="FirstController" class="包名.类名">
value指定Bean的id名称,如果不指定默认为类名,
如果Controller中只配置value,可以省略value直接写值
5.@ResponseBody:
接收前端传递过来的json数据,当返回值不是逻辑视图名称,而是一组数据,
相当于response中的writer方法response.getWriter().writer("方法的返回值")
6.依赖注入:
@Autowired(requirted=false):
默认是type注入,如果想id注入,就要配合@Qualifier注解使用
required:如果找不到bean注入 true(默认),
异常false:不注入即可,不会报异常
@Qualifer: 配合上面的注解使用,byName
@Resourse: 按照id注入, javaEE提供的依赖注入的注解1.6之后才可以使用
24.Spring ? IOC? AOP? DI?
底层实现原理是什么?
DI是如何实现的?
Spring如何管理事务?事务的传播特性和隔离级别?
Spring:
spring是一个轻量级别(基本版本2MB)的控制反转(IOC)和面向切面的(AOP)的容器框架
IOC: 控制反转
之前我们都是自己创建对象,管理对象.控制反转就是将对象的管理交给spring,我们只需要使用对象即可,实现了松散耦合.
DI: 依赖注入
IOC的一种特殊体现形式,配合接口达到不同层之间的解耦
我们在使用A对象的时候,在A对象的内部必须依赖B的对象,我们在获取A对象时,将B对象注入到A对象中
DI不能单独存在,要在IOC的基础上完成操作,既要先创建对象才能注入属性值
AOP:面向切面的编程
对面向对象的完善和补充,就是将面向对象中各个不同的业务模块所使用到的共同的功能提取出来,通过动态代理模式在不影响现有业务模块的前提下,为业务模块扩展功能
所以一般AOP都是用在一些系统级别的功能配置上
本质: 是在一系列纵向流程中,把那些相同的子流程提取成一个横向的面,它所面对的是处理过程中某个步骤或阶段,以获得逻辑过程中各部分之前低耦合的隔离效果
在程序开发中主要用来解决系统层面上的问题,比如日志,事务,权限等待.
连接点(关注点/拦截点)joinPoint: 需要增加额外功能的方法
切入点pointcut: 所有连接点的集合
通知advice: 定义了要为切入点增加的额外功能
代理proxy: 将额外的功能切入切入点
织入weavng: 根据代理的规则,将额外功能添加到切入点
目标对象target: 连接点所在的对象
切面aspect: 封装横切关注点信息的类,每个关注带你体现为一个通知方法
通知类型:
1.前置通知:在连接点之前添加的功能,指定的通知里面的方法会在连接点之前执行
2. 后置通知: 在连接点之后添加的功能,连接点的方法中无论是否发生异常,都照常执行
3. 后置异常通知: 在连接点发生异常之后,才会添加的功能
4.后置成功通知: 在连接点正常执行的情况下,才会添加的功能
5.环绕通知: 可以更加灵活的在连接点执行之前,之后添加功能
IOC和DI的底层实现原理:
IOC底层实现:
IOC容器时创建对象和处理对象之间的依赖关系. 工厂模式+ 反射机制
项目中具体的创建都是Spring容器帮助我们创建的,即通过控制反转和依赖注入.实现都是通过反射机制实现的
通常有三种创建方式:
1.通过静态工厂创建对象
(1)根据id获取工程的类名
(2)通过调用factory-method来指定创建bean实例的静态工厂方法
<bean id="car" class="com.xalo.action.CarFactory" factory-method="getCar">
</bean>
2.通过工厂方法模式创建对象
工厂中获取具体对象的方法不是静态方法,而是成员方法
(1)定义一个工厂类(加载工厂对象)
(2)通过factory-bean获取工厂对象,通过factory-method配置工厂对象要调用的方法
<bean id="carFactory" class="com.xalo.action.CarFactory"></bean>
<bean id="car" factory-bean="carFactory" factory-method="getCar">
<!--要注入的bean的id.
要注入的值为java-bean,需要使用ref 引用已经配置的bean
要注入的值是简单类型 例如: 四类八种 字符串等 需要使用value-->
<constructor-arg name="type" value="suv"></constructor-arg>
</bean>
3.通过Bean的class来加载
<bean id="girl" class="com.xalo.entity.Girl"></bean>
<bean id="person" name="father,monther" class="com.xalo.entity.Person" init-method="init" destroy-method="destory"></bean>
AOP的底层实现:
采用动态代理模式
具体分为两种:
(1)有接口的情况:
创建接口的实现类的代理模式 JDK动态代理
(2)没有接口的情况: 子类可以通过super调用父类方法
创建user类的子类的代理对象 oglib动态代理
DI依赖注入的方式:
1.构造器注入
保证了一些必要的属性在Bean实例化时就设置,并且确保了bean实例化后就可以使用
(1)在类中,不用为属性设置setter方法,只需要提供构造方法即可
(2)在构造文件中配置该类的bean,并配置构造器,在配置构造器中用
public class LoginAction {
private String name;
//提供构造方法
public LoginAction(String name) {
this.name = name;
System.out.println("name:" + name);
}
//ApplicationContext.xml
<bean id="action" class="com.xalo.action.LoginAction">
<constructor-arg index ="0" name="name" value="碧瑶"></constructor-arg>
</bean>
//DITest
public class DITest {
@Test
public void test() {
//加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
LoginAction action = (LoginAction) context.getBean("action");
}
/*index:当前要赋值的构造方法的位置,从0开始(可选).如果不设置index,自上而下为对应位置的参数赋值
*value: 给构造方法的参数赋值,必须和对应的参数的类型匹配
*name: 构造方法的形参名称
* 如果没有指定index,也没有指定name,必须按照参数的顺序进行注入-->
*/
/*
*向LoginAction里面注入bean 构造器注入
*/
public interface ServiceInterf {
}
public class LoginService implements ServiceInterf {
public void sayHello(){
}
}
public class LoginAction {
/*
*我们将要使用的类型声明为接口类型,当前类对象和要使用的对象就没有直接的联系.
*主要适合接口进行对接,所以两个类之间的耦合度就降低了
*(不同层之间的耦合度越低越好,同层之间的耦合度越高越好)
*/
private ServiceInterf loginService;
//提供有参的构造方法
public LoginAction(ServiceInterf loginService) {
this.loginService = loginService;
System.out.println(loginService);
}
}
//ApplicationContext.xml
<bean id="service" class="com.xalo.service.LoginService">
</bean>
<bean id="action" class="com.xalo.action.LoginAction">
<constructor-arg name="loginService" ref="service" ></constructor-arg>
</bean>
/*要注入的bean的id
*要注入的值为java bean,需要使用ref 引用已经配置的bean
*要注入的值为简单类型 例如: 四类八种 字符串等 需要使用value
*type: 指定是注入数据的类型,当使用构造器注入时,
* 如果参数除了类型不一样,其它都一样需要指定type来区分执行哪一个构造方法
*/
//DITest
public class DITest {
@Test
public void test() {
//加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
LoginAction action = (LoginAction) context.getBean("action");
}
}
2.setter注入
(1)根据property标签的name属性的值去找对应的setter方法. 例如: name = "aa" 对应的就是setAa()方法
(2)由于属性注入具有可选性和灵活性高的优点,是实际上最常用的注入方式
(3)属性注入要求bean提供一个默认的构造函数,并为需要注入的属性值提供setter方法.
String先调用bean默认的构造函数实例化bean对象,然后通过反射机制的方法调用setter方法注入属性值
public class SetterAction {
private String name;
public void setName(String name) {
this.name = name;
}
}
//ApplicationContext.xml
<bean id="setter" class="com.xalo.action.SetterAction">
<property name="name" value="碧瑶"/>
</bean>
//DITest
public class DITest {
@Test
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
SetterAction setterAction = (SetterAction) context.getBean("setter");
System.out.println(setterAction.getName());
}
}
3.静态工厂注入
4.实例化工厂注入
Spring管理事务分两种:
1.编程式事务管理:
通过编程的方式管理事务,灵活性高,但很难维护
2.声明事务管理:
将事务的管理和业务代码分离,只需要通过注解或者XML配置事务管理
事务的传播特性:
1.required: 如果当前没有事务,就新建一个事物,如果有一个事物,就加入到这个事务中
2.supports: 支持当前事务,如果当前没有事务,以非事务方法执行
3.mandatory: 使用当前事务,如果没有当前事务,就抛出异常
4.required_new: 新建事务,如果当前存在事务,把当前事务挂起
5.not_supports: 以非事务方式操作,如果当前存在事务,把当前事务挂起
6.never: 以非事务方式执行,如果当前事务存在则抛出异常
7.nested: 如果当前存在事务,则在嵌套事务内执行.
如果当前没有事务,则执行与propagation_required类似的操作
<!-- 事务通知以及传播特性 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 传播行为 -->
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="insert*" propagation="REQUIRED" />
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="create*" propagation="REQUIRED" />
<tx:method name="delete*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="find*" propagation="SUPPORTS" read-only="true" />
<tx:method name="select*" propagation="SUPPORTS" read-only="true" />
<tx:method name="get*" propagation="SUPPORTS" read-only="true" />
</tx:attributes>
</tx:advice>
<!-- AOP配置 proxy-target-class="false":不使用自动代理-->
<aop:config>
<!-- 切入点的配置 expression:要额外增加功能的方法 返回值 包名 类名 方法名-->
<aop:pointcut id="mypointcut" expression="execution(* com.yangsheng.dao.*.*(..))"/>
<!--环绕增强,通知和切入点 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="mypointcut"/>
</aop:config>
事务的隔离级别:
1.Read uncommited(读未提交):
允许另外一个事务可以看到这个事务未提交的数据
2.Read commited(读提交):
一个事务提交之后,才能被另外一个事务读取,另外一个事务不能读该事务未提交的数据
3.Repeatable read(读重复):
一个事物不能读取该事物未提交的数据
4.Serializable(序列化):
事务被处理为顺序执行
脏读:
一个事务读取了另外一个未提交事务的数据
不可重复读:
一个事物两次读取同一行数据,结果得到不同的状态结果.
如:中间正好一个事物更新了该数据,导致前后读取结果不一样
虚读(幻读):
一个事物内读取了别的事物插入的数据,导致前后结果不一样.
25.Struts2执行流程:
1.用户发送请求
2.请求经过一系列的过滤器(Filter)
3.FilterDispatcher被调用,FilterDispatcher询问ActionMapper来决定这个请求是否需要调用某个Action
4.如果需要处理请求,ActionMapper会通知FilterDispatcher处理请求,FilterDispatcher会将请求的处理交给ActionProxy(代理)
5.ActionProxy(代理)通过Configuration Manager询问框架的配置文件struts.xml,找到需要调用的Action类
6.ActionProxy(代理)创建ActionInvocation实例
7.ActionInvocation通过命名模式来调用,Action的过程前后涉及到一系列拦截器(Interceptor)调用
8.Action执行完毕,ActionInvocation根据struts.xml中的配置,找到对应的返回结果.
返回结果是一个需要被表示的JSP或者FreeMarker模块
9.ActionInvocation倒序执行拦截器
10.ActionInvocation执行完毕,响应用户
26.Hibernate对象的状态有哪些? 它们之间如何转换?
Hibernate对象有三种状态:
(1)临时状态
该对象既没有在session中,也没有在数据库中
刚new出来的对象
session执行了delete之后的操作
(2)持久化状态
对象在session中存在,在数据库中也存在数据
临时状态的对象被save();
游离状态的对象被update();
get或load得到对象
(3)游离状态
该对象的id在数据库中存在,在session中没有改对象
处理持久化状态的对象变成了游离状态:
session执行了close(关闭session)
clean(清理session缓存)
evict
刚new出来的对象,如果数据库中有它的主键
27.JDK和JRE的关系区别?
JDK是java的开发工具,JDK包含JRE
JRE只是java程序的运行环境,它最核心的内容就是JVM(java虚拟机)及核心类库
28.基本数据类型? 自动拆装箱? Integer和int区别?
基本数据类型: 四类八种
整数型: byte(1) short(2) int(4) long(8)
浮点型: float(4) double(8)
字符型: char(2)
布尔类型: boolean(1/4字节)
注意: String不是基本数据类型,而是引用类型
自动装拆箱:
基本数据类型和引用数据类型的转换
int是基本数据类型,初始值为0
Integer是int的包装类,初始值为null
Integer缓存: 注意拆箱和装箱(-128-127之间)
原始类型: boolean char byte short int long float double
包装类型: Boolean character Byte Short Integer Long Float Double
29.拦截器的作用? 使用场景?
拦截器和过滤器的区别?
拦截器的作用:
当流程正在运行时,你希望干预它的进展,甚至终止它的运行.这就是拦截器
使用场景:
1).日志记录
2).权限管理
3).性能监控
4).通用行为:
读取cookie得到用户信息并且将用户对象放到请求,方便后续流程使用
5).openSessionView:
Hibernate在进入处理器打开session,在完成后关闭session
区别:
拦截器更加灵活,Filter能做的事情,它都能做,并且是在请求之前,请求之后执行
1.拦截器是基于java的反射机制的,而过滤器是基于函数回调的
2.拦截器不依赖于servlet容器,而过滤器依赖servlet容器
3.拦截器只能对action请求起作用,而过滤器是可以对所有的请求起作用
4.拦截器可以访问action上下文,值栈里面的对象,而过滤器不能
5.在action的生命周期中,拦截器可以多次被调用,
而过滤器只能在容器初始化时被调用一次
30.SpringMVC 与Struts中拦截器的区别?
1.它们的拦截器都是继承servlet的filter,且都能传递request和response作用域,
Spring过滤后去找Controller,Struts过滤后去struts的配置文件中找action
2.SpringMVC完全替代了struts.xml换成了注解,需要配置
注解扫描,注解驱动, 支持静态访问, 前后缀等
接收参数和发送参数都是 SpringMVC自动完成,
无需定义setter和getter方法,只需传入接收参数即可