这里对今日的内容进行总结:
具备的条件:
1. 在分布式系统环境下,一个方法在同一时间只能被一个机器的一个线程执行。
2. 高可用的获取锁与释放锁。
3. 高性能的获取锁与释放锁。
4. 具备可重入的特性。
5. 具备锁失效机制,防止死锁。
6. 具备阻塞锁特性,即没有获取到锁将会继续等待获取锁。
7. 具备非阻塞锁特性,即没有获取到锁将会直接返回获取锁失败。
在学习9个组件之前,我们需要先了解Handler的概念,也就是处理器。它直接应对着MVC中的C也就是Controller层,它的具体表现形式有很多,可以是类,也可以是方法。在Controller层中@RequestMapping标注的所有方法都可以看成是一个Handler,只要可以实际处理请求就可以是Handler。
是用来查找Handler的。在SpringMVC中会有很多请求,每个请求都需要一个Handler处理,具体接收到一个请求之后使用哪个Handler进行处理呢?这就是HandlerMapping需要做的事。
从名字上看,它就是一个适配器。因为SpringMVC中的Handler可以是任意的形式,只要能处理请求就ok,但是Servlet需要的处理方法的结构却是固定的,都是以request和response为参数的方法。如何让固定的Servlet处理方法调用灵活的Handler来进行处理呢?这就是HandlerAdapter要做的事情。
小结:Handler是用来干活的工具;HandlerMapping用于根据需要干的活找到相应的工具;HandlerAdapter是使用工具干活的人。
其它组件都是用来干活的。在干活的过程中难免会出现问题,出问题后怎么办呢?这就需要有一个专门的角色对异常情况进行处理,在SpringMVC中就是HandlerExceptionResolver。具体来说,此组件的作用是根据异常设置ModelAndView,之后再交给render方法进行渲染。
ViewResolver用来将String类型的视图名和Locale解析为View类型的视图。View是用来渲染页面的,也就是将程序返回的参数填入模板里,生成html(也可能是其它类型)文件。这里就有两个关键问题:使用哪个模板?用什么技术(规则)填入参数?这其实是ViewResolver主要要做的工作,ViewResolver需要找到渲染所用的模板和所用的技术(也就是视图的类型)进行渲染,具体的渲染过程则交由不同的视图自己完成。
ViewName是根据ViewName查找View,但有的Handler处理完后并没有设置View也没有设置ViewName,这时就需要从request获取ViewName了,如何从request中获取ViewName就是RequestToViewNameTranslator要做的事情了。RequestToViewNameTranslator在Spring MVC容器里只可以配置一个,所以所有request到ViewName的转换规则都要在一个Translator里面全部实现。
解析视图需要两个参数:一是视图名,另一个是Locale。视图名是处理器返回的,Locale是从哪里来的?这就是LocaleResolver要做的事情。LocaleResolver用于从request解析出Locale,Locale就是zh-cn之类,表示一个区域,有了这个就可以对不同区域的用户显示不同的结果。SpringMVC主要有两个地方用到了Locale:一是ViewResolver视图解析的时候;二是用到国际化资源或者主题的时候。
用于解析主题。SpringMVC中一个主题对应一个properties文件,里面存放着跟当前主题相关的所有资源、如图片、css样式等。SpringMVC的主题也支持国际化,同一个主题不同区域也可以显示不同的风格。SpringMVC中跟主题相关的类有 ThemeResolver、ThemeSource和Theme。主题是通过一系列资源来具体体现的,要得到一个主题的资源,首先要得到资源的名称,这是ThemeResolver的工作。然后通过主题名称找到对应的主题(可以理解为一个配置)文件,这是ThemeSource的工作。最后从主题中获取资源就可以了。
用于处理上传请求。处理方法是将普通的request包装成MultipartHttpServletRequest,后者可以直接调用getFile方法获取File,如果上传多个文件,还可以调用getFileMap得到FileName->File结构的Map。此组件中一共有三个方法,作用分别是判断是不是上传请求,将request包装成MultipartHttpServletRequest、处理完后清理上传过程中产生的临时资源。
用来管理FlashMap的,FlashMap主要用在redirect中传递参数。
Spring AOP 机制是动态代理的应用场景。
ArrayList是Java集合框架中使用最多的一个类,是一个数组队列,线程不安全集合。
它继承于AbstractList,实现了List, RandomAccess, Cloneable, Serializable接口。
(1)ArrayList实现List,得到了List集合框架基础功能;
(2)ArrayList实现RandomAccess,获得了快速随机访问存储元素的功能,RandomAccess是一个标记接口,没有任何方法;
(3)ArrayList实现Cloneable,得到了clone()方法,可以实现克隆功能;
(4)ArrayList实现Serializable,表示可以被序列化,通过序列化去传输,典型的应用就是hessian协议。
它具有如下特点:
容量不固定,随着容量的增加而动态扩容(阈值基本不会达到)
有序集合(插入的顺序==输出的顺序)
插入的元素可以为null
增删改查效率更高(相对于LinkedList来说)
线程不安全
LinkedList是一个双向链表,每一个节点都拥有指向前后节点的引用。相比于ArrayList来说,LinkedList的随机访问效率更低。
它继承AbstractSequentialList,实现了List, Deque, Cloneable, Serializable接口。
(1)LinkedList实现List,得到了List集合框架基础功能;
(2)LinkedList实现Deque,Deque 是一个双向队列,也就是既可以先入先出,又可以先入后出,说简单些就是既可以在头部添加元素,也可以在尾部添加元素;
(3)LinkedList实现Cloneable,得到了clone()方法,可以实现克隆功能;
(4)LinkedList实现Serializable,表示可以被序列化,通过序列化去传输,典型的应用就是hessian协议。
数据结构:(JDK1.7)
A:添加功能 boolean add(E e):向集合中添加一个元素 void add(int index, E element):在指定位置添加元素 boolean addAll(Collection<? extends E> c):向集合中添加一个集合的元素。 B:删除功能 void clear():删除集合中的所有元素 E remove(int index):根据指定索引删除元素,并把删除的元素返回 boolean remove(Object o):从集合中删除指定的元素 boolean removeAll(Collection<?> c):从集合中删除一个指定的集合元素。 C:修改功能 E set(int index, E element):把指定索引位置的元素修改为指定的值,返回修改前的值。 D:获取功能 E get(int index):获取指定位置的元素 Iterator iterator():就是用来获取集合中每一个元素。 E:判断功能 boolean isEmpty():判断集合是否为空。 boolean contains(Object o):判断集合中是否存在指定的元素。 boolean containsAll(Collection<?> c):判断集合中是否存在指定的一个集合中的元素。 F:长度功能 int size():获取集合中的元素个数 G:把集合转换成数组 Object[] toArray():把集合变成数组。
Set:注重独一无二的性质,该体系集合可以知道某物是否已近存在于集合中,不会存储重复的元素
用于存储无序(存入和取出的顺序不一定相同)元素,值不能重复。
对象的相等性
引用到堆上同一个对象的两个引用是相等的。如果对两个引用调用hashCode方法,会得到相同的结果,如果对象所属的类没有覆盖Object的hashCode方法的话,hashCode会返回每个对象特有的序号(java是依据对象的内存地址计算出的此序号),所以两个不同的对象的hashCode值是不可能相等的。
如果想要让两个不同的Person对象视为相等的,就必须覆盖Object继下来的hashCode方法和equals方法,因为Object hashCode方法返回的是该对象的内存地址,所以必须重写hashCode方法,才能保证两个不同的对象具有相同的hashCode,同时也需要两个不同对象比较equals方法会返回true
该集合中没有特有的方法,直接继承自Collection。
---| Itreable 接口 实现该接口可以使用增强for循环 ---| Collection 描述所有集合共性的接口 ---| List接口 可以有重复元素的集合 ---| ArrayList ---| LinkedList ---| Set接口 不可以有重复元素的集合
eg:
public class Demo4 { public static void main(String[] args) { //Set 集合存和取的顺序不一致。 Set hs = new HashSet(); hs.add("世界军事"); hs.add("兵器知识"); hs.add("舰船知识"); hs.add("汉和防务"); System.out.println(hs); // [舰船知识, 世界军事, 兵器知识, 汉和防务] Iterator it = hs.iterator(); while (it.hasNext()) { System.out.println(it.next()); } } }
—| Itreable 接口 实现该接口可以使用增强for循环
—| Collection 描述所有集合共性的接口
—| List接口 可以有重复元素的集合
—| ArrayList
—| LinkedList
—| Set接口 不可以有重复元素的集合
—| HashSet 线程不安全,存取速度快。底层是以哈希表实现的。
元素的哈希值是通过元素的hashcode方法 来获取的, HashSet首先判断两个元素的哈希值,如果哈希值一样,接着会比较equals方法 如果 equls结果为true ,HashSet就视为同一个元素。如果equals 为false就不是同一个元素。
哈希值相同equals为false的元素是怎么存储呢,就是在同样的哈希值下顺延(可以认为哈希值相同的元素放在一个哈希桶中)。也就是哈希一样的存一列。
public class Demo5 { public static void main(String[] args) { TreeSet ts = new TreeSet(); ts.add("ccc"); ts.add("aaa"); ts.add("ddd"); ts.add("bbb"); System.out.println(ts); // [aaa, bbb, ccc, ddd] } }
---| Itreable 接口 实现该接口可以使用增强for循环 ---| Collection 描述所有集合共性的接口 ---| List接口 有序,可以重复,有角标的集合 ---| ArrayList ---| LinkedList ---| Set接口 无序,不可以重复的集合 ---| HashSet 线程不安全,存取速度快。底层是以hash表实现的。 ---| TreeSet 红-黑树的数据结构,默认对元素进行自然排序(String)。如果在比较的时候两个对象返回值为0,那么元素重复。
红-黑树
红黑树是一种特定类型的二叉树
Map 是一种把键对象和值对象映射的集合,它的每一个元素都包含一对键对象和值对象。 Map没有继承于Collection接口 从Map集合中检索元素时,只要给出键对象,就会返回对应的值对象。
HashMap //Map基于散列表的实现。插入和查询“键值对”的开销是固定的。可以通过构造器设置容量capacity和负载因子load factor,以调整容器的性能。
LinkedHashMap //类似于HashMap,但是迭代遍历它时,取得“键值对”的顺序是其插入次序,或者是最近最少使用(LRU)的次序。只比HashMap慢一点。而在迭代访问时发而更快,因为它使用链表维护内部次序。
TreeMap //底层是二叉树数据结构,线程不同步,可用于给Map集合中的键进行排序。
HashTable //HashMap是Hashtable的轻量级实现,非线程安全的实现他们都实现了map接口,主要区别是HashMap键值可以为空null,效率可以高于Hashtable。
ConcurrentHashMap //ConcurrentHashMap通常只被看做并发效率更高的Map,用来替换其他线程安全的Map容器,比如Hashtable和Collections.synchronizedMap。
WeakHashMap //弱键(weak key)Map,Map中使用的对象也被允许释放: 这是为解决特殊问题设计的。如果没有map之外的引用指向某个“键”,则此“键”可以被垃圾收集器回收。
IdentifyHashMap //使用==代替equals()对“键”作比较的hash map
ArrayMap //ArrayMap是一个<key,value>映射的数据结构,它设计上更多的是考虑内存的优化,内部是使用两个数组进行数据存储,一个数组记录key的hash值,另外一个数组记录Value值,它和SparseArray一样,也会对key使用二分法进行从小到大排序,在添加、删除、查找数据的时候都是先使用二分查找法得到相应的index,然后通过index来进行添加、查找、删除等操作,所以,应用场景和SparseArray的一样,如果在数据量比较大的情况下,那么它的性能将退化至少50%。
SparseArray //SparseArray比HashMap更省内存,在某些条件下性能更好,主要是因为它避免了对key的自动装箱(int转为Integer类型),它内部则是通过两个数组来进行数据存储的,一个存储key,另外一个存储value,为了优化性能,它内部对数据还采取了压缩的方式来表示稀疏数组的数据,从而节约内存空间。
Object put(Object key, Object value): 向集合中加入元素
Object remove(Object key): 删除与KEY相关的元素
void putAll(Map t): 将来自特定映像的所有元素添加给该映像
void clear():从映像中删除所有映射
HashMap的存储原理:(跟HashSet很像的,可以类比的理解下) 往HashMap添加元素的时候,首先会调用键的hashCode方法得到元素 的哈希码值,然后经过运算就可以算出该 元素在哈希表中的存储位置。 情况1: 如果算出的位置目前没有任何元素存储,那么该元素可以直接添加到哈希表中。 情况2:如果算出 的位置目前已经存在其他的元素,那么还会调用该元素的equals方法与这个位置上的元素进行比较 ,如果equals方法返回 的是false,那么该元素允许被存储,如果equals方法返回的是true,那么该元素被视为 重复元素,不允存储。
HashMap的基本用法 package collection; import java.util.HashMap; import java.util.Iterator; import java.util.Set; import java.util.Map.Entry; public class HashMap { public static void main(String[] args) { HashMap<String, String> hashMap = new HashMap<String, String>(); hashMap.put("cn", "中国"); hashMap.put("jp", "日本"); hashMap.put("fr", "法国"); System.out.println(hashMap); System.out.println("****"); System.out.println("cn:" + hashMap.get("cn")); System.out.println(hashMap.containsKey("cn")); System.out.println(hashMap.keySet()); System.out.println(hashMap.isEmpty()); hashMap.remove("cn"); System.out.println(hashMap); //采用Iterator遍历HashMap Iterator it = hashMap.keySet().iterator(); while(it.hasNext()) { String key = (String)it.next(); System.out.println("key:" + key); System.out.println("value:" + hashMap.get(key)); } //遍历HashMap的另一个方法 Set<Entry<String, String>> sets = hashMap.entrySet(); for(Entry<String, String> entry : sets) { System.out.print(entry.getKey() + ", "); System.out.println(entry.getValue()); } } }
TreeMap TreeMap也是基于红黑树(二叉树)数据结构实现 的, 特点:会对元素的键进行排序存储。(这个跟TreeSet一样的,可以参考TreeSet的原理) TreeMap 要注意的事项: 1. 往TreeMap添加元素的时候,如果元素的键具备自然顺序,那么就会按照键的自然顺序特性进行排序存储。 2. 往TreeMap添加元素的时候,如果元素的键不具备自然顺序特性, 那么键所属的类必须要实现Comparable接口,把键 的比较规则定义在CompareTo方法上。 3. 往TreeMap添加元素的时候,如果元素的键不具备自然顺序特性,而且键所属的类也没有实现Comparable接口,那么就必须 在创建TreeMap对象的时候传入比较器。
public class TreeMapTest { public static void main(String[] agrs){ //创建TreeMap对象: TreeMap<String,Integer> treeMap = new TreeMap<String,Integer>(); System.out.println("初始化后,TreeMap元素个数为:" + treeMap.size()); //新增元素: treeMap.put("hello",1); treeMap.put("world",2); treeMap.put("my",3); treeMap.put("name",4); treeMap.put("is",5); treeMap.put("jiaboyan",6); treeMap.put("i",6); treeMap.put("am",6); treeMap.put("a",6); treeMap.put("developer",6); System.out.println("添加元素后,TreeMap元素个数为:" + treeMap.size()); //遍历元素: Set<Map.Entry<String,Integer>> entrySet = treeMap.entrySet(); for(Map.Entry<String,Integer> entry : entrySet){ String key = entry.getKey(); Integer value = entry.getValue(); System.out.println("TreeMap元素的key:"+key+",value:"+value); } //获取所有的key: Set<String> keySet = treeMap.keySet(); for(String strKey:keySet){ System.out.println("TreeMap集合中的key:"+strKey); } //获取所有的value: Collection<Integer> valueList = treeMap.values(); for(Integer intValue:valueList){ System.out.println("TreeMap集合中的value:" + intValue); } //获取元素: Integer getValue = treeMap.get("jiaboyan");//获取集合内元素key为"jiaboyan"的值 String firstKey = treeMap.firstKey();//获取集合内第一个元素 String lastKey =treeMap.lastKey();//获取集合内最后一个元素 String lowerKey =treeMap.lowerKey("jiaboyan");//获取集合内的key小于"jiaboyan"的key String ceilingKey =treeMap.ceilingKey("jiaboyan");//获取集合内的key大于等于"jiaboyan"的key SortedMap<String,Integer> sortedMap =treeMap.subMap("a","my");//获取集合的key从"a"到"jiaboyan"的元素 //删除元素: Integer removeValue = treeMap.remove("jiaboyan");//删除集合中key为"jiaboyan"的元素 treeMap.clear(); //清空集合元素: //判断方法: boolean isEmpty = treeMap.isEmpty();//判断集合是否为空 boolean isContain = treeMap.containsKey("jiaboyan");//判断集合的key中是否包含"jiaboyan" } }