您的位置:首页 > 其它

笔记

2016-03-08 20:28 197 查看
1.spring mvc内部机制;

1)客户端发出一个http请求给web服务器,web服务器对http请求进行解析,如果匹配DispatcherServlet

的请求映射路径(在web.xml中指定),web容器将请求转交给DispatcherServlet.

2)DipatcherServlet接收到这个请求之后将根据请求的信息(包括URL、Http方法、请求报

文头和请求参数Cookie等)以及HandlerMapping的配置找到处理请求的处理器(Handler)

3-4)DispatcherServlet根据HandlerMapping找到对应的Handler,将处理权交给Handler

(Handler将具体的处理进行封装),再由具体的HandlerAdapter对Handler进行具体的调用。

5)Handler对数据处理完成以后将返回一个ModelAndView()对象给DispatcherServlet

6)Handler返回的ModelAndView()只是一个逻辑视图并不是一个正式的视图,DispatcherSevlet

通过ViewResolver将逻辑视图转化为真正的视图View
7)Dispatcher通过model解析出ModelAndView()中的参数进行解析最终展现出完整的view并返回给客户端。

SpringMvc中的controller默认是单例的,若是在@controller之前增加@Scope("prototype"),就可以改变单例模式为多例模式。

struts2中action是多例的,即一个session产生一个action;而servlet采用单实例多线程模式开发,减少产生servlet实例的开销。

开发线程安全的servlet

1)多线程并不共享局部变量.所以我们要尽可能的在servlet中使用局部变量。

2)使用同步块Synchronized,防止可能异步调用的代码块。

3)使用同步的集合类:使用Vector代替ArrayList,使用Hashtable代替HashMap。

2.sql优化;

1)用子查询代替连接表:建议仅在数据量非常大的情况下用该方法,因为数据量小的话效果很不明显,且影响语句的可读性。

2)避免在select语句使用*来表示要查询的列,使用分页技术限制查询的数量

3)少用like查询,该查询必然走全表扫描,除非必要,否则不要在关键词前加%,like “%aaa%” 不会使用索引而like “aaa%”可以使用索引。

4)合理的索引设计(不能用null作索引,任何包含null值的列都将不会被包含在索引中)

5)EXISTS要远比IN的效率高。

6)IN、OR子句常会使用工作表,使索引失效:如果不产生大量重复值,可以考虑把子句拆开。拆开的子句中应该包含索引。

3.sql建立索引的规则

索引是建立在数据库表中的某些列的上面。因此,在创建索引的时候,应该仔细考虑在哪些列上可以创建索引,在哪些列上不能创建索引。一般来说,应该在这些列上创建索引,例如:

在经常需要搜索的列上,可以加快搜索的速度;

在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构;

在经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度;

在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的;

在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间;

在经常使用在WHERE子句中的列上面创建索引,加快条件的判断速度。
 Mysql目前主要有以下几种索引类型:BTREE(默认,树形的数据结构,遍历),HASH,FULLTEXT(全文索引,目前只有MyISAM引擎支持),RTREE(优势是范围查找)。

虽然索引大大提高了查询速度,同时却会降低更新表的速度;建立索引会占用磁盘空间的索引文件

4.集群并发同步的处理以及高并发解决方案;

1)使用分布式事务:常见的两个处理办法就是两段式提交和补偿。解决分布式事务的最好办法就是不考虑分布式事务。拆分大的业务流程,转化成几个小的业务流程,然后考虑最终一致性。

2)数据库层面解决:使用悲观锁(for update),但是数据库性能开销大;使用乐观锁,基于数据版本(Version)记录机制实现

3)解决方案:HTML静态化;图片服务器分离;数据库集群、库表散列、缓存、镜像、负载均衡、CDN加速技术

5.left join跟inner join的区别;

left join(左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录

right join(右联接) 返回包括右表中的所有记录和左表中联结字段相等的记录

inner join(等值连接) 只返回两个表中联结字段相等的行

6.stringbuffer跟stringbuilder的区别;

在执行速度方面的比较:StringBuilder > StringBuffer;StringBuilder线程非安全的;StringBuffer线程安全的

7.AOP

AOP利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度。

使用“横切”技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。Aop 的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。

实现AOP的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。

spring aop的用法,实际案例

AOP有三种织入切面的方法:

其一是编译期织入,这要求使用特殊的Java编译器,AspectJ是其中的代表者;

其二是类装载期织入,而这要求使用特殊的类装载器,AspectJ和AspectWerkz是其中的代表者;

其三为动态代理织入,在运行期为目标类添加增强生成子类的方式,Spring AOP采用动态代理织入切面。

Spring AOP使用了两种代理机制,一种是基于JDK的动态代理(基于实现某个接口的类),另一种是基于CGLib的动态代理,之所以需要两种代理机制,很大程度上是因为JDK本身只提供基于接口的代理,不支持类的代理。

AOP可以应用在日志、事务、权限方面的面向切面编程思想的一种架构或者设计模式,或者每次保存创建者、创建时间、修改者等的时候使用

所谓Dynamic Proxy(动态代理)是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些interface。这个Dynamic Proxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的,在使用动态代理类时,我们必须实现InvocationHandler接口

动态代理的步骤:

1)创建一个实现接口InvocationHandler的类,它必须实现invoke方法

