『安全开发』JAVA安全开发(一)Java基础
这一系列旨在从安全的视角来学习Java开发,聚焦于JavaEE开发,主要目的在于快速学习并读懂 JavaEE 的开发代码。
本文主要对Java的基础知识、开发基础进行介绍
基础知识
基本概念
-
概念
Java 是一种面向对象的编程语言,广泛用于开发各种应用程序,包括 Web 应用、移动应用、企业级系统和嵌入式系统等。
-
特点
-
面向对象编程:Java 是一种基于对象的语言,支持继承、多态、封装和抽象等 OOP 概念。
通过对象和类的定义,Java 能够实现模块化的代码结构,易于维护和扩展。
-
跨平台性:Java 使用
JVM
来实现跨平台功能,具有“Write Once, Run Anywhere”(一次编写,到处运行)的特点。不同操作系统上安装的 JVM 能够解释相同的 Java 字节码,因此 Java 程序可以在任何支持 JVM 的系统上运行。
-
-
版本
Java 可以分为三大版本:
- SE即标准版,包含了Java核心类库,主要用来开发桌面应用;
- EE即企业版,包含SE,又有扩展部分(Servlet,JDBC等),主要用来开发分布式网络程序;
- ME即微型版,包含了SE中部分类库,又有自己扩展部分,主要用来做移动类、嵌入式开发。
相关名词解释
-
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
-
-
-
java web开发三大件
在 Java Web 开发中,Servlet、Filter、和Listener被称为“三大件”,它们是Java EE中用于处理Web请求、响应和事件的三种核心组件。
-
Servlet:Servlet是运行在服务器端的Java程序,用于处理客户端(通常是浏览器)发送的请求,并生成动态响应。主要用于处理HTTP请求,比如GET和POST请求,接收到请求后生成HTML内容、处理表单数据、执行业务逻辑、与数据库交互等。
原理:
-
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
-
-
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()
方法进行请求转发。
-
-
中间件(Middleware):中间件是一种用于在不同应用、系统或组件之间进行连接和通信的软件层(一种组件),负责数据管理、通信和事务处理。它不局限于Web环境,而是适用于各种分布式系统和企业应用。
-
Java Instrumentation
它是一种在 Java 代码运行时动态修改字节码的技术。该功能主要由 Java SE 提供的
java.lang.instrument
包实现。它允许开发者在不修改源代码的情况下,通过代理或其他方式对类进行修改或增强。开发者可以通过修改方法的字节码实现动态修改类代码。利用Instrument,开发者可以开发单独的代理Agent,实现对JVM进程的运行时监控,分析JVM进程运行时内存状态,甚至可以很方便地修改内存中类的字节码,修改或者扩展已有的功能。
Java agent和Java Instrumentation的区别
简单来说,Java Agent 是一种在 JVM 启动时注入代码的机制,而 Instrumentation 提供了实际执行类字节码修改的能力。Java Agent 通过 Instrumentation API 实现字节码修改,是更高层次的抽象和应用。
-
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
-
Hook:在计算机领域,hook(钩子)是一种技术,允许开发者在程序的正常执行路径中插入自己的代码,从而在特定的位置对程序的行为进行拦截、修改或增强。
恶意代码(例如内存马)通常会调用某些特定类和方法以达到目的。Hook 可以拦截这些方法的调用,从而发现和阻止恶意行为。
-
Jar包(Java ARchive)
JAR包可以将 Java 应用程序的多个
.class
文件、资源文件(如图片、配置文件)、以及依赖项封装成一个单独的文件。这样,分发和部署应用时,只需提供一个 JAR 包,避免发送多个文件的麻烦。实现模块化和插件化。
java运行原理
-
将Java 代码编译成字节码:
.java
源码被javac.exe
编译器编译成.class
字节码文件。这个过程的大致执行流程:Java源代码-> 词法分析器 -> 语法分析器 -> 语义分析器 -> 字节码生成器-> 最终生成字节码,其中任何一个节点执行失败就会造成编译失败; -
类加载:虚拟机通过类加载器(ClassLoader)把class文件和相关Java API加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的 Java 类型。
-
字节码校验:为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,不会危害虚拟机的安全,Java虚拟机对输入的字节流走验证过程。验证阶段包括四个阶段:文件格式验证、元数据验证、字节码验证、符号引用验证。
-
翻译执行:JVM 解释器会把字节码翻译成机器码交由操作系统执行
-
解释执行:来一行代码,解释一行,大部分不常用的代码,都是采用这种方式。
-
即时编译:对于部分热点代码,将一个方法包含的所有字节码翻译成机器指令,以提高java虚拟机的运行效率。
-
Java项目目录结构
在Java项目中,目录结构通常遵循一定的标准,以保持代码的组织清晰、可维护性高。
标准Maven/Gradle项目目录结构
以下是标准的基于 Maven 或 Gradle Java 的 Java 项目目录结构
1 | my-java-project/ |
-
src/main/java/
- 主要的Java源代码文件存放位置。
- 通常按照包结构进行组织,如
com.example
。
-
src/main/resources/
:- 存放资源文件,如
application.properties
(Spring Boot 配置)或log4j.properties
(日志配置)。 static/
用于存放静态资源,如 HTML、CSS、JavaScript(Web 应用中)。
- 存放资源文件,如
-
src/test/java/
-
存放测试代码,通常使用 JUnit 或 TestNG 进行单元测试。
-
结构与
src/main/java/
类似。
-
-
src/test/resources/
存放测试相关的资源,如测试环境下的
application.properties
。 -
pom.xml
(Maven项目):用于Maven项目管理依赖、构建信息、插件等。
-
build.gradle
&settings.gradle
(Gradle项目):Gradle 项目的构建配置文件。
-
.gitignore
指定 Git 需要忽略的文件(如
target/
、build/
)。 -
README.md
项目的文档说明,通常包含项目介绍、使用方法、开发指南等信息。
-
target/
&build/
-
编译后的输出目录,
target/
用于 Maven,build/
用于 Gradle。 -
这些目录通常不会提交到版本控制(在
.gitignore
中忽略)。
-
-
libs/
:存放额外的 JAR 依赖(如果使用了本地 JAR)。
Spring Boot项目目录结构
基于 Spring Boot 开发的 Java 项目目录结构与标准的 Maven 或 Gradle Java 项目类似,但有一些特定的调整,以便于支持 Spring Boot 的特性,如自动配置、嵌入式服务器和约定优于配置。
以下是一个典型的 Spring Boot 项目目录结构:
1 | my-springboot-app/ |
-
MySpringBootApplication.java
Spring Boot 启动类,是应用的入口。该类会启用自动配置,管理
Bean
,并嵌入 Web 服务器(如 Tomcat)。 -
分层结构
Spring Boot 推荐按照
Controller-Service-Repository
三层架构组织代码:controller/
:负责接收和返回 HTTP 请求service/
:负责处理业务逻辑repository/
:负责与数据库交互,通常使用JpaRepository
或CrudRepository
-
application.properties
或application.yml
Spring Boot 推荐将配置信息放在
src/main/resources/application.properties
或application.yml
-
templates/
和static/
templates/
:用于存放 Thymeleaf、Freemarker 等模板引擎的 HTML 视图文件。static/
:用于存放静态资源,如 CSS、JS、图片等(Spring Boot 会自动映射)。
-
日志配置
默认情况下,Spring Boot 使用 Logback 进行日志管理,可通过
logback-spring.xml
配置。 -
数据初始化
可以在
resources/
目录下放置schema.sql
(数据库结构)和data.sql
(默认数据),应用启动时自动执行。 -
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
请求定位 Servlet 的过程
一个请求是如何定位到让哪个 Wrapper
的 Servlet
处理的?答案是,Tomcat 是用 Mapper 组件来完成这个任务的。
Mapper
组件的功能就是将用户请求的 URL
定位到一个 Servlet
,它的工作原理是:Mapper
组件里保存了 Web 应用的配置信息,其实就是容器组件与访问路径的映射关系,比如 Host
容器里配置的域名、Context
容器里的 Web
应用路径,以及 Wrapper
容器里 Servlet
映射的路径,你可以想象这些配置信息就是一个多层次的 Map
。
当一个请求到来时,Mapper
组件通过解析请求 URL 里的域名和路径,再到自己保存的 Map 里去查找,就能定位到一个 Servlet
。请你注意,一个请求 URL 最后只会定位到一个 Wrapper
容器,也就是一个 Servlet
。
假如有用户访问一个 URL,比如图中的http://user.shopping.com:8080/order/buy
,Tomcat 如何将这个 URL 定位到一个 Servlet 呢?
- 首先根据协议和端口号确定 Service 和 Engine。Tomcat 默认的 HTTP 连接器监听 8080 端口、默认的 AJP 连接器监听 8009 端口。上面例子中的 URL 访问的是 8080 端口,因此这个请求会被 HTTP 连接器接收,而一个连接器是属于一个 Service 组件的,这样 Service 组件就确定了。我们还知道一个 Service 组件里除了有多个连接器,还有一个容器组件,具体来说就是一个 Engine 容器,因此 Service 确定了也就意味着 Engine 也确定了。
- 根据域名选定 Host。 Service 和 Engine 确定后,Mapper 组件通过 URL 中的域名去查找相应的 Host 容器,比如例子中的 URL 访问的域名是
user.shopping.com
,因此 Mapper 会找到 Host2 这个容器。 - 根据 URL 路径找到 Context 组件。 Host 确定以后,Mapper 根据 URL 的路径来匹配相应的 Web 应用的路径,比如例子中访问的是 /order,因此找到了 Context4 这个 Context 容器。
- 根据 URL 路径找到 Wrapper(Servlet)。 Context 确定后,Mapper 再根据 web.xml 中配置的 Servlet 映射路径来找到具体的 Wrapper 和 Servlet。
基础语法
基本语法:Java教程:入门基础【十万字详解】
对象、类等概念的总结:Java 对象和类
java package:Java中的包(package)是什么和如何使用它们