1)方法区(method):被所有的线程共享。方法区包含所有的类信息和静态变量。
2)堆(heap):被所有的线程共享,存放对象实例以及数组,Java堆是GC的主要区域。
3)栈(stack):每个线程包含一个栈区,栈中保存一些局部变量等。
4)程序计数器:是当前线程执行的字节码的行指示器。
1、继承Thread类,重写run函数
2、实现Runnable接口,重写run函散
3、实现Callable接口,重写call函数
Java多线程中的死锁
死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,
若无外力作用,它们都将无法推进下去。这是一个严重的问题,因为死锁会让你的程序挂
起无法完成任务,死锁的发生必须满足以下四个条件:
1、互斥条件:一个资源每次只能被一个进程使用。
2、请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
3、不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剩夺。
4、循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
避免死锁最简单的方法就是阻止循环等待条件,将系统中所有的资源设置标志位、排序,规定所有的进程申请资源
从这四个方面去解决:
1.资源互斥(ThreadLocal);2.资源不可抢占;3.几个不同的进程或线程它持有了资源并且不去释放;4.相互等待
1、HashMap是线程非安全的,ConcurrentHashMap是线程安全的。
2、ConcurrentHashMap将整个Hash桶进行了分段segment,也就是讲这个大的数组分成了几个小的片段segment,而且每个小的片段segment上面都有锁存在,那么在插入元素的时候需要先找到应该插入到哪个segment片段,然后再这个片段上面进行插入,而且这里还需要获取segment锁。
3、ConcurrentHashMap让锁的力度更精细一些,并发性能更好。
1、数据结构:ArrrayList 底层的数据结构是数组,支持随机访问,
而LinkedList 的底层数据结构书链表,不支持随机访问。增删低效
数组要查询那个元素只给出其下标即可,所以才说arraylist随机访问多的场景比较合适。但是如果删除某个元素比如第 i 个元素,则要将 i 之后的元素都向前移一位以保证顺序表的正确,增加也是一样,要移动多个元素。要多次删除增加的话是很低效的。
2、查询时间复杂度∶使用下标访问一个元素,ArrayList 的时间复杂度是O(1),
而LinkedList 是O(n)。LinkedList是双向链表。增删高效,查询慢。
要查询只能头结点开始逐步查询,需要遍历。但是,如果要增加后删除一个元素的话,只需要改变其前后元素的指向即可,不需要像arraylist那样整体移动,所以才说多用于增删多的场合
HashMap是非线程安全的,HashTable是线程安全的。
HashMap的键和值都允许有null值存在,而HashTable则不行。
因为线程安全的问题,HashMap效率比HashTable的要高。
1、fina1修饰符(关键字)
用于声明属性、方法和类,属性不可交变、方法不可覆盖、类不可继承
被final修饰的类,就意味着不能再派生出新的子类,不能作为父类而被子类继承。因此一个类不能既被abstract声明,又被final声明。 将变量或方法声明为final,可以保证他们在使用的过程中不被修改。
2、finally是在异常处理时提供finally块来执行任何清除操作
不管有没有异常被抛出、捕获,finally块都会被执行。try块中 的内容是在无异常时执行到结束。catch块中的内容,是在try块内容发生catch所声明的异常时,跳转到catch块
3、finalize是方法名
java技术允许使用finalize方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它.是在object类中定义的,因此所有的类都继承了它。子类覆盖finalize方法以整理系统资源或者被执行其他清理工作。
在Java中,处理异常的语句由try、catch、finally三部分组成。
其中,try块用于包裹业务代码,catch块用于捕获并处理某个类型的异常,finally块则用于回收资源。当业务代码发生异常时,系统会创建一个异常对象,然后由JVM寻找可以处理这个异常的catch块,并将异常对象交给这个catch块处理。若业务代码打开了某项资源,则可以在finally块中关闭这项资源,因为无论是否发生异常,finally块一定会执行。
(1)String是不可变字符串;StringBuilder、StringBuffer可变字符串
(2)String、StringBuffer是线程安全,保证线程同步;StringBuilder非线程安全,不保证线程同步
(3)String不适合大量字符串的拼接,在JDK1.8时字符串常量拼接被自动优化成了StringBuiler;
StringBuilder适合单线程情况下大量字符串的拼接;
StringBuffer适合多线程大量字符串的拼接。
(4)执行速度String(慢) < StringBuffer(较快) < StringBuilder(快)
(5)String[JDK1.0], StringBuffer[JDK1.0 ],StringBuilder[JDK1.5 ]
1、提高效率:
采取重写hashcode方法,先进行hashcode比较,如果不同,那么就没必要在进行equals的比较了,这样就大大减少了equals比较的次数,这对比需要比较的数量很大的效率提高是很明显的,一个很好的例子就是在集合中的使用。
【我们都知道java中的List集合是有序的,因此是可以重复的,而set集合是无序的,因此是不能重复的,那么怎么能保证不能被放入重复的元素呢,但靠equals方法一样比较的话,如果原来集合中以后又10000个元素了,那么放入10001个元素,难道要将前面的所有元素都进行比较,看看是否有重复,这个效率可想而知,因此hashcode就应遇而生了,java就采用了hash表,利用哈希算法(也叫散列算法),就是将对象数据根据该对象的特征使用特定的算法将其定义到一个地址上,那么在后面定义进来的数据只要看对应的hashcode地址上是否有值,那么就用equals比较,如果没有则直接插入,只要就大大减少了equals的使用次数,执行效率就大大提高了。】
2、为了保证同一个对象
保证在equals相同的情况下hashcode值必定相同,如果重写了equals而未重写hashcode方法,可能就会出现两个没有关系的对象equals相同的(因为equal都是根据对象的特征进行重写的),但hashcode确实不相同的。
总结:hash类存储结构(HashSet、HashMap等等)添加元素会有重复性校验,校验的方式就是先取hashCode判断是否相等(找到对应的位置,该位置可能存在多个元素),然后再取equals方法比较(极大缩小比较范围,高效判断),最终判定该存储结构中是否有重复元素。
1、包装类是对象,有方法和字段,对象的调用是通过引用对象的地址,而基本类型不是。
2、包装类型是引用的传递,基本类型是值的传递。
3、初始值不同:int的初始值为0,包装类型的初始值为null。
4、声明的方式不同:基本类型不需要new关键字;包装类型需要new关键字创建对象分配内存空间。
5、存储位置不同:基本数据类型直接将值保存在堆中;包装类型的对象存储在堆中,通过对象的引用来调用。
6、使用的方式不同:基本数据类型直接赋值就可以;包装类型通常是在集合时使用。
面向对象的三大基本特征:封装、继承、多态
多态是指==父类引用指向子类对象,在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。(同一消息可以根据发送对象的不同而采用多种不同的行为方式。)
多态的作用:消除类型之间的耦合关系。
实现多态的技术称为:动态绑定Q (dynamic binding), 是指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。
实现多态的三要索:继承,重写,父类引用指向子类对象【翻译:明明是父类,实际指向的是子类的一个对象】
1、抽象类和接口都不能直接实例化。如果要实例化,抽象类变量必须指向实现所有抽象方法的子类对象,接口变量必须指向实现所有接口方法的类对象。
2、抽象类要被子类继承,接口要被类实现。
3、接口只能做方法申明,抽象类中可以做方法申明,也可以做方法实现。
4、接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。
5、抽象类里的抽象方法必须全部被子类所实现,如果子类不能全部实现父类抽象方法,那么该子类只能是抽象类。同样,实现接口的时候,如不能全部实现接口方法,那么该类也只能为抽象类。
6、抽象方法只能申明,不能实现。
7、抽象类里可以没有抽象方法
8、如果—个类里有抽象方法,那么这个类只能是抽象类
9、抽象方法要被实现,所以不能是静态的,也不能是私有的。
10、接口可以继承接口,并且可多继承接口,但类只能单—继承。
11.接口可以通过匿名内部类实例化。接口是对动作的抽象,抽象类是对根源的抽象。抽象类表示的是,这个对象是什么。而接口表示的是,这个对象能做什么。
equals()是Object中的方法, ==:是比较运算符。
==:比较的是基本数据类型时:判断数据值是否相等
比较的是引用数据类型时:判断内存地址的是否为同一个
equals():默认比较的是引用数据类型变量所指向的对象的地址值是否相等,
重写后用来检测两个对象是否相等,即两个对象的内容是否相等。
四个整数类型: byte(1个字节, 8位)、 short(2个字节, 16位)、int(4个字节, 32位)、 long(8个字节, 64位)。
二个浮点数类型: float(4个字节, 32位)、double(8个字节, 64位)。
一个字符类型: char(2个字节, 16位)。
个布尔类型: boolean(1个字节, 8位)。
1、隐式转换
1. 取值范围小的转成取值范围大的。如int转成double
2. byte、short、char类型在进行数据类型转换的时候会先转成int类型,再进行运算。
2、强制转换
1. 取值范围大的转成取值范围小的。如double转成int
java.lang.NullPointerException 空指针异常 :调用了未经初始化的对象或者是不存在的对象
java.lang.ClassNotFoundException 指定的类找不到 :类的名称和路径加载错误;通常都是程序试图通过字符串来加载某个类时可能引发异常
java.lang.NumberFormatException 字符串转换为数字异常 :字符型数据中包含非数字型字符
java.lang.IndexOutOfBoundsException 数组下标越界异常 :常见于操作数组对象时发生
java.lang.IIIegalArgumentException 方法传递参数错误
java.lang.ClassCastException 数据类型转换异常
java.lang.NoClassDefFoundException 未找到类定义错误
SQLException SQL异常 :常见于操作数据库时的SQL语句错误
java.lang.InstantiationException 实例化异常
java.lang.NoSuchMethodException 方法不存在异常
SecurityException - 安全异常
UnsupportedOperationException - 不支持的操作异常
第一种方式:在方法声明的位置上,使用throws关键字,抛给上一级。谁调用我,我就抛给谁。
第二种方式:使用try…catch语句进行异常的捕捉。
异常发生之后,如果我选择了上抛,抛给了我的调用者,调用者需要对这个异常继续处理,那么调用者处理这个异常同样有两种处理方式。Java中异常发生之后如果一直上抛,最终抛给了main方法,main方法向上抛,抛给了调用者JVM,JVM知道这个异常发生,只有一个结果:终止java程序。(方法1 --> 方法2 --> … --> JVM)
不同点:
一:位置不同。throws用在函数上,后边跟的是异常类,可以跟多个异常类。throw用在函数内,后面跟的是异常对象。
二:功能不同。①throws用来声明异常,让调用者只知道该功能可能出现的问题,可以给出预先得处理方式。throw抛出具体的问题对象,执行到throw。功能就已经结束了跳转到调用者,并将具体的问题对象抛给调用者,也就是说throw语句独立存在时,下面不要定义其他语句,因为执行不到。②throws表示出现异常的一种可能性,并不一定会发生这些异常,throw则是抛出了异常,执行throw则一定抛出了某种异常对象。
相同点:
两者都是消极处理异常的方式,只是抛出或者可能抛出异常,但是不会由函数去处理异常,真正的处理异常由函数的上层调用处理。
public static void checkNegativeNum(int num) {
if (num < 0) {
throw new ArithmeticException("不能输入负数!");
} else {
System.out.println("输入的数字是:" + num + ",合法!");
}
}
用try来指定一块预防所有"异常"的程序。
紧跟在try程序后面,应包含一个catch子句来指定你想要捕捉的"异常"的类型。
throw语句用来明确地抛出一个"异常"。
throws用来标明一个成员函数可能抛出的各种"异常"。
Finally为确保一段代码不管发生什么"异常"都被执行一段代码。
理解: 面向对象是一种分类的思维模式,提到面向对象就要于面向过程作比较:面向过程,是把我们要做的事情当作一个整体,我们所关心的是这个整体,在整个整体上发生的是行为和属性,而面向对象,所关心的不是这个整体,而是具体的行为和属性,一步一步怎么实现的调用,哪些函数。
面向对象的特征是:1、抽象,把现实世界中的某一类东西,提取出来,用程序代码表示;2、封装,把过程和数据包围起来,对数据的访问只能通过已定义的界面;3、继承,一种联结类的层次模型;4、多态,允许不同类的对象对同一消息做出响应。面向对象(Object Oriented)是软件开发方法,一种编程范式。
1、数据存放位置不同:cookie数据存放在客户的浏览器上,session数据放在服务器上。
2、安全程度不同:cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,考虑到安全应当使用session。
3、性能使用程度不同:session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用cookie。
4、数据存储大小不同:单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie,而session则存储于服务端,浏览器对其没有限制。
5、会话机制不同:
session会话机制是一种服务器端机制,它使用类似于哈希表(可能还有哈希表)的结构来保存信息。
cookies会话机制:cookie是服务器存储在本地计算机上的小块文本,并随每个请求发送到同一服务器。 Web服务器使用HTTP标头将cookie发送到客户端。在客户端终端,浏览器解析cookie并将其保存为本地文件,该文件自动将来自同一服务器的任何请求绑定到这些cookie。
一个HTTP请求报文有四部分组成,请求行、请求头部、空行、请求数据。
1. 请求行
请求行由请求方法字段、URL字段和HTTP协议版本字段3个字段组成,它们用空格分隔。
例如:GET /index.html HTTP/1.1
请求方法比较多:GET、POST、HEAD、PUT、DELETE、OPTIONS、TRACE、CONNECT
但最常用的是GET和POST。
2. 请求头部
请求头部由关键字/值对组成,每行一对,关键字和值用英文冒号“:”分隔。
请求头部通知服务器有关于客户端请求的信息,典型的请求头有:
1. User-Agent:产生请求的浏览器类型。
2. Accept:客户端可识别的内容类型列表。
3. Host:请求的主机名,允许多个域名同处一个IP地址,即虚拟主机。
3. 空行
请求头之后是一个空行,它的作用是通过一个空行,告诉服务器请求头部到此为止。
4. 请求数据
请求数据不在GET方法中使用,而是在POST方法中使用。
POST方法适用于需要客户填写表单的场合。
与请求数据相关的最常使用的请求头是Content-Type和Content-Length。
上面是POST方法,它的请求行URL段中一般是没有参数的,参数放在了报文体中。
而GET方法的参数直接置于请求行URL中,报文体则为空。
比较项 | Get | post |
---|---|---|
参数出现在URL中 | 是(?name=xxx&pwd=aaa) | 否 |
长度限制 | 有 | 无 |
安全性 | 低 | 高 |
URL可传播 | 是 | 否 |
速度 | 速度快(查询) | 慢(增删改) |
1. 传递数据的方式
2.缓存
GET请求返回的内容可以被浏览器缓存起来。
POST请求默认不会缓存
缓存是针对URL来进行缓存的,GET请求由于其参数是直接加在URL上的,一种参数组合就有一种URL的缓存,可以根据参数来进行一一对应,重复请求是幂等的(不论请求多少次,结果都一样);
而POST请求的URL没有参数,每次请求的URL都相同,数据体(HTTPBody)可能不同,无法一一对应,所以缓存没有意义
3.数据量
HTTP协议没有对传输的数据大小进行限制,HTTP协议规范也没有对URL长度进行限制。但是,实际应用中它们通常受限于软硬件平台的设计和性能。
4.安全性
相对而言,POST的安全性要比GET的安全性高。
通过GET提交数据,用户名和密码将明文出现在URL上,因为(1)登录页面有可能被浏览器缓存, (2)其他人查看浏览器的历史纪录,那么别人就可以拿到你的账号和密码了。 POST的安全是相对的,对于普通用户来说他们看不到明文,数据封装对他们来说就是屏障。但是对于专业人士,它们会抓包会分析,没有加密的数据包对他们来说也是小case。所以,POST仅仅是相对安全。
1、转发在服务器端完成的;重定向是在客户端完成的。转发使用getRequestDispatcher()方法;重定向使用、sendRedirect()。
2、转发的速度快;重定向速度慢。转发是浏览器只做了一次访问请求。重定向是浏览器做了至少两次的访问请求
3、转发的是同一次请求;重定向是两次不同请求。
转发2次跳转之间传输的信息不会丢失(共享request)
重定向2次跳转之间传输的信息会丢失,因为重定向产生了新的请求
3、转发不会执行转发后的代码;重定向会执行重定向之后的代码
4、转发:浏览器url的地址栏不变。重定向:浏览器url的地址栏改变
5、转发必须是在同一台服务器下完成;重定向可以在不同的服务器下完成
https://www.zybuluo.com/wangzhuanyun/note/1534126
request、reaponse、session、application、out、pageContext、page、config、exception
1、request对象
request 对象是 javax.servlet.httpServletRequest类型的对象。 该对象代表了客户端的请求信息,主要用于接受通过HTTP协议传送到服务器的数据。(包括头信息、系统信息、请求方式以及请求参数等)。request对象的作用域为一次请求。
2、response对象
response 代表的是对客户端的响应,主要是将JSP容器处理过的对象传回到客户端。response对象也具有作用域,它只在JSP页面内有效。
3、session对象
session 对象是由服务器自动创建的与用户请求相关的对象。服务器为每个用户都生成一个session对象,用于保存该用户的信息,跟踪用户的操作状态。session对象内部使用Map类来保存数据,因此保存数据的格式为 “Key/value”。 session对象的value可以使复杂的对象类型,而不仅仅局限于字符串类型。
4、application对象
application 对象可将信息保存在服务器中,直到服务器关闭,否则application对象中保存的信息会在整个应用中都有效。与session对象相比,application对象生命周期更长,类似于系统的“全局变量”。
5、out 对象
out 对象用于在Web浏览器内输出信息,并且管理应用服务器上的输出缓冲区。在使用 out 对象输出数据时,可以对数据缓冲区进行操作,及时清除缓冲区中的残余数据,为其他的输出让出缓冲空间。待数据输出完毕后,要及时关闭输出流。
6、pageContext 对象
pageContext 对象的作用是取得任何范围的参数,通过它可以获取 JSP页面的out、request、reponse、session、application 等对象。pageContext对象的创建和初始化都是由容器来完成的,在JSP页面中可以直接使用 pageContext对象。
7、config 对象
config 对象的主要作用是取得服务器的配置信息。通过 pageConext对象的 getServletConfig() 方法可以获取一个config对象。当一个Servlet 初始化时,容器把某些信息通过 config对象传递给这个 Servlet。 开发者可以在web.xml 文件中为应用程序环境中的Servlet程序和JSP页面提供初始化参数。
8、page 对象
page 对象代表JSP本身,只有在JSP页面内才是合法的。 page隐含对象本质上包含当前 Servlet接口引用的变量,类似于Java编程中的 this 指针。
9、exception 对象
exception 对象的作用是显示异常信息,只有在包含 isErrorPage=“true” 的页面中才可以被使用,在一般的JSP页面中使用该对象将无法编译JSP文件。excepation对象和Java的所有对象一样,都具有系统提供的继承结构。exception 对象几乎定义了所有异常情况。在Java程序中,可以使用try/catch关键字来处理异常情况; 如果在JSP页面中出现没有捕获到的异常,就会生成 exception 对象,并把 exception 对象传送到在page指令中设定的错误页面中,然后在错误页面中处理相应的 exception 对象。
1、AJAX是一种通过在后台与服务器进行少量的数据交换,可以使页面实现异步更新,这就意味着可以在不重新加载整个网页的情况下,对页面的某一部分进行数据的更新。
1、情景描述:ajax分为同步和异步。一般使用异步,异步不会使页面阻塞,用户体验较好。但是异步会使编写js程序的复杂度提高,对新手来说很可能由于玩不转异步导致各种bug。下面介绍ajax同步的使用方法,不过也要尽量把所有ajax都写成异步的。
2、在ajax的参数中增加一个async: false参数可以发送同步ajax请求。
$.ajax({
url: '',
async: false
});
3、但是同步代码的缺点是,等待ajax请求响应之前,页面会卡住,用户什么都做不了,感受很不好,就像浏览器崩溃或者死机似的。所以同步ajax代码不适合应用到正式产品中。
优点:
1、实现了异步交互,提高了用户体验。 2、无需重新加载整个网页,只需要与服务器进行少量的数据交换,就能够实现对网页中的某一部分进行更新,从而减少了带宽的占用。 3、AJAX是在客户端运行的,它承载了一部分本来由服务器承担的工作,减少了大用户量下的服务器负载。
缺点:
1、安全性问题,大量的使用AJAX暴露了服务器交互的细节。 2、不容易调试。3、对搜索引擎的支持比较弱。
http://t.zoukankan.com/david1216-p-11515246.html
servlet有良好的生存期的定义,包括加载和实例化、初始化、处理请求以及服务结束。这个生存期由javax.servlet.Servlet接口的init,service和destroy方法表达。 Servlet被服务器实例化后,容器运行其init方法,请求到达时运行其service方法,service方法自动派遣运行与请求对应的do方法(doGet,doPost)等,当服务器决定将实例销毁的时候调用其destroy方法。
与CGI的区别在于servlet处于服务器进程中,它通过多线程方式运行其service方法,一个实例可以服务于多个请求,并且其实例一般不会销毁,而CGI对每个请求都产生新的进程,服务完成后就销毁,所以效率上低于servlet。
跨域问题的出现是由于浏览器为了防止csrf(跨域请求伪造)攻击,避免恶意攻击而采取的同源策略限制,也就是当一个页面使用XMLHTTPRequest对象发送HTTP请求时(XHR),必须保证当前页面和请求的资源是同源的(即协议,域名和端口号要完全一致,否则浏览器就会阻止跨域请求返回额的数据)。
如何解决跨域的问题的呢, 有以下三种方案
1,代理的方案,将请求资源的操作通过一层代理,然后取回数据,再从代理层把数据返给浏览器,由于代理层和浏览器是同源的,这样就解决了跨域的问题(通常试用于node层)
2,放开服务端跨域限制,通过添加response的header的方法(参考header(‘Access-Control-Allow-Origin:*’); //允许所有来源访问 header(‘Access-Control-Allow-Method:POST,GET’); // 允许访问的方式)
3,JSONP的方式,JSONP方式的原理是将返回数据以资源的方式放在< script>标签里面返回,由于返回的不是JSON数据,就没有跨域的限制了,类似对页面添加的js引用,这样就解决了跨域的问题。但需要在服务端拼接结构,违背了restful的原则。
1、 通过jsonp跨域:jsonp的原理就是利用标签没有跨域限制,通过
标签src
属性,发送带有callback
参数的GET
请求,服务端将接口返回数据拼凑到callback
函数中,返回给浏览器,浏览器解析执行,从而前端拿到callback函数返回的数据。
2、 document.domain + iframe跨域
3、 location.hash + iframe
4、 window.name + iframe跨域
5、 postMessage跨域
6、 跨域资源共享(CORS)
7、 nginx代理跨域
8、 nodejs中间件代理跨域
9、 WebSocket协议跨域
https://www.pudn.com/news/6325dce2b283a472d02711a3.html
1、转发:request.getRequestDispatcher(“1.jsp”).forward(request,response);
在服务器组件收到用户请求后。经过它的处理后有传递给了另一个组件。不修改用户的请求码。
2、重定向:response.sendRedirect(“success.jsp”);
重定向一般是为了防止用户提交完数据后点浏览器刷新或点后退之后产生重复提交
3、标准动作元素:
注意事项:
1、此语句前也不允许有out.flush(),如果有,会有异常:
2、跳转后浏览器地址栏不变,但是只能跳到当前主机下
3、此语句后面的语句执行完成后才会跳转
4、跳转后得路径变为当前路径,图片不是绝对路径将无法显示
简单介绍3个js实现页面跳转:
1、window.location.href=“URL”
2、window.navigate(“URL”)
3、window.location.replace(“URL”)
AOP:面向切面编程;IOC:控制反转;DI:依赖注入
1、AOP:
主要是模块化编程的思想,降低程序之间的耦合度。
在项目中,日志记录是必不可少的,但是,只是简单的将记录日志的代码块复制到各个模块当中,项目冗余和耦合度就会增大,如果使用面向切面编程,就可以将业务代码和业务相关性较低的代码分离开来,便于维护。
首先面向切面编程会有切点(Pointcut)、通知(Advice),通知分为以下五大类:
1)前置通知 :函数执行前增强
2)后置通知 :函数执行后增强,除非异常,最后执行
3)环绕通知 :函数执行的前后都增强
4)异常通知 :出现异常的时候执行
5)最终通知:不管出不出现异常,都会执行,类似于异常捕获的finally
2、IOC / DI:
AOP 的实现原理就是代理模式。 代理模式的核心作用就是通过代理,控制对对象的访问。它的设计思路是:定义一个抽象角色,让代理角色和真实角色分别去实现它。
策略模式:我们知道,在AOP中是有两种动态代理的,分别是jdk代理和cglib代理,在运行的过程中,Spring会选择不同的动态代理实现方式,这个就是策略模式典型的应用场景。
实现的方法其实也很简单,首先就是要定义一个策略接口,然后让不同的策略类都实现这个策略接口。
责任链模式:在AOP代理执行时,我们知道有一个非常关键的数据结构,那就是拦截器链,而这个拦截器链的本质,其实是使用了责任链模式。代表就是:ReflectiveMethodInvocation类中的proceed()方法。
**模板方法模式:**模板方法模式,说白了就是将不变的代码,也就是通用代码放到父类中,这样可以有效减少子类中的重复代码并且我们还可以在父类中定义好骨架,将细节交给子类去实现,从而方便后续扩展。
总结:AOP设计模式,除了刚刚提到的代理模式、策略模式、责任链模式、模板模式,还有一些未提到的设计模式,比如:单例模式,工厂模式,适配器模式。这些模式,我们要学习的是其思想,而不是死板的实现方式。
spring bean 的生命周期大致可以分为5个阶段,分别是创建前准备、创建实例化、依赖注入、容器缓存、销毁实例
第一阶段创建前准备,这个阶段的主要作用,bean在开始加载前要从上下文和一些配置中去解析并查找bean有关的扩展实现,比如像init-method,容器在初始化bean的时候会调用的一个方法,destory-method容器在销毁bean的时候会调用的一些方法以及beanFactoryPostProcessor这个一类bean加载过程中的一些前置和后置的一些处理扩展实现,这些类或者配置,其实是spring提供给开发者用来去实现bean加载过程中的一些扩展。在很多的Spring集成的中间。
第二个阶段是创建实例阶段,这个阶段的主要作用是通过反射区创建bean的实例对象,并且会扫描和解析bean声明的一些属性
第三个阶段是依赖注入的阶段,如果被实例化的bean存在依赖其他bean对象的情况,则需要对这些依赖的bean进行对象注入,比如autowired,以及settter注入 这样配置形式,同时在这个阶段会,触发一些扩展的调用比如像常见的beanPostProcessorss,用来去实现bean的初始化前后的扩展回调,以及像beanFactoryAware等
第四个阶段是容器缓存阶段,容器缓存阶段主要是把bean保存到容器以及缓存中,到这个阶段bean就可以使用了,这个阶段涉及到那些操作像常见的init-method,这个属性配置的方法会在这个阶段被调用以及像beanpostProcessor的后置处理器方法也会在这个阶段被触发
第五个阶段销毁实例阶段,当Spring的应用上下文被关闭的时候,那么上下文中的所有bean会被销毁,如果存在bean实现了像DisposableBean接口,或者配置destory-method方法,会在这个阶段被调用
(1)构造方法注入: 即被注入对象可以通过在其构造方法中声明依赖对象的参数列表,让外部(通常是IOC容器)知道它需要哪些依赖对象,然后IOC容器会检查被注入对象的构造方法,取得其所需要的依赖对象列表,进而为其注入相应对象
(2)setter方法注入: 即当前对象只需要为其依赖对象所对应的属性添加setter方法,IOC容器通过此setter方法将相应的依赖对象设置到被注入对象的方式即setter方法注入。
(3)接口注入: 接口注入有点复杂,被注入对象如果想要IOC容器为其注入依赖对象,就必须实现某个接口,这个接口提供一个方法,用来为被注入对象注入依赖对象,IOC容器通过接口方法将依赖对象注入到被注入对象中去。相对于前两种注入方式,接口注入比繁琐和死板被注入对象就必须专门声明和实现另外的接口。
https://baijiahao.baidu.com/s?id=1748622481597422969&wfr=spider&for=pc
http://blog.itpub.net/69955379/viewspace-2770212/
代码理解
Spring MVC的功能:
Spring MVC提供了一种轻度耦合的方式来开发web应用
Spring MVC是Spring的一个模块,是一个web框架。通过Dispatcher Servlet, ModelAndView 和 View Resolver,开发web应用变得很容易。解决的问题领域是网站应用程序或者服务开发——URL路由、Session、模板引擎、静态Web资源等等。
Spring Boot的功能:
Spring Boot实现了自动配置,降低了项目搭建的复杂度。
众所周知Spring框架需要进行大量的配置,Spring Boot引入自动配置的概念,让项目设置变得很容易。Spring Boot本身并不提供Spring框架的核心特性以及扩展功能,只是用于快速、敏捷地开发新一代基于Spring框架的应用程序。也就是说,它并不是用来替代Spring的解决方案,而是和Spring框架紧密结合用于提升Spring开发者体验的工具。同时它集成了大量常用的第三方库配置(例如Jackson, JDBC, Mongo, Redis, Mail等等),Spring Boot应用中这些第三方库几乎可以零配置的开箱即用out-of-the-box,大部分的Spring Boot应用都只需要非常少量的配置代码,开发者能够更加专注于业务逻辑。
Spring Boot只是承载者,辅助你简化项目搭建过程的。如果承载的是WEB项目,使用Spring MVC作为MVC框架,那么工作流程和你上面描述的是完全一样的,因为这部分工作是Spring MVC做的而不是Spring Boot。
对使用者来说,换用Spring Boot以后,项目初始化方法变了,配置文件变了,另外就是不需要单独安装Tomcat这类容器服务器了,maven打出jar包直接跑起来就是个网站,但你最核心的业务逻辑实现与业务流程实现没有任何变化。
所以,用最简练的语言概括就是:Spring 是一个“引擎”; Spring MVC 是基于Spring的一个 MVC 框架 ;Spring Boot 是基于Spring4的条件注册的一套快速开发整合包。
1)编程式事务,在代码中硬编码。(不推荐使用)
2)声明式事务,在配置文件中配置(推荐使用)
声明式事务又分为两种:
a)基于XML的声明式事务
b)基于注解的声明式事务
@Transactional 注解管理事务的实现步骤
分为两步。第一步,在 xml 配置文件中添加 事务配置信息。除了用配置文件的方式,@EnableTransactionManagement 注解也可以启用事务管理功能。这里以简单的 DataSourceTransactionManager 为例。
在 xml 配置中的事务配置信息
<tx:annotation-driven />
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
bean>
第二步,将@Transactional 注解添加到合适的方法上,并设置合适的属性信息。
如果你想在Spring Boot启动的时候运行一些特定的代码,你可以实现接口ApplicationRunner或 者CommandLineRunner,这两个接口实现方式一样,它们都只提供了一个run方法。
原理:
SpringApplication 的run方法会执行afterRefresh方法;
afterRefresh方法会执行callRunners方法;
callRunners方法会调用所有实现ApplicationRunner和CommondLineRunner接口的方法。
@Slf4j :
@Slf4j是用作日志输出的,一般会在项目每个类的开头加入该注解,如果不写private final Logger logger = LoggerFactory.getLogger(当前类名.class);
,并且想用log就可以用@Slf4j来代替;这样就省去这段很长的代码 。
**@Api :**使用swagger资源
@Controller和@RestController :
@RestController注解由@Controller 与@ResponseBody组成,以前需要使用这两个注解配合返回json,现在合在一起,在项目中直接使用@RestController注解。
@RequestMapping :
@RequestBody: 主要作用是用来接受前端传来的json中的数据(请求体中的数据)
@Autowired : @Autowired由Spring提供 , 完成自动装配,可以作用于类成员变量,方法及构造函数上(最常用是类常量),会自动在容器中查找对应的bean,并装配给该对象的属性
@SpringBootApplication: @SpringBootApplication注解是SpringBoot最核心,最基础的注解。表示一个配置类。等效于 同时声明:@Configuration,@EnableAutoConfiguration和@ComponentScan三个注解
@Resource:
@value: 直接将字符串"xiaoxiong"赋值给属性,如果属性类型不是String,或无法进行类型转换,则报错
@Autowired注入的对象在注入之前就已经实例化,是从IOC容器中获取已经初始化的对象, 整个生命周期都交由容器管控
new实例化一个对象,new对象不能注入其他对象,因为new出来的对象生命周期不受IOC容器管控,自然无法完成属性的注入(空指针异常)
最本质的区别,一个是从spring容器获取,一个是直接创建新对象。即Autowired是全局实例,而new创建的仅可以在当前类使用
预编译:在框架底层,是JDBC中的PreparedStatement类在起作用,PreparedStatement是我们很熟悉的Statement的子类,它的对象包含了编译好的SQL语句。这种“准备好”的方式不仅能提高安全性,而且在多次执行同一个SQL时,能够提高效率。原因是SQL已编译好,再次执行时无需再编译。
#{} 使用预编译,通过 PreparedStatement 和占位符来实现,会把参数部分用一个占位符 ? 替代,而后注入的参数将不会再进行 SQL 编译,而是当作字符串处理。可以有效避免 SQL 注入漏洞。
定义语句相关;insert、delete、update、select
查询结果集相关; resultMap
控制sql动态拼接相关: if、 choose、foreach
格式化相关;where、set、trim
关联关系相关的: collection、association、select
查询常量相关; sql、include
@Delete("<script>
delete from product where id in
<foreach collection='array' item='id' open='(' separator=',' close=')'>#{id}</foreach>
script>")
void delete(int[] ids);
@Component :这将 java 类标记为 bean。它是任何 Spring 管理组件的通用构造型。spring 的组件扫描机制现在可以将其拾取并将其拉入应用程序环境中
@Controller :这将一个类标记为 Spring Web MVC 控制器。标有它的 Bean 会自动导入到 IoC 容器中。
@Service :此注解是组件注解的特化。它不会对 @Component 注解提供任何其他行为。可以在服务层类中使用 @Service 而不是 @Component,因为它以更好的方式指定了意图。
@Repository :这个注解是具有类似用途和功能的 @Component 注解的特化。 注解可以标记在任何的类上。它为 DAO 提供了额外的好处。它将 DAO 导入 IoC 容器,并使未经检查 的异常有资格转换为 Spring DataAccessException
1、@Service用于标注业务层组件
2、@Controller用于标注控制层组件(如struts中的action)
3、@Repository用于标注数据访问组件,即DAO组件.
4、@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
1、@SpringBootApplication
这是 Spring Boot 最最最核心的注解,用在 Spring Boot 主类上,标识这是一个 Spring Boot 应用,用来开启 Spring Boot 的各项能力。
其实这个注解就是 @SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan 这三个注解的组合,也可以用这三个注解来代替 @SpringBootApplication 注解。
2、@EnableAutoConfiguration
允许 Spring Boot 自动配置注解,开启这个注解之后,Spring Boot 就能根据当前类路径下的包或者类来配置 Spring Bean。
如:当前类路径下有 Mybatis 这个 JAR 包,MybatisAutoConfiguration 注解就能根据相关参数来配置 Mybatis 的各个 Spring Bean。
3、@Configuration
这是 Spring 3.0 添加的一个注解,用来代替 applicationContext.xml 配置文件,所有这个配置文件里面能做到的事情都可以通过这个注解所在类来进行注册。
4、@SpringBootConfiguration
这个注解就是 @Configuration 注解的变体,只是用来修饰是 Spring Boot 配置而已,或者可利于 Spring Boot 后续的扩展。
5、@ComponentScan
这是 Spring 3.1 添加的一个注解,用来代替配置文件中的 component-scan 配置,开启组件扫描,即自动扫描包路径下的 @Component 注解进行注册 bean 实例到 context 中。
@Data,
@Configuration和@Bean
@Configuration和@Bean,@ComponentScan和@Component四个之间的关联
@EnableSwagger2,
@Controller、@RestController注解区别
swagger2的使用:@Api,@ApiOperation等
@EnableAutoConfiguration,
@ResponseBody,
@SpringBootApplication,
@Autowired
启动流程:
1、创建SpringApplication对象
2、调用SpringApplication的run方法
3、在执行run方法的过程中创建的spring容器会解析@SpringBootApplication注解进行自动装配
SpringBoot的运行原理:
Spring Boot 通过 @EnableAutoConfiguration 注解开启自动配置,加载 spring.factories 中注册的各种 AutoConfiguration 类,当某个 AutoConfiguration 类满足其注解 @Conditional 指定的生效条件(Starters 提供的依赖、配置或 Spring 容器中是否存在某个 Bean 等)时,那么实例化该 AutoConfiguration 类中定义的 Bean(组件等),并注入 Spring 容器,至此就完成了依赖框架的自动配置。
https://blog.csdn.net/CRMEB/article/details/122184762
当我们构建完Spring Boot项目后,会在resources目录下给我们一个默认的全局配置文件
application.properties,这是一个空文件,因为Spring Boot在底层已经把配置都给我们自动配置好了,当在配置文件进行配置时,会修改SpringBoot自动配置的默认值。
mybatis-springboot-starter
依赖application.properties
配置文件https://blog.csdn.net/m0_70083523/article/details/127887766
先加载后缀为.properties
的,如果.yml
中的有相同的配置,则不会在加载.yml
配置。按优先级排序,位置高的将覆盖位置低的
(properties位置高)。
如果在不同的目录中存在多个配置文件,它的读取顺序是:
1、项目根目录下的config文件中的:
config/application.properties
config/application.yml
2、项目根目录下的:
application.properties
application.yml
3、项目resources目录下config目录中的:
resources/config/application.properties
resources/config/application.yml
4、项目的resources目录下(项目创建自动生成的):
resources/application.properties(项目的resources目录下)
resources/application.ym
四种隔离级别可能导致的问题:
1、Serializable (串行化):最严格的级别,事务串行执行,资源消耗最大;
2、REPEATABLE READ(重复读) :保证了一个事务不会修改已经由另一个事务读取但未提交(回滚)的数据。避免了“脏读取”和“不可重复读取”的情况,但不能避免“幻读”,但是带来了更多的性能损失。
3、READ COMMITTED (提交读):大多数主流数据库的默认事务等级,保证了一个事务不会读到另一个并行事务已修改但未提交的数据,避免了“脏读取”,但不能避免“幻读”和“不可重复读取”。该级别适用于大多数系统。
4、Read Uncommitted(未提交读) :事务中的修改,即使没有提交,其他事务也可以看得到,会导致“脏读”、“幻读”和“不可重复读取”。
脏读:所谓的脏读,其实就是读到了别的事务回滚前的脏数据。比如事务B执行过程中修改了数据X,在未提交前,事务A读取了X,而事务B却回滚了,这样事务A就形成了脏读。也就是说,当前事务读到的数据是别的事务想要修改成为的但是没有修改成功的数据。
不可重复读:事务A首先读取了一条数据,然后执行逻辑的时候,事务B将这条数据改变了,然后事务A再次读取的时候,发现数据不匹配了,就是所谓的不可重复读了。也就是说,当前事务先进行了一次数据读取,然后再次读取到的数据是别的事务修改成功的数据,导致两次读取到的数据不匹配,也就照应了不可重复读的语义。
幻读:事务A首先根据条件索引得到N条数据,然后事务B改变了这N条数据之外的M条或者增添了M条符合事务A搜索条件的数据,导致事务A再次搜索发现有N+M条数据了,就产生了幻读。也就是说,当前事务读第一次取到的数据比后来读取到数据条目不一致。
Serializable 序列化
Serializable 是最高的事务隔离级别,在该级别下,事务串行化顺序执行,可以避免脏读、不可重复读与幻读。但是这种事务隔离级别效率低下,比较耗数据库性能,一般不使用。
REQUIRED(默认):支持使用当前事务,如果当前事务不存在,创建一个新事务。
SUPPORTS:支持使用当前事务,如果当前事务不存在,则不使用事务。
MANDATORY:中文翻译为强制,支持使用当前事务,如果当前事务不存在,则抛出Exception。
REQUIRES_NEW:创建一个新事务,如果当前事务存在,把当前事务挂起。
NOT_SUPPORTED:无事务执行,如果当前事务存在,把当前事务挂起。
NEVER:无事务执行,如果当前有事务则抛出Exception。
NESTED:嵌套事务,如果当前事务存在,那么在嵌套的事务中执行。如果当前事务不存在,则表现跟REQUIRED一样。
格式:@Transactional(propagation = Propagation.REQUIRES_NEW)
传播行为 | 含义 |
---|---|
PROPAGATION_REQUIRED | 表示当前方法必须运行在事务中,如果当前事务存在,方法将会在该事务中运行,否则,会启动一个新的事务 |
PROPAGATION_SUPPORTS | 表示该方法不需要事务上下文,但是如果存在当前的事务的话,那么该方法会在这个事务汇总运行 |
PROPAGATION_MANDATORY | 表示该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常 |
PROPAGATION_REQUIRED_NEW | 表示当前方法必须运行在它自己的事务中。一个新的事务将被启动,如果存在当前事务,在该方法执行期间,当期事务会被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager |
PROPAGATION_NOT_SUPPORTED | 表示当前方法不应该运行在事务中,如果存在当前事务,在该方法运行期间,当前事务将被挂起,如果使用JTATransactionManager的话,则需要访问TransactionManager |
PROPAGATION_NEVER | 表示当前方法不应该运行在事务上下文中,如果当前正有一个事务在运行,则抛出异常 |
PROPAGATION_NESTED | 表示如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。嵌套的事务可以独立于当前事务进行单独的提交或回滚。如果当前事务不存在,那么其行为和 PROPAGATION_REQUIRED一样。注意各厂商对这种传播行为的支持是有所差异的,可以参考资源管理器的文档来确认它们是够支持嵌套事务 |
1、第一种分页,全部查出来,然后在进行分页,这种分页不好
2、第二种分页,使用limit,前端传进来页码和每页的条数,在sql中使用limit进行查询
3、第三种分页方式,用RowBounds分页,创建RowBounds对象,使用有参传开始的条数((page -1*pagesize)和每页几条数据(pagesize),调用mapper方法讲RowBounds对象传递进去
4、使用pageHelper插件分页、主要是通过mybatis拦截器实现的
https://blog.csdn.net/bhegi_seg/article/details/126465056
【 导入pageHelper包,使用springboot进行脚手架搭建,导入对应依赖,写对应的yaml文件 】
<dependency>
<groupId>com.github.pagehelpergroupId>
<artifactId>pagehelperartifactId>
<version>5.3.0version>
dependency>
<dependency>
<groupId>com.github.pagehelpergroupId>
<artifactId>pagehelper-spring-boot-autoconfigureartifactId>
<version>1.4.1version>
dependency>
<dependency>
<groupId>com.github.pagehelpergroupId>
<artifactId>pagehelper-spring-boot-starterartifactId>
<version>1.4.1version>
pages(超过总数时),会查询最后一页。
reasonable: true
#支持通过 Mapper 接口参数来传递分页参数,默认值false,
#分页插件会从查询方法的参数值中,自动根据上面 params 配置的字段中取值,查找到合适的值时就会自动分页
support-methods-arguments: true
#为了支持startPage(Object params)方法,增加了该参数来配置参数映射,用于从对象中根据属性名取值
params: =count=countSql
配置完成之后,只需要在需要分页的service层代码,查询数据集合的上一行加一代码
//开启分页
PageHelper.startPage(pageNo,pageSize);
过滤器:
- servlet规范中的一部分,任何java web程序都可以使用。
- 在url-pattern中配置之后,可以对所要访问的资源进行拦截。
拦截器:
- 拦截器在SpringMvc框架自己的,只有使用了SpringMvc框架工程才能使用。
- 拦截器只会拦截访问控制器的方法,如果访问的是js,css,image…是不会进行拦截的。
1、工厂模式。
Spring的BeanFactory类,就是使用了简单工厂模式。它主要提供getBean()方法,用来创建对象的实例;我们见得比较多的ApplicationContext也是继承自BeanFactory。
2、单例模式。
Spring中的Bean默认为singleton单例。我们可以通过配置Bean的作用域scope参数来进行修改。Spring Bean一共有5种内置的作用域,分别是singleton、prototype、request、session、globalSession。
3、装饰器模式。
在Spring中,只要见到以Wrapper命名的类基本都是使用装饰器模式。比如BeanWrapper,用来访问Bean的属性和方法。
4、策略模式。
Spring中Bean的实例化采用的就是策略模式。因为Bean的实例化包含原生对象的实例化,和代理对象的实例化,不同对象实例化的逻辑也不一样,所以实例化策略也不一样,比如SimpleInstantiationStrategy就是Spring中默认的实例化策略。
5、适配器模式。
在Spring,只要是以Adapter命名的类基本都是适配器模式的应用。比如MVC模块中的HandlerAdapter。
6、代理模式。
比如AOP模块中的AopProxy,用到了JDK的动态代理和CGLIB字节码生成技术;
7、模板方法模式。
主要用来解决代码重复的问题。Spring提供了非常多的模板类来减少重复代码,基本都是以Template结尾,比如RestTemplate,JmsTemplate,JdbcTemplate。
8、观察者模式。
主要用于当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知,在Spring中一般以Listener结尾,比如ApplicationListener等等。
Mybatis 可以映射枚举类。不单可以映射枚举类,Mybatis 可以映射任何对象到表的一列上。
映射方式为自定义一个TypeHandler,实现 TypeHandler 的 setParameter()和getResult()接口方法。TypeHandler 有两个作用,一是完成从 javaType 至 jdbcType 的转换, 二是完成jdbcType 至 javaType 的转换,体现为 setParameter()和 getResult()两个方法,分别 代表设置sql 问号占位符参数和获取列查询结果。
还有很多其他的标签,< resultMap>、< parameterMap>、< sql>、< include>、< selectKey>,加上动态sql的9个标签,trim|where|set|foreach|if|choose|when|otherwise|bind等,其中< sql>为sql片段标签,通过< include>标签引入sql片段,< selectKey>为不支持自增的主键生成策略标签。
https://blog.csdn.net/m0_47010003/article/details/124516230
Spring有七大功能模块,分别是Spring Core,AOP,ORM,DAO,MVC,WEB,Context。
1,Spring Core
Core模块是Spring的核心类库,Spring的所有功能都依赖于该类库,Core主要实现IOC功能,Sprign的所有功能都是借助IOC实现的。
2,AOP
AOP模块是Spring的AOP库,提供了AOP(拦截器)机制,并提供常用的拦截器,供用户自定义和配置。
3,ORM
Spring 的ORM模块提供对常用的ORM框架的管理和辅助支持,Spring支持常用的Hibernate,ibtas,jdao等框架的支持,Spring本身并不对ORM进行实现,仅对常见的ORM框架进行封装,并对其进行管理
4,DAO模块
Spring 提供对JDBC的支持,对JDBC进行封装,允许JDBC使用Spring资源,并能统一管理JDBC事物,并不对JDBC进行实现。(执行sql语句)
5,WEB模块
WEB模块提供对常见框架如Struts1,WEBWORK(Struts 2),JSF的支持,Spring能够管理这些框架,将Spring的资源注入给框架,也能在这些框架的前后插入拦截器。
6,Context模块
Context模块提供框架式的Bean访问方式,其他程序可以通过Context访问Spring的Bean资源,相当于资源注入。
7,MVC模块
位符参数和获取列查询结果。