java理解

发布于:2025-08-18 ⋅ 阅读:(18) ⋅ 点赞:(0)

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: 被标记的方法如果出现**RuntimeExceptionError**会回滚事物。
    1. Spring 事务的隔离级别有哪些?
      • READ_UNCOMMITTED:最低的隔离级别,允许读取未提交的数据,可能出现脏读。
      • READ_COMMITTED:允许读取已提交的数据,避免了脏读,但可能出现不可重复读。
      • REPEATABLE_READ(默认级别):保证在同一个事务中多次读取数据的结果是一致的,避免了不可重复读,但可能出现幻读。
      • SERIALIZABLE:最高的隔离级别,完全隔离并发事务,避免了脏读、不可重复读和幻读,但性能开销最大。
    2. 什么是脏读、不可重复读和幻读?
      • 脏读:一个事务读取了另一个事务未提交的数据。
      • 不可重复读:一个事务在两次读取同一数据时,数据被另一个事务修改,导致两次读取的结果不一致。
      • 幻读:一个事务在两次读取同一范围的数据时,数据被另一个事务插入或删除,导致两次读取的结果不一致。

线程池

线程池的基本概念

  1. 什么是线程池?
    • 线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建了线程后,从队列中取出任务并执行。
    • 线程池的主要目的是减少线程创建和销毁的开销,提高线程的复用性。
  2. 线程池的主要优点是什么?
    • 减少线程创建和销毁的开销:线程池会复用已创建的线程,减少线程创建和销毁的次数。
    • 提高响应速度:任务提交后可以直接从线程池中获取线程执行,减少了线程创建的时间。
    • 提高线程的可管理性:线程池可以对线程进行统一管理,如设置线程的最大数量、队列大小等。
    • 避免资源耗尽:通过限制线程的最大数量,避免系统资源耗尽。
  3. 线程池的主要组成部分是什么?
    • 线程池管理器:负责创建和管理线程池。
    • 工作线程:线程池中实际执行任务的线程。
    • 任务队列:用于存储待执行任务的队列。
    • 任务接口:所有任务必须实现的接口,以便工作线程可以执行。

线程池的实现原理

  1. Java 中的线程池是如何实现的?
    • Java 的线程池主要通过 java.util.concurrent 包中的 Executor 框架实现。
    • Executor 是一个接口,定义了执行任务的方法。
    • ExecutorServiceExecutor 的子接口,提供了更丰富的功能,如线程池的管理。
    • ThreadPoolExecutorExecutorService 的实现类,提供了线程池的核心实现。
  2. ThreadPoolExecutor 的构造参数有哪些?
    • corePoolSize:核心线程数,线程池中始终保持的线程数量。
    • maximumPoolSize:最大线程数,线程池中允许的最大线程数量。
    • keepAliveTime:非核心线程的空闲存活时间。
    • unitkeepAliveTime 的时间单位。
    • workQueue:任务队列,用于存储待执行任务的队列。
    • threadFactory:线程工厂,用于创建线程。
    • handler:拒绝策略,当任务队列满且线程数达到最大值时,如何处理新任务。
  3. 线程池的拒绝策略有哪些?
    • AbortPolicy:直接抛出 RejectedExecutionException
    • CallerRunsPolicy:由调用线程执行任务。
    • DiscardPolicy:直接丢弃任务。
    • DiscardOldestPolicy:丢弃队列中最老的任务,然后尝试提交新任务。

线程池的使用方法

  1. 如何创建一个线程池?

    • 使用 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();
          }
      }
      
  2. 如何关闭线程池?

    • 使用 shutdown() 方法关闭线程池,等待所有任务完成。
    • 使用 shutdownNow() 方法立即关闭线程池,尝试中断正在执行的任务。
  3. 如何提交任务到线程池?

    • 使用 execute(Runnable command) 方法提交任务。
    • 使用 submit(Callable<T> task) 方法提交任务并返回 Future 对象。

线程池的性能优化

  1. 如何优化线程池的性能?
    • 合理设置线程池大小:根据系统的硬件资源和任务类型,合理设置核心线程数和最大线程数。
    • 选择合适的任务队列:根据任务的特点选择合适的任务队列,如 LinkedBlockingQueueArrayBlockingQueue
    • 设置合理的拒绝策略:根据业务需求选择合适的拒绝策略,避免任务丢失。
    • 监控线程池状态:通过 ThreadPoolExecutor 提供的方法监控线程池的状态,如 getActiveCount()getCompletedTaskCount() 等。

线程池的高级特性

  1. 什么是线程池的饱和策略?

    • 当任务队列满且线程数达到最大值时,线程池会采取的策略。可以通过 RejectedExecutionHandler 接口自定义饱和策略。
  2. 如何自定义线程工厂?

    • 实现 ThreadFactory 接口,自定义线程的创建逻辑。

    • 示例:

      import java.util.concurrent.*;
      
      public class CustomThreadFactory implements ThreadFactory {
             
             
          private final String threadNamePrefix;
      
          public CustomThreadFactory(String threadNamePrefix) {
             
             
              this.threadNamePrefix = threadNamePrefix;
          }
      
          @Override
          public 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();
          }
      }
      

线程池的常见问题

  1. 线程池中的线程是如何复用的?
    • 线程池中的线程在执行完一个任务后,会返回线程池,等待下一个任务。如果线程池中的线程数量超过核心线程数且空闲时间超过 keepAliveTime,则会销毁多余的线程。
  2. 线程池中的线程是如何销毁的?
    • 当线程池中的线程数量超过核心线程数且空闲时间超过 keepAliveTime 时,多余的线程会被销毁。
    • 当调用 shutdown() 方法时,线程池会等待所有任务完成后再销毁所有线程。
    • 当调用 shutdownNow() 方法时,线程池会尝试中断正在执行的任务,并立即销毁所有线程。
  3. 线程池中的任务是如何调度的?
    • 线程池中的任务通过任务队列进行调度。任务队列可以是阻塞队列(如 LinkedBlockingQueueArrayBlockingQueue)或非阻塞队列(如 SynchronousQueue)。
    • 线程池会从任务队列中取出任务并分配给空闲的线程执行。

线程池的监控

  1. 如何监控线程池的状态?
    • 使用 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
  • 存储方式:无状态服务端设计

认证流程

sequenceDiagram
    participant Client
    participant Server
    participant Filter
    participant AuthProvider
    
    Client->>Server: 登录请求(username/password)
    Server->>AuthProvider: 验证凭证
    AuthProvider-->>Server: 生成JWT
    Server->>Client: 返回JWT
    Client->>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 {
    @Override
    public 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;
    }

    @Override
    public String ZSQService(String arg0, Strin

网站公告

今日签到

点亮在社区的每一天
去签到