1、servlet生命周期
Servlet 生命周期指的是在 web 容器中,一个 Servlet 从被加载到被卸载的整个过程,它包括以下几个阶段:
-
加载和实例化:当客户端第一次请求访问一个 Servlet 时,web 容器会根据配置信息加载该 Servlet 的类文件,并创建一个 Servlet 实例。
-
初始化:在实例化之后,容器会调用 Servlet 的
init()
方法来进行初始化操作。在该方法中,可以执行一些必要的设置和准备工作,比如初始化数据库连接、加载配置文件等。 -
服务:一旦 Servlet 初始化完成,它就可以接收来自客户端的请求,并在容器的管理下提供相应的服务。每当有请求到达时,容器会创建一个新的线程来处理该请求并调用 Servlet 的
service()
方法。 -
销毁:当 web 应用程序卸载、servlet 容器关闭或者 servlet 的配置文件发生改变时,容器会调用 Servlet 的
destroy()
方法,用于释放资源、清理工作、保存状态等。在该方法执行完成后,Servlet 实例将不再提供服务,并且最终会被垃圾回收。
需要注意的是,每个 Servlet 实例只会创建一次,且在整个生命周期内只存在一个实例。而服务阶段中的 service()
方法会根据请求的类型(GET、POST、PUT、DELETE 等)调用不同的处理方法(如 doGet()
、doPost()
、doPut()
、doDelete()
等)来处理具体的业务逻辑。
以上就是 Servlet 生命周期的主要阶段,开发者可以在不同的生命周期方法中编写相应的代码,根据需求进行初始化、服务或销毁相关的操作。
2、同步请求&异步请求
同步请求和异步请求是两种不同的方式来处理客户端发送的请求和服务器返回的响应。
-
同步请求:
- 在同步请求中,客户端发送请求后会一直等待服务器返回响应,期间客户端的进程会被阻塞。
- 客户端会发送请求,然后等待服务器进行处理,并在服务器处理完毕后立即收到响应。
- 在服务器端处理请求时,该请求会占用一个线程,线程会一直等待响应返回给客户端,直到响应返回之前不能处理其他请求。
- 同步请求适合于需要立即获取响应结果并进行后续处理的场景。
-
异步请求:
- 在异步请求中,客户端发送请求后不会等待服务器立即返回响应,而是继续执行其他操作。
- 客户端发送请求后,可以继续进行其他的操作,而不需要等待服务器的响应。
- 在服务器端处理请求时,请求会被分发给一个独立的线程进行处理,处理完毕后将响应返回给客户端。
- 异步请求在发送请求后不需要一直等待响应结果,可以继续进行其他操作,适用于一些需要长时间处理的操作,比如上传文件、完成复杂计算等。
3、转发和重定向
转发(Forward)和重定向(Redirect)是两种常见的在服务器端进行页面跳转的方式。
-
转发(Forward):
- 转发是服务器内部进行的页面跳转,从一个 Servlet/JSP 程序转发到另一个 Servlet/JSP 程序。
- 在转发过程中,请求由客户端发送到服务器,并在服务器端内部进行处理,然后将请求和响应传递给下一个 Servlet/JSP 程序进行处理。
- 转发是在同一个请求中完成的,因此在浏览器地址栏中仍然显示原始请求的 URL,客户端不会察觉到页面发生了转发。
- 转发可以共享请求的属性和参数,适合用于在不同的 Servlet/JSP 中共享数据,比如表单数据、验证信息等。
- 在代码中,使用
RequestDispatcher
的forward()
方法进行转发,如:request.getRequestDispatcher("/nextPage.jsp").forward(request, response);
-
重定向(Redirect):
- 重定向是通过向客户端发送特殊的响应来实现的,表示客户端需要发送一个新的请求到新的 URL。
- 在重定向过程中,客户端收到服务器响应后,会根据响应的指示发送新的请求到指定的 URL。
- 重定向会导致浏览器地址栏中显示新的 URL,客户端感知到了页面的跳转。
- 重定向不会共享请求的属性和参数,每次重定向会创建一个新的请求,适合用于处理用户的提交、防止表单的重复提交等。
- 在代码中,使用
HttpServletResponse
的sendRedirect()
方法进行重定向,如:response.sendRedirect("/nextPage.jsp");
转发能够在服务器内部完成,共享请求信息和客户端状态,效率较高;而重定向是通过多次请求和响应实现跳转,相对于转发更消耗资源。因此,根据页面跳转的要求,选择合适的方式可以提高应用性能和用户体验。
4、集合
集合(Collection)是 Java 中用于存储和操作一组对象的工具类。它提供了一组灵活而强大的数据结构和算法,能够方便地对集合中的元素进行增删改查等操作。
Java 提供了多种集合类,主要包括以下几种:
-
List(列表):按照元素的插入顺序进行存储,允许元素的重复。常用的实现类有 ArrayList、LinkedList 和 Vector。
-
Set(集):不允许重复元素的集合,没有固定的顺序。常用的实现类有 HashSet、LinkedHashSet 和 TreeSet。
-
Map(映射表):键值对的集合,每个键唯一。常用的实现类有 HashMap、LinkedHashMap 和 TreeMap。
-
Queue(队列):先进先出(FIFO)的集合。常用的实现类有 LinkedList 和 PriorityQueue。
集合类提供了丰富的方法和功能,可以对元素进行增加、删除、修改、查找和遍历等操作。同时,Java 还提供了许多工具类和接口来辅助集合的操作,如 Collections 类用于对集合进行排序和查找,Iterator 接口用于遍历集合等。
集合类的选择应该根据具体的需求和场景来确定。例如,如果需要对元素进行频繁的插入和删除操作,可以选择使用 LinkedList 实现的 List;如果需要快速的查找和访问元素,可以选择使用 HashMap 实现的 Map。根据元素的特性和操作的要求,选择合适的集合类可以提高程序的效率和易用性。
5、多线程
多线程是指一个程序中同时执行多个线程的并发机制。通过多线程,可以同时执行多个任务,提高程序的并发性和响应性能。
在 Java 中,多线程可以通过以下两种方式来实现:
-
继承
Thread
类:可以创建一个继承自Thread
类的子类,在子类中重写run()
方法来定义线程要执行的任务。然后通过创建该子类的对象,调用start()
方法来启动线程的执行。
class MyThread extends Thread {
public void run() {
// 线程要执行的任务
}
}
public class Main {
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start();
}
}
2、实现 Runnable
接口:可以创建一个实现了 Runnable
接口的类,实现接口中的 run()
方法来定义线程要执行的任务。然后通过创建该类的对象,将其作为参数传递给 Thread
类的构造方法,并调用 start()
方法来启动线程的执行。
class MyRunnable implements Runnable {
public void run() {
// 线程要执行的任务
}
}
public class Main {
public static void main(String[] args) {
MyRunnable runnable = new MyRunnable();
Thread thread = new Thread(runnable);
thread.start();
}
}
多线程可以实现并行执行多个任务,每个线程在独立的执行路径上运行,可以同时进行不同的操作。在多线程编程中,需要处理线程同步、互斥、资源共享等问题,以避免出现竞态条件和数据不一致等问题。
Java 提供了丰富的多线程相关的类和方法,如 synchronized
关键字、wait()
、notify()
、notifyAll()
方法用于线程同步和互斥;Thread
类的方法如 sleep()
、join()
、interrupt()
等用于控制线程的执行和状态;ExecutorService
和 ThreadPoolExecutor
类用于管理线程池等。
使用多线程可以提高程序的性能和响应性,但也需要注意线程安全和资源共享的问题,合理地设计和管理多线程可以充分发挥多核处理器的优势,提高程序的执行效率。同时,也需要注意避免线程死锁、资源竞争等问题,保证多线程的正确性和稳定性。
6、bio和nio的区别
BIO(Blocking I/O,阻塞 I/O)和 NIO(Non-blocking I/O,非阻塞 I/O)是 Java 中用于进行 I/O 操作的两种不同的方式,它们之间存在着一些区别。
-
阻塞 I/O(BIO):
- 阻塞 I/O 是传统的 I/O 模型,在进行 I/O 操作时会阻塞当前线程,直到操作完成才返回结果。
- 在阻塞模式下,当一个线程在执行 I/O 操作时,线程会被阻塞,无法执行其他任务,直到 I/O 操作完成或超时。
- 在服务器端,每个连接需要一个独立的线程进行处理,当并发连接数较高时,会占用大量的线程资源,降低系统的可伸缩性。
- 由于阻塞 I/O 的阻塞特性,适用于连接数较少且短期连接较多的场景,比如传统的阻塞式的 Socket 编程。
-
非阻塞 I/O(NIO):
- 非阻塞 I/O 是基于事件驱动的异步 I/O 模型,当进行 I/O 操作时,如果数据不可用,线程不会被阻塞,而是可以继续执行其他任务。
- 在非阻塞模式下,可以通过轮询来检查数据是否就绪,如果就绪则进行读取或写入操作,否则可以继续处理其他任务。
- 采用 Reactor 模式,通过一个或少量的线程来处理多个连接,提高系统的并发能力和资源利用率。
- NIO 提供了 Channel、Selector 和 Buffer 等新的抽象概念,并提供了非阻塞的 SocketChannel 和 ServerSocketChannel 等组件,可以实现更高效的异步 I/O 操作。
- 由于非阻塞 I/O 的非阻塞特性,适用于连接数较多且连接时间较长的场景,比如实现高性能的网络服务端和客户端。
7、数据库sql中的行转列和列转行
在数据库 SQL 中,行转列(Pivot)和列转行(Unpivot)是两种常见的数据转换操作。
-
行转列(Pivot):
- 行转列操作将多行数据转换为一行,将行数据按照某种规则进行合并、汇总,形成新的列。
- 通常使用聚合函数(如 SUM、MAX、MIN)和条件表达式(如 CASE WHEN)来实现行转列操作。
- 行转列通常用于将某个字段的多个取值转换为不同的列,方便数据展示和分析。
- 以下是一个示例,将不同年份的销售额转换为不同的列:
SELECT
Product,
SUM(CASE WHEN Year = 2020 THEN Sales ELSE 0 END) AS Sales_2020,
SUM(CASE WHEN Year = 2021 THEN Sales ELSE 0 END) AS Sales_2021
FROM
SalesTable
GROUP BY
Product;
2、列转行(Unpivot):
- 列转行操作将一行数据中的多个列变成多行,将列数据按照一定的规则拆分,形成新的行。
- 通常使用 UNION 或者 CASE WHEN 表达式来实现列转行操作。
- 列转行通常用于将多个相关字段的数据合并为一列,方便进行检索和分析。
- 以下是一个示例,将不同时段的销售额拆分成不同的行:
SELECT
Product,
'2020' AS Year,
Sales_2020 AS Sales
FROM
SalesTable
UNION ALL
SELECT
Product,
'2021' AS Year,
Sales_2021 AS Sales
FROM
SalesTable;
8、http和https的区别
HTTP(Hypertext Transfer Protocol)和 HTTPS(Hypertext Transfer Protocol Secure)是用于在客户端和服务器之间传输数据的两种协议,它们之间存在以下区别:
-
安全性:
- HTTP 是明文传输协议,数据传输过程中不进行加密,容易被黑客截获并窃取敏感信息。
- HTTPS 基于 SSL/TLS 协议,对传输的数据进行加密,提供更高的安全性,可以保护数据的机密性和完整性。
-
默认端口:
- HTTP 默认使用端口号 80 进行通信。
- HTTPS 默认使用端口号 443 进行通信。
-
证书要求:
- 使用 HTTPS 需要在服务器上配置数字证书,确保通信的安全性。
- HTTP 不需要数字证书。
-
连接建立:
- 在 HTTP 中,连接的建立是简单而直接的,每个请求都会建立一个新的连接,请求完成后连接关闭。
- 在 HTTPS 中,使用 SSL/TLS 协议进行通信,涉及到握手和密钥交换等过程,较 HTTP 略慢。但 HTTPS 支持持久连接,同一个域名下的多个请求可以在同一连接上复用,提高性能。
-
SEO 影响:
- 搜索引擎更喜欢采用 HTTPS 加密网站,将 HTTPS 网站排名在搜索结果的前面。
- HTTP 网站可能会被搜索引擎降权,导致排名较低。