这一系列旨在从安全的视角来学习Java开发,聚焦于JavaEE开发,主要目的在于快速学习并读懂 JavaEE 的开发代码。

本文主要对Java的基础知识、开发基础进行介绍

基础知识

基本概念

  1. 概念

    Java 是一种面向对象的编程语言,广泛用于开发各种应用程序,包括 Web 应用、移动应用、企业级系统和嵌入式系统等。

  2. 特点

    • 面向对象编程:Java 是一种基于对象的语言,支持继承、多态、封装和抽象等 OOP 概念。

      通过对象和类的定义,Java 能够实现模块化的代码结构,易于维护和扩展。

    • 跨平台性:Java 使用 JVM来实现跨平台功能,具有“Write Once, Run Anywhere”(一次编写,到处运行)的特点。不同操作系统上安装的 JVM 能够解释相同的 Java 字节码,因此 Java 程序可以在任何支持 JVM 的系统上运行。

  3. 版本

    Java 可以分为三大版本:

    • SE即标准版,包含了Java核心类库,主要用来开发桌面应用;
    • EE即企业版,包含SE,又有扩展部分(Servlet,JDBC等),主要用来开发分布式网络程序;
    • ME即微型版,包含了SE中部分类库,又有自己扩展部分,主要用来做移动类、嵌入式开发。

相关名词解释

  1. Java运行环境与开发工具

    • JDK(Java Development Kit)

      JDK 是 Java 开发工具包,它提供了 Java 的开发环境(提供了编译器 javac 等工具,用于将 java 文件编译为 class 文件)和运行环境(提 供了 JVM 和 Runtime 辅助包,用于解析 class 文件使其得到运行)。如果你下载并安装了 JDK,那么你不仅可以开发 Java 程序,也同时拥有了运行 Java 程序的平台。JDK 是整个 Java 的核心,包括了 Java 运行环境(JRE),一堆 Java 工具 tools.jar 和 Java 标准类库 (rt.jar)。

      • **JRE(Java Runtime Enviroment) **

        JRE 是 Java 的运行环境。面向 Java 程序的使用者,而不是开发者。如果你仅下载并安装了 JRE,那么你的系统只能运行 Java 程序。JRE 是运行 Java 程序所必须环境的集合,包含 JVM 标准实现及 Java 核心类库。它包括 Java 虚拟机、Java 平台核心类和支持文件。它不包含开发工具(编译器、调试器等)。

      • JVM(Java Virtual Machine,java虚拟机)

        java虚拟机是java的运行时环境,提供了内存管理、垃圾回收、线程调度等功能,保证了 Java 程序的安全性、可移植性和高性能。对于不同的平台,Windows,Linux,Mac OS等,有具体不同的JVM版本。这些JVM屏蔽了平台的不同,提供了统一的运行环境,让Java代码无需考虑平台的差异,运行在不同的环境中。

        参考:大白话带你认识 JVM

  2. java web开发三大件

    在 Java Web 开发中,Servlet、Filter、和Listener被称为“三大件”,它们是Java EE中用于处理Web请求、响应和事件的三种核心组件。

    • Servlet:Servlet是运行在服务器端的Java程序,用于处理客户端(通常是浏览器)发送的请求,并生成动态响应。主要用于处理HTTP请求,比如GET和POST请求,接收到请求后生成HTML内容、处理表单数据、执行业务逻辑、与数据库交互等。

      原理:

      image-20241025162021934

    • Filter:介于Web容器和Servlet之间的过滤器,用于过滤未到达Servlet的请求或者由Servlet生成但还未返回响应。客户端请求从 Web 容器到达 Servlet 之前,会先经过 Filter,由 Filter 对 request 的某些信息进行处理之后交给 Servlet。同样,响应从 Servlet 传回 Web 容器之前,也会被 Filter 拦截,由 Filter 对 response 进行处理之后再交给 Web 容器。

    • Listener:用于监听Web应用程序中各种事件(如会话创建、销毁、请求初始化、上下文加载等)的组件。当特定动作发生时,监听该动作的监听器就会自动调用对应的方法。通常用于执行一些事件驱动的任务,比如统计在线用户数、记录日志、监控应用状态等。

    当我们在请求一个实现servlet-api规范的java web应用时,程序先自动执行 listener 监听器的内容,再去执行 filter 过滤器,如果存在多个过滤器则会组成过滤链,最后一个过滤器将会去执行 Servlet 的 service 方法,即 Listener -> Filter -> Servlet

  3. Context:在Java Web应用中,Context通常指的是ServletContext,它是Web容器(如Tomcat、Jetty、JBoss等)为每个Web应用创建的上下文环境,类似于一个全局对象,用于存储Web应用的配置信息和资源。

    Context的作用

    • Web应用的全局信息管理:ServletContext在Web应用启动时被创建,并在整个应用的生命周期内都存在。它可以存储全局的配置信息,比如初始化参数、应用级别的属性等。

    • 资源管理:通过ServletContext,Web应用可以访问Web应用的资源,比如Web应用目录中的文件、静态资源、属性文件等。

    • 对象共享:ServletContext允许在不同的Servlet、Filter、Listener之间共享数据。开发者可以通过ServletContext的setAttribute()getAttribute()方法,在不同组件之间共享对象。

    • 请求转发:ServletContext也可以用于请求的转发和资源的请求,通过调用getRequestDispatcher()方法进行请求转发。

  4. 中间件(Middleware):中间件是一种用于在不同应用、系统或组件之间进行连接和通信的软件层(一种组件),负责数据管理、通信和事务处理。它不局限于Web环境,而是适用于各种分布式系统和企业应用。

  5. Java Instrumentation

    它是一种在 Java 代码运行时动态修改字节码的技术。该功能主要由 Java SE 提供的 java.lang.instrument 包实现。它允许开发者在不修改源代码的情况下,通过代理或其他方式对类进行修改或增强。

    开发者可以通过修改方法的字节码实现动态修改类代码。利用Instrument,开发者可以开发单独的代理Agent,实现对JVM进程的运行时监控,分析JVM进程运行时内存状态,甚至可以很方便地修改内存中类的字节码,修改或者扩展已有的功能。

    Java agent和Java Instrumentation的区别

    简单来说,Java Agent 是一种在 JVM 启动时注入代码的机制,而 Instrumentation 提供了实际执行类字节码修改的能力。Java Agent 通过 Instrumentation API 实现字节码修改,是更高层次的抽象和应用。

  6. Attach API

    Attach API 是 Java 虚拟机(JVM)中提供的一个 API,用于在 Java 应用程序运行时动态地加载或附加外部工具和代理(agents)到已启动的 JVM 进程上。这在诊断、性能分析和调试方面非常有用,因为它允许在不重新启动 JVM 的情况下附加工具,进行故障排查和性能监控。

    白话:attach api 用于将java agent动态附加到运行中的JVM上,这样可以进一步使用Instrumentation API修改类字节码