2)创建被代理的类以及接口

3)通过Proxy的静态方法

newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 创建一个代理

4)通过代理调用方法

8.mybatis注意点

1)xml中某些特殊符号作为内容信息时需要做转义,否则会对文件的合法性和使用造成影响

2)使用<![CDATA[ ]]>来标记不应由xml解析器进行解析的文本数据

3)使用$,但这种写法存在一定的风险,可能会引起sql注入。使用#

9.重写equal 的同时为什么必须重写hashcode?

hashCode是编译器为不同对象产生的不同整数,根据equal方法的定义:如果两个对象是相等(equal)的,那么两个对象调用hashCode必须产生相同的整数结果,即:equal为true,hashCode必须为true,equal为false,hashCode也必须为false,所以必须重写hashCode来保证与equal同步。

在java的集合中,判断两个对象是否相等的规则是:

1)判断两个对象的hashCode是否相等

    如果不相等,认为两个对象也不相等,完毕

    如果相等,转入2

2)判断两个对象用equals运算是否相等

    如果不相等,认为两个对象也不相等

    如果相等,认为两个对象相等

(1)为什么要重载equal方法?

答案:因为Object的equal方法默认是两个对象的引用的比较,意思就是指向同一内存,地址则相等,否则不相等;如果你现在需要利用对象里面的值来判断是否相等,则重载equal方法。

(2)为什么重载hashCode方法?

答案:一般的地方不需要重载hashCode,只有当类需要放在HashTable、HashMap、HashSet等等hash结构的集合时才会重载hashCode,那么为什么要重载hashCode呢?就HashMap来说,好比HashMap就是一个大内存块,里面有很多小内存块,小内存块里面是一系列的对象,可以利用hashCode来查找小内存块hashCode%size(小内存块数量),所以当equal相等时,hashCode必须相等,而且如果是object对象,必须重载hashCode和equal方法。

(3)为什么equals()相等,hashCode就一定要相等,而hashCode相等,却不要求equals相等?

答案:1、因为是按照hashCode来访问小内存块,所以hashCode必须相等。

           2、HashMap获取一个对象是比较key的hashCode相等和equal为true。

之所以hashCode相等,却可以equal不等,就比如ObjectA和ObjectB他们都有属性name,那么hashCode都以name计算,所以hashCode一样,但是两个对象属于不同类型,所以equal为false。

10.HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。HashMap底层就是一个数组结构,数组中的每一项又是一个链表。Entry就是数组中的元素,每个 Map.Entry 其实就是一个key-value对,它持有一个指向下一个元素的引用,这就构成了链表;当新建一个HashMap的时候,就会初始化一个数组。构建一个初始容量为 16,负载因子为 0.75 的 HashMap,线程不安全; 解决hash冲突的办法:Java中hashmap的解决办法就是采用的链地址法;HashMap可以让你将空值作为一个表的条目的key或value,而Hashtable不行且线程安全

11. java.NIO包里包括三个基本的组件

1)buffer:因为NIO是基于缓冲的,所以buffer是最底层的必要类,本质是一个数组,这也是IO和NIO的根本不同,虽然stream等有buffer开头的扩展类,但只是流的包装类,还是从流读到缓冲区,而NIO却是直接读到buffer中进行操作。

2)channel:类似于IO的stream,但是不同的是除了FileChannel,其他的channel都能以非阻塞状态运行。Channel中读数据和写数据都只能通过Buffer传输。数据可以从Channel读到Buffer中,也可以从Buffer写到Channel中,是Buffer对象的唯一接口。

3)selector:用于分发请求到不同的channel,这样才能确保channel不处于阻塞状态就可以收发消息。使用一个select线程就能监听多个通道上的事件,并基于事件驱动触发相应的响应。而不需要为每个channel去分配一个线程。

   Java NIO和IO之间第一个最大的区别是,IO是面向流的,NIO是面向缓冲区的;Java IO是阻塞式的操作,当一个inputstream或outputstream在进行read()或write()操作时,是一直处于等待状态的,直到有数据读/写入后才进行处理.而NIO是非阻塞式的,当进行读写操作时,只会返回当前已经准备好的数据,没有就返回空,这样当前线程就可以处理其他的事情,提高了资源的使用率。

   在老的IO包中,serverSocket和socket都是阻塞式的,因此一旦有大规模的并发行为,而每一个访问都会开启一个新线程。这时会有大规模的线程上下文切换操作(因为都在等待,所以资源全都被已有的线程吃掉了),这时无论是等待的线程还是正在处理的线程,响应率都会下降,并且会影响新的线程。而NIO包中的serverSocket和socket就不是这样,只要注册到一个selector中,当有数据放入通道的时候,采取Reactor模式,或者说是Observer模式为我们监察I/O端口,selector就会得知哪些channel就绪,这时就可以做响应的处理,这样服务端只有一个线程就可以处理大部分情况(当然有些持续性操作,比如上传下载一个大文件,用NIO的方式不会比IO好)。

   NIO里对性能提升最显著的是内存映射(memorymapping)。内存映射是一个系统层面的服务,它把程序里用到的文件的一段当作内存来处理。

   charset,一个用来转换不同字符编码的包。在NIO之前,Java通过getByte方法内置实现了大部分相同的功能。charset很受欢迎,因为它比getBytes更加灵活,并且能够在更底层去实现,这样就能够获得更好的性能。

使用NIO读取数据

在前面我们说过,任何时候读取数据,都不是直接从通道读取,而是从通道读取到缓冲区。所以使用NIO读取数据可以分为下面三个步骤: 

1. 从FileInputStream获取Channel 

2. 创建Buffer 

3. 将数据从Channel读取到Buffer中

在缓冲区中,最重要的属性有下面三个,它们一起合作完成对缓冲区内部状态的变化跟踪:position(位置),limit(多少),capacity(最大容量);

当有读或写等任何注册的事件发生时,可以从Selector中获得相应的SelectionKey,同时从 SelectionKey中可以找到发生的事件和该事件所发生的具体的SelectableChannel,以获得客户端发送过来的数据。

使用NIO中非阻塞I/O编写服务器处理程序,大体上可以分为下面三个步骤:

1. 向Selector对象注册感兴趣的事件 

2. 从Selector中获取感兴趣的事件 

3. 根据不同的事件进行相应的处理

创建了ServerSocketChannel对象,并调用configureBlocking()方法,配置为非阻塞模式,把该通道绑定到指定端口,最后向Selector中注册事件,此处指定的是参数是OP_ACCEPT,即指定我们想要监听accept事件,也就是新的连接发 生时所产生的事件,对于ServerSocketChannel通道来说,我们唯一可以指定的参数就是OP_ACCEPT。

从Selector中获取感兴趣的事件,即开始监听,进入内部循环,首先调用select()方法,该方法会阻塞,直到至少有一个事件发生,然后再使用selectedKeys()方法获取发生事件的SelectionKey,再使用迭代器进行循环。

12.synchronized修饰方法非static方法时,多线程下是并行的

当synchronized修饰一个static方法时,多线程下,获取的是类锁(即Class本身,注意:不是实例);

当synchronized修饰一个非static方法时,多线程下,获取的是对象锁(即类的实例对象)

所以,当synchronized修饰一个static方法时,在run方法中执行都是同步的;

相反,当synchronized修饰一个非static方法时,就无法保证同步操作,因为这时调用的方法是属于对象方法,每个线程都执有一个独立的对象实例,所以多线程下执行该方法并不会产生互斥,也不会有同步操作。

13.linux命令

Linux下显示进程ps aux和ps -ef,无区别,如果直接用ps命令,会显示所有进程的状态,通常结合grep命令查看某进程的状态。利用Linux所提供的管道符“|”将两个命令隔开

ps aux|grep java  //查看java进程

ps a  显示现行终端机下的所有程序,包括其他用户的程序

ps u  以用户为主的格式来显示程序状况

ps x  显示所有程序,不以终端机来区分

netstat -an | grep 3306   //查看所有3306端口使用情况

-a  显示所有连接和监听端口 

-n  以数字形式显示地址和端口号。

14.比较Redis与Memcached的区别

1)Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,zset,hash等数据结构的存储。

2)Redis支持数据的备份,即master-slave模式的数据备份。

3)Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用。

4)网络IO模型:Memcached是多线程,非阻塞IO复用的网络模型,实际Memcached所有操作都要对这个全局变量加锁,进行计数等工作,带来了性能损耗。Redis使用单线程的IO复用模型,单线程模型实际会严重影响整体吞吐量,CPU计算过程中,整个IO调度都是被阻塞住的。

5)内存管理方面:Memcached使用预分配的内存池的方式,Redis使用现场申请内存的方式来存储数据,并且很少使用free-list等方式来优化内存分配,这点上Redis更适合作为存储而不是cache。

6)数据一致性问题:Memcached提供了cas命令,可以保证多个并发访问操作同一份数据的一致性问题。 Redis没有提供cas 命令,并不能保证这点,不过Redis提供了事务的功能,可以保证一串 命令的原子性,中间不会被任何操作打断。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: