java理解
springboot
打包
mvn install:install-file -Dfile=<path-to-jar> -DgroupId=<group-id> -DartifactId=<artifact-id> -Dversion=<version> -Dpackaging=jar
<path-to-jar> 是你的 JAR 文件的路径。
<group-id> 是你的项目的组 ID。
<artifact-id> 是你的项目的构件 ID。
<version> 是你的项目的版本号。mvn install:install-file -Dfile=D:\ojdbc6-11.2.0.1.0.jar -DgroupId=com.oracle -DartifactId=ojdbc6 -Dversion=11.2.0.1.0 -Dpackaging=jar
AOP
根据目标对象是否实现接口自动选择动态代理机制。
-
JDK 动态代理:适用于目标对象实现了接口的情况。
JDK 动态代理是 Java 提供的一种动态创建代理对象的机制。它允许在运行时动态地创建一个代理类,该代理类实现了与目标对象相同的接口,并且可以拦截对目标对象方法的调用。通过这种方式,可以在不修改目标对象代码的情况下,对目标对象的方法调用进行增强(如添加日志、事务管理等)。
-
CGLIB 动态代理:适用于目标对象没有实现接口的情况。
通过aspect注解定义切面,可以结合自定义注解实现 不改变源代码情况下,在方法执行前后增加功能。
IOC
通过 IoC,Spring 容器负责管理对象的生命周期和依赖关系,而不是由开发者手动管理。
@Repository
:标记一个类为数据访问层组件,通常用于数据库操作。@Qualifier
:用于指定注入的 Bean 的名称,当存在多个同类型的 Bean 时,可以使用该注解来明确指定注入哪一个 Bean。@Primary
:用于指定默认注入的 Bean,当存在多个同类型的 Bean 时,Spring 容器会优先注入标记为@Primary
的 Bean。- @Cacheable` 是 Spring 缓存框架提供的一个注解,用于声明一个方法的结果是可缓存的。当方法被调用时,Spring 会检查缓存中是否已经存在相应的值。如果存在,则直接从缓存中返回结果,而不会执行方法体;如果不存在,则执行方法体并将结果存入缓存,以便下次调用时可以直接从缓存中获取。
- @Transactional: 被标记的方法如果出现**
RuntimeException
和Error
**会回滚事物。- Spring 事务的隔离级别有哪些?
READ_UNCOMMITTED
:最低的隔离级别,允许读取未提交的数据,可能出现脏读。READ_COMMITTED
:允许读取已提交的数据,避免了脏读,但可能出现不可重复读。REPEATABLE_READ
(默认级别):保证在同一个事务中多次读取数据的结果是一致的,避免了不可重复读,但可能出现幻读。SERIALIZABLE
:最高的隔离级别,完全隔离并发事务,避免了脏读、不可重复读和幻读,但性能开销最大。
- 什么是脏读、不可重复读和幻读?
- 脏读:一个事务读取了另一个事务未提交的数据。
- 不可重复读:一个事务在两次读取同一数据时,数据被另一个事务修改,导致两次读取的结果不一致。
- 幻读:一个事务在两次读取同一范围的数据时,数据被另一个事务插入或删除,导致两次读取的结果不一致。
- Spring 事务的隔离级别有哪些?
线程池
线程池的基本概念
- 什么是线程池?
- 线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建了线程后,从队列中取出任务并执行。
- 线程池的主要目的是减少线程创建和销毁的开销,提高线程的复用性。
- 线程池的主要优点是什么?
- 减少线程创建和销毁的开销:线程池会复用已创建的线程,减少线程创建和销毁的次数。
- 提高响应速度:任务提交后可以直接从线程池中获取线程执行,减少了线程创建的时间。
- 提高线程的可管理性:线程池可以对线程进行统一管理,如设置线程的最大数量、队列大小等。
- 避免资源耗尽:通过限制线程的最大数量,避免系统资源耗尽。
- 线程池的主要组成部分是什么?
- 线程池管理器:负责创建和管理线程池。
- 工作线程:线程池中实际执行任务的线程。
- 任务队列:用于存储待执行任务的队列。
- 任务接口:所有任务必须实现的接口,以便工作线程可以执行。
线程池的实现原理
- Java 中的线程池是如何实现的?
- Java 的线程池主要通过
java.util.concurrent
包中的Executor
框架实现。 Executor
是一个接口,定义了执行任务的方法。ExecutorService
是Executor
的子接口,提供了更丰富的功能,如线程池的管理。ThreadPoolExecutor
是ExecutorService
的实现类,提供了线程池的核心实现。
- Java 的线程池主要通过
ThreadPoolExecutor
的构造参数有哪些?corePoolSize
:核心线程数,线程池中始终保持的线程数量。maximumPoolSize
:最大线程数,线程池中允许的最大线程数量。keepAliveTime
:非核心线程的空闲存活时间。unit
:keepAliveTime
的时间单位。workQueue
:任务队列,用于存储待执行任务的队列。threadFactory
:线程工厂,用于创建线程。handler
:拒绝策略,当任务队列满且线程数达到最大值时,如何处理新任务。
- 线程池的拒绝策略有哪些?
AbortPolicy
:直接抛出RejectedExecutionException
。CallerRunsPolicy
:由调用线程执行任务。DiscardPolicy
:直接丢弃任务。DiscardOldestPolicy
:丢弃队列中最老的任务,然后尝试提交新任务。
线程池的使用方法
-
如何创建一个线程池?
-
使用
ThreadPoolExecutor
的构造方法创建线程池。 -
示例:
import java.util.concurrent.*;public class ThreadPoolExample {public static void main(String[] args) {ThreadPoolExecutor executor = new ThreadPoolExecutor(2, // 核心线程数4, // 最大线程数60L, // 空闲存活时间TimeUnit.SECONDS, // 时间单位new LinkedBlockingQueue<Runnable>(100) // 任务队列);for (int i = 0; i < 10; i++) {executor.execute(() -> {System.out.println("Task executed by: " + Thread.currentThread().getName());});}executor.shutdown();} }
-
-
如何关闭线程池?
- 使用
shutdown()
方法关闭线程池,等待所有任务完成。 - 使用
shutdownNow()
方法立即关闭线程池,尝试中断正在执行的任务。
- 使用
-
如何提交任务到线程池?
- 使用
execute(Runnable command)
方法提交任务。 - 使用
submit(Callable<T> task)
方法提交任务并返回Future
对象。
- 使用
线程池的性能优化
- 如何优化线程池的性能?
- 合理设置线程池大小:根据系统的硬件资源和任务类型,合理设置核心线程数和最大线程数。
- 选择合适的任务队列:根据任务的特点选择合适的任务队列,如
LinkedBlockingQueue
或ArrayBlockingQueue
。 - 设置合理的拒绝策略:根据业务需求选择合适的拒绝策略,避免任务丢失。
- 监控线程池状态:通过
ThreadPoolExecutor
提供的方法监控线程池的状态,如getActiveCount()
、getCompletedTaskCount()
等。
线程池的高级特性
-
什么是线程池的饱和策略?
- 当任务队列满且线程数达到最大值时,线程池会采取的策略。可以通过
RejectedExecutionHandler
接口自定义饱和策略。
- 当任务队列满且线程数达到最大值时,线程池会采取的策略。可以通过
-
如何自定义线程工厂?
-
实现
ThreadFactory
接口,自定义线程的创建逻辑。 -
示例:
import java.util.concurrent.*;public class CustomThreadFactory implements ThreadFactory {private final String threadNamePrefix;public CustomThreadFactory(String threadNamePrefix) {this.threadNamePrefix = threadNamePrefix;}@Overridepublic Thread newThread(Runnable r) {return new Thread(r, threadNamePrefix + "-Thread-" + Thread.currentThread().getId());}public static void main(String[] args) {ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 4, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100),new CustomThreadFactory("MyCustomThread"));for (int i = 0; i < 10; i++) {executor.execute(() -> {System.out.println("Task executed by: " + Thread.currentThread().getName());});}executor.shutdown();} }
-
线程池的常见问题
- 线程池中的线程是如何复用的?
- 线程池中的线程在执行完一个任务后,会返回线程池,等待下一个任务。如果线程池中的线程数量超过核心线程数且空闲时间超过
keepAliveTime
,则会销毁多余的线程。
- 线程池中的线程在执行完一个任务后,会返回线程池,等待下一个任务。如果线程池中的线程数量超过核心线程数且空闲时间超过
- 线程池中的线程是如何销毁的?
- 当线程池中的线程数量超过核心线程数且空闲时间超过
keepAliveTime
时,多余的线程会被销毁。 - 当调用
shutdown()
方法时,线程池会等待所有任务完成后再销毁所有线程。 - 当调用
shutdownNow()
方法时,线程池会尝试中断正在执行的任务,并立即销毁所有线程。
- 当线程池中的线程数量超过核心线程数且空闲时间超过
- 线程池中的任务是如何调度的?
- 线程池中的任务通过任务队列进行调度。任务队列可以是阻塞队列(如
LinkedBlockingQueue
、ArrayBlockingQueue
)或非阻塞队列(如SynchronousQueue
)。 - 线程池会从任务队列中取出任务并分配给空闲的线程执行。
- 线程池中的任务通过任务队列进行调度。任务队列可以是阻塞队列(如
线程池的监控
- 如何监控线程池的状态?
- 使用
ThreadPoolExecutor
提供的方法监控线程池的状态,如:getActiveCount()
:获取当前活跃的线程数。getCompletedTaskCount()
:获取已完成的任务数。getTaskCount()
:获取任务总数。getPoolSize()
:获取线程池中的线程数。getLargestPoolSize()
:获取线程池中曾经出现的最大线程数。
- 使用
权限架构设计
五张表的sql
-- 1. 权限表
CREATE TABLE `sys_permission` (`id` bigint NOT NULL AUTO_INCREMENT,`code` varchar(100) NOT NULL COMMENT '权限标识符',`name` varchar(100) NOT NULL COMMENT '权限名称',`description` varchar(200) DEFAULT NULL COMMENT '权限描述',`category` varchar(50) DEFAULT NULL COMMENT '权限分类',`resource_type` varchar(20) DEFAULT NULL COMMENT '资源类型(MENU/BUTTON/API)',`resource_id` varchar(100) DEFAULT NULL COMMENT '关联资源ID',`order_num` int DEFAULT '0' COMMENT '排序号',`visible` bit(1) DEFAULT b'1' COMMENT '是否可见',`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',PRIMARY KEY (`id`),UNIQUE KEY `uk_code` (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='系统权限表';-- 2. 角色表
CREATE TABLE `sys_role` (`id` bigint NOT NULL AUTO_INCREMENT,`code` varchar(50) NOT NULL COMMENT '角色编码',`name` varchar(100) NOT NULL COMMENT '角色名称',`description` varchar(200) DEFAULT NULL COMMENT '角色描述',`data_scope` int DEFAULT '1' COMMENT '数据权限范围(1-全部 2-部门 3-个人)',`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',PRIMARY KEY (`id`),UNIQUE KEY `uk_code` (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='系统角色表';-- 3. 角色权限关联表
CREATE TABLE `sys_role_permission` (`role_id` bigint NOT NULL COMMENT '角色ID',`permission_id` bigint NOT NULL COMMENT '权限ID',`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',PRIMARY KEY (`role_id`,`permission_id`),KEY `idx_permission_id` (`permission_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='角色权限关联表';-- 4. 用户表
CREATE TABLE `sys_user` (`id` bigint NOT NULL AUTO_INCREMENT,`username` varchar(50) NOT NULL COMMENT '用户名',`password` varchar(100) NOT NULL COMMENT '密码',`nickname` varchar(50) DEFAULT NULL COMMENT '昵称',`email` varchar(100) DEFAULT NULL COMMENT '邮箱',`phone` varchar(20) DEFAULT NULL COMMENT '手机号',`avatar` varchar(255) DEFAULT NULL COMMENT '头像URL',`enabled` bit(1) DEFAULT b'1' COMMENT '是否启用',`account_non_expired` bit(1) DEFAULT b'1' COMMENT '账号是否未过期',`account_non_locked` bit(1) DEFAULT b'1' COMMENT '账号是否未锁定',`credentials_non_expired` bit(1) DEFAULT b'1' COMMENT '凭证是否未过期',`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',PRIMARY KEY (`id`),UNIQUE KEY `uk_username` (`username`),UNIQUE KEY `uk_email` (`email`),UNIQUE KEY `uk_phone` (`phone`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='系统用户表';-- 5. 用户角色关联表
CREATE TABLE `sys_user_role` (`user_id` bigint NOT NULL COMMENT '用户ID',`role_id` bigint NOT NULL COMMENT '角色ID',`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',PRIMARY KEY (`user_id`,`role_id`),KEY `idx_role_id` (`role_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户角色关联表';-- 6. 部门表(用于数据权限)
CREATE TABLE `sys_department` (`id` bigint NOT NULL AUTO_INCREMENT,`name` varchar(100) NOT NULL COMMENT '部门名称',`parent_id` bigint DEFAULT NULL COMMENT '父部门ID',`order_num` int DEFAULT '0' COMMENT '排序号',`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='部门表';-- 7. 用户部门关联表
CREATE TABLE `sys_user_department` (`user_id` bigint NOT NULL COMMENT '用户ID',`dept_id` bigint NOT NULL COMMENT '部门ID',`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',PRIMARY KEY (`user_id`,`dept_id`),KEY `idx_dept_id` (`dept_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户部门关联表';-- 初始化权限数据
INSERT INTO `sys_permission` (`code`, `name`, `description`, `category`, `resource_type`) VALUES
('system:user:create', '创建用户', '创建新用户权限', '用户管理', 'API'),
('system:user:update', '修改用户', '修改用户信息权限', '用户管理', 'API'),
('system:user:delete', '删除用户', '删除用户权限', '用户管理', 'API'),
('system:user:view', '查看用户', '查看用户信息权限', '用户管理', 'API'),
('system:role:manage', '角色管理', '角色增删改查权限', '角色管理', 'MENU');-- 初始化角色数据
INSERT INTO `sys_role` (`code`, `name`, `description`, `data_scope`) VALUES
('ROLE_ADMIN', '管理员', '系统管理员', 1),
('ROLE_USER', '普通用户', '普通用户', 3);-- 初始化角色权限关联
INSERT INTO `sys_role_permission` (`role_id`, `permission_id`) VALUES
(1, 1), (1, 2), (1, 3), (1, 4), (1, 5); -- 管理员拥有所有权限-- 初始化管理员用户
INSERT INTO `sys_user` (`username`, `password`, `nickname`, `email`, `enabled`) VALUES
('admin', '$2a$10$EblZqNptyYvcLm/VwDCVAuBjzZOI7khzdyGPBr08PpIi0na624b8.', '系统管理员', 'admin@example.com', 1);-- 设置管理员角色
INSERT INTO `sys_user_role` (`user_id`, `role_id`) VALUES (1, 1);-- 添加API权限数据
INSERT INTO sys_permission (code, name, description, resource_type) VALUES
('GET:/api/users', '查询用户列表', '查询用户列表API权限', 'API'),
('POST:/api/users', '创建用户', '创建用户API权限', 'API'),
('PUT:/api/users/*', '更新用户', '更新用户API权限', 'API'),
('DELETE:/api/users/*', '删除用户', '删除用户API权限', 'API'),
('GET:/api/admin', '管理员接口', '管理员专用API', 'API');-- 设置权限角色关系
INSERT INTO sys_role_permission (role_id, permission_id)
SELECT r.id, p.id FROM sys_role r, sys_permission p
WHERE r.code = 'ROLE_ADMIN' AND p.resource_type = 'API';-- 给普通用户分配部分权限
INSERT INTO sys_role_permission (role_id, permission_id)
SELECT r.id, p.id FROM sys_role r, sys_permission p
WHERE r.code = 'ROLE_USER' AND p.code IN ('GET:/api/users');
注册
注册相对简答,只需要在用户表和用户角色表添加记录就行
登录
本方案采用 Spring Security 作为安全框架基础,结合 JWT(JSON Web Token) 实现无状态认证,是一种典型的现代前后端分离架构的安全解决方案。
技术栈组成
- 认证方式:基于令牌的认证(Token-Based Authentication)
- 令牌格式:JWT(RFC 7519标准)
- 安全框架:Spring Security 6.x
- 存储方式:无状态服务端设计
认证流程
sequenceDiagramparticipant Clientparticipant Serverparticipant Filterparticipant AuthProviderClient->>Server: 登录请求(username/password)Server->>AuthProvider: 验证凭证AuthProvider-->>Server: 生成JWTServer->>Client: 返回JWTClient->>Server: 携带JWT的请求(Authorization头)Server->>Filter: JWT验证Filter->>Server: 构建认证对象Server->>Client: 返回受保护资源
组件关系图
┌─────────────────────────────────────────────────┐
│ Spring Security │
│ │
│ ┌─────────────┐ ┌───────────────────────┐ │
│ │ JwtFilter │◄────┤ SecurityConfig │ │
│ └─────────────┘ └───────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ ┌───────────────────────┐ │
│ │ JwtProvider │ │ UserDetailsService │ │
│ └─────────────┘ └───────────────────────┘ │
│ │ ▲ │
│ ▼ │ │
│ ┌─────────────┐ ┌───────────────────────┐ │
│ │ AuthController │ │ UserRepository │ │
│ └─────────────┘ └───────────────────────┘ │
└─────────────────────────────────────────────────┘
代码去gitee仓库找,太多了,懒得放了。
设计模式
装饰器加适配器
理解:
准备一个接口,两个实现类,实现类一实现基本功能,实现类二中将实现类一注入进去,调用实现类一的方法,在方法前后添加特殊逻辑。
应用场景:
流程里用不用适配器,就看一点:各环节接口对不上,但又得一起干活。 对不上(参数、格式、方法名不一样),又改不了其中一方,就用适配器当“翻译”;能对上,或者能直接改接口,就不用折腾。
示例:
public interface ZSQservice {String ZSQService(String arg0, String arg1);
}
@Service
public class ZSQserviceImpl implements ZSQservice {@Overridepublic String ZSQService(String arg0, String arg1) {System.out.println("ZSQservice impl, arg0=" + arg0 + ", arg1=" + arg1);return "return, arg0=" + arg0 + ", arg1=" + arg1;}
}
@Slf4j
@Service
public class ZSQLOGIMPL implements ZSQservice {private ZSQservice zsqservice;public ZSQLOGIMPL(@Qualifier("ZSQEncryImpl")ZSQservice zsqservice) {this.zsqservice = zsqservice;}@Overridepublic String ZSQService(String arg0, Strin