API 作用 使用场景 特点与限制
Instrumentation API 在运行时对类进行修改和管理 JVM 启动时加载的代理、性能监控、代码增强 可以修改类字节码,也可以重定义类;需与 Java Agent 配合
Transform API 类加载时拦截字节码并修改 类加载时的字节码修改,如日志注入、监控 Instrumentation API 的子集,不能独立使用
Attach API 动态附加代理到已运行的 JVM 上 动态附加代理,特别是远程调试和动态监控 不直接修改字节码,需借助 Instrumentation API
  1. Hook:在计算机领域,hook(钩子)是一种技术,允许开发者在程序的正常执行路径中插入自己的代码,从而在特定的位置对程序的行为进行拦截、修改或增强。

    恶意代码(例如内存马)通常会调用某些特定类和方法以达到目的。Hook 可以拦截这些方法的调用,从而发现和阻止恶意行为。

  2. Jar包(Java ARchive)

    JAR包可以将 Java 应用程序的多个 .class 文件、资源文件(如图片、配置文件)、以及依赖项封装成一个单独的文件。这样,分发和部署应用时,只需提供一个 JAR 包,避免发送多个文件的麻烦。实现模块化和插件化。

java运行原理

image-20241031111240801

  1. 将Java 代码编译成字节码.java 源码被 javac.exe 编译器编译成.class字节码文件。这个过程的大致执行流程:Java源代码-> 词法分析器 -> 语法分析器 -> 语义分析器 -> 字节码生成器-> 最终生成字节码,其中任何一个节点执行失败就会造成编译失败;

  2. 类加载:虚拟机通过类加载器(ClassLoader)把class文件和相关Java API加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的 Java 类型。

  3. 字节码校验:为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,不会危害虚拟机的安全,Java虚拟机对输入的字节流走验证过程。验证阶段包括四个阶段:文件格式验证、元数据验证、字节码验证、符号引用验证。

  4. 翻译执行:JVM 解释器会把字节码翻译成机器码交由操作系统执行

    • 解释执行:来一行代码,解释一行,大部分不常用的代码,都是采用这种方式。

    • 即时编译:对于部分热点代码,将一个方法包含的所有字节码翻译成机器指令,以提高java虚拟机的运行效率。

Java项目目录结构

在Java项目中,目录结构通常遵循一定的标准,以保持代码的组织清晰、可维护性高。

参考:看完这篇,别人的开源项目结构应该能看懂了

标准Maven/Gradle项目目录结构

以下是标准的基于 Maven 或 Gradle Java 的 Java 项目目录结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
my-java-project/
│── src/
│ ├── main/
│ │ ├── java/ # 存放Java源代码
│ │ │ └── com/
│ │ │ └── example/
│ │ │ ├── App.java # 主要的Java应用程序
│ │ │ ├── service/ # 业务逻辑层
│ │ │ ├── dao/ # 数据访问层(通常用于数据库操作)
│ │ │ ├── model/ # 数据模型(实体类)
│ │ │ └── utils/ # 工具类
│ │ ├── resources/ # 存放资源文件(配置文件、模板等)
│ │ ├── application.properties # 配置文件
│ │ ├── log4j.properties # 日志配置文件
│ │ └── static/ # 静态资源(如HTML、CSS、JavaScript)
│ ├── test/ # 测试代码目录
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── example/
│ │ │ ├── AppTest.java # 单元测试代码
│ │ ├── resources/ # 测试资源文件
│ │ ├── test-application.properties # 测试环境配置文件
│── pom.xml (Maven项目配置文件)
│── build.gradle (Gradle项目配置文件)
│── settings.gradle (Gradle配置文件)
│── .gitignore (Git忽略文件)
│── README.md (项目说明文档)
│── target/ (Maven 构建输出目录,通常不会提交到版本控制)
│── build/ (Gradle 构建输出目录,通常不会提交到版本控制)
│── libs/ (存放外部依赖的JAR包)
  1. src/main/java/

    • 主要的Java源代码文件存放位置。
    • 通常按照包结构进行组织,如 com.example
  2. src/main/resources/

    • 存放资源文件,如 application.properties(Spring Boot 配置)或 log4j.properties(日志配置)。
    • static/ 用于存放静态资源,如 HTML、CSS、JavaScript(Web 应用中)。
  3. src/test/java/

    • 存放测试代码,通常使用 JUnit 或 TestNG 进行单元测试。

    • 结构与 src/main/java/ 类似。

  4. src/test/resources/

    存放测试相关的资源,如测试环境下的 application.properties

  5. pom.xml(Maven项目)

    用于Maven项目管理依赖、构建信息、插件等。

  6. build.gradle & settings.gradle(Gradle项目)

    Gradle 项目的构建配置文件。

  7. .gitignore

    指定 Git 需要忽略的文件(如 target/build/)。

  8. README.md

    项目的文档说明,通常包含项目介绍、使用方法、开发指南等信息。

  9. target/ & build/

    • 编译后的输出目录,target/ 用于 Maven,build/ 用于 Gradle。

    • 这些目录通常不会提交到版本控制(在 .gitignore 中忽略)。

  10. libs/

    存放额外的 JAR 依赖(如果使用了本地 JAR)。

Spring Boot项目目录结构

基于 Spring Boot 开发的 Java 项目目录结构与标准的 Maven 或 Gradle Java 项目类似,但有一些特定的调整,以便于支持 Spring Boot 的特性,如自动配置、嵌入式服务器和约定优于配置。

以下是一个典型的 Spring Boot 项目目录结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
my-springboot-app/
│── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── example/
│ │ │ ├── MySpringBootApplication.java # Spring Boot 启动类
│ │ │ ├── controller/ # 控制层(处理 HTTP 请求)
│ │ │ ├── service/ # 业务逻辑层
│ │ │ ├── repository/ # 数据访问层 (类似 DAO)
│ │ │ ├── model/ # 数据模型 (Entity)
│ │ │ ├── config/ # 配置类 (如 Security、CORS)
│ │ │ └── utils/ # 工具类
│ │ ├── resources/
│ │ │ ├── application.properties # Spring Boot 配置 (YAML 也可以)
│ │ │ ├── application.yml # 配置文件(另一种格式)
│ │ │ ├── static/ # 静态资源(HTML, CSS, JS)
│ │ │ ├── templates/ # 存放 Thymeleaf 或 Freemarker 模板
│ │ │ ├── messages.properties # 国际化资源文件
│ │ │ ├── logback-spring.xml # 日志配置
│ │ │ └── data.sql # 启动时初始化数据库数据
│ ├── test/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── example/
│ │ │ ├── MySpringBootApplicationTests.java # 测试类
│ │ │ ├── controller/ # 控制层测试
│ │ │ ├── service/ # 业务层测试
│ │ │ ├── repository/ # 数据层测试
│── pom.xml (Maven 构建配置)
│── build.gradle (Gradle 构建配置)
│── .gitignore
│── README.md
│── target/ (Maven 编译输出)
│── build/ (Gradle 编译输出)
│── Dockerfile (可选,Docker 部署)
│── scripts/ (可选,存放 Shell 或 SQL 脚本)
│── src/main/docker/ (可选,Docker 配置)
│── src/main/resources/banner.txt (可选,Spring Boot 启动 Banner)
  1. MySpringBootApplication.java

    Spring Boot 启动类,是应用的入口。该类会启用自动配置,管理 Bean,并嵌入 Web 服务器(如 Tomcat)。

  2. 分层结构

    Spring Boot 推荐按照 Controller-Service-Repository 三层架构组织代码:

    • controller/:负责接收和返回 HTTP 请求
    • service/:负责处理业务逻辑
    • repository/:负责与数据库交互,通常使用 JpaRepositoryCrudRepository
  3. application.propertiesapplication.yml

    Spring Boot 推荐将配置信息放在 src/main/resources/application.propertiesapplication.yml

  4. templates/static/

    • templates/:用于存放 ThymeleafFreemarker 等模板引擎的 HTML 视图文件。
    • static/:用于存放静态资源,如 CSS、JS、图片等(Spring Boot 会自动映射)。
  5. 日志配置

    默认情况下,Spring Boot 使用 Logback 进行日志管理,可通过 logback-spring.xml 配置。

  6. 数据初始化

    可以在 resources/ 目录下放置 schema.sql(数据库结构)和 data.sql(默认数据),应用启动时自动执行。

  7. Docker & DevOps

    • 许多 Spring Boot 项目会添加 Dockerfile 进行容器化部署。

    • 可能还会包含 scripts/ 目录,存放 Shell 脚本或 SQL 脚本。

一些特殊文件

  • MANIFEST.MF :用于配置和描述 JAR 文件的元数据。它位于 JAR 文件的 META-INF 目录下,主要作用是提供关于 JAR 文件的描述信息和配置指定属性,以控制 JAR 的执行方式和行为。

  • web.xml:配置 Web 应用的相关组件和行为,在项目部署到 Servlet 容器(如 Tomcat)时,容器会读取这个文件来初始化应用。主要包含Servlet配置、Filter配置、Listener配置、error-page配置等

    注意:在 Servlet 3.0 之后,可以通过 注解(如 @WebServlet@WebFilter)来替代 web.xml 中的大部分配置。

Tomcat

参考:Tomcat 架构原理解析到架构设计借鉴

请求定位 Servlet 的过程

一个请求是如何定位到让哪个 WrapperServlet 处理的?答案是,Tomcat 是用 Mapper 组件来完成这个任务的。

Mapper 组件的功能就是将用户请求的 URL 定位到一个 Servlet,它的工作原理是:Mapper组件里保存了 Web 应用的配置信息,其实就是容器组件与访问路径的映射关系,比如 Host容器里配置的域名、Context容器里的 Web应用路径,以及 Wrapper容器里 Servlet 映射的路径,你可以想象这些配置信息就是一个多层次的 Map

当一个请求到来时,Mapper 组件通过解析请求 URL 里的域名和路径,再到自己保存的 Map 里去查找,就能定位到一个 Servlet。请你注意,一个请求 URL 最后只会定位到一个 Wrapper容器,也就是一个 Servlet

img

假如有用户访问一个 URL,比如图中的http://user.shopping.com:8080/order/buy,Tomcat 如何将这个 URL 定位到一个 Servlet 呢?

  1. 首先根据协议和端口号确定 Service 和 Engine。Tomcat 默认的 HTTP 连接器监听 8080 端口、默认的 AJP 连接器监听 8009 端口。上面例子中的 URL 访问的是 8080 端口,因此这个请求会被 HTTP 连接器接收,而一个连接器是属于一个 Service 组件的,这样 Service 组件就确定了。我们还知道一个 Service 组件里除了有多个连接器,还有一个容器组件,具体来说就是一个 Engine 容器,因此 Service 确定了也就意味着 Engine 也确定了。
  2. 根据域名选定 Host。 Service 和 Engine 确定后,Mapper 组件通过 URL 中的域名去查找相应的 Host 容器,比如例子中的 URL 访问的域名是user.shopping.com,因此 Mapper 会找到 Host2 这个容器。
  3. 根据 URL 路径找到 Context 组件。 Host 确定以后,Mapper 根据 URL 的路径来匹配相应的 Web 应用的路径,比如例子中访问的是 /order,因此找到了 Context4 这个 Context 容器。
  4. 根据 URL 路径找到 Wrapper(Servlet)。 Context 确定后,Mapper 再根据 web.xml 中配置的 Servlet 映射路径来找到具体的 Wrapper 和 Servlet。

基础语法

基本语法:Java教程:入门基础【十万字详解】

对象、类等概念的总结:Java 对象和类

java package:Java中的包(package)是什么和如何使用它们