Java架构师100道面试题
Java高级工程师面试题100道(含详细答案)
一、Spring基础框架(20题)
1. Spring框架的核心模块有哪些?它们的作用分别是什么?
答案:
Spring框架由多个核心模块组成,主要分为以下几大类:
-
核心容器(Core Container)
- Spring Core:框架的基础模块,提供IOC容器和依赖注入功能
- Spring Beans:提供BeanFactory,是工厂模式的实现
- Spring Context:构建在Core和Beans模块之上,是配置文件的核心抽象
- Spring Expression Language (SpEL):提供表达式语言,可以在运行时查询和操作对象图
-
数据访问/集成(Data Access/Integration)
- JDBC:抽象了JDBC操作,简化数据库访问
- ORM:支持ORM框架如Hibernate、MyBatis等
- JMS:Java消息服务,支持消息传递
- Transactions:支持编程式和声明式事务管理
-
Web
- Spring Web:提供基础的Web开发功能
- Spring MVC:实现Web层的MVC框架
- Spring WebFlux:响应式Web框架
-
AOP
- Spring AOP:面向切面编程,支持声明式事务、安全等功能
-
测试
- Spring Test:支持JUnit和TestNG进行测试
-
其他
- Spring Security:安全框架
- Spring Boot:快速开发框架
- Spring Cloud:微服务解决方案
2. 详细解释Spring IOC容器的原理
答案:
IOC(Inversion of Control,控制反转) 是Spring框架的核心概念之一。
原理:
-
什么是IOC
- 传统开发:对象A需要对象B,由A自己创建B
- IOC:对象A需要对象B,由Spring容器创建并注入给A
- 控制反转:将对象的创建权交给容器,而不是在代码中new
-
IOC容器
- BeanFactory:最基础的IOC容器,延迟加载Bean
- ApplicationContext:BeanFactory的子接口,功能更强大,启动时立即创建Bean
-
Bean的生命周期
实例化Bean → 属性填充 → 初始化 → 使用Bean → 销毁Bean详细过程:
- 实例化:通过构造函数或工厂方法创建Bean实例
- 属性填充:将Bean依赖的属性注入(@Autowired、setter注入等)
- 初始化:
- 如果Bean实现了BeanNameAware,调用setBeanName()
- 如果Bean实现了BeanFactoryAware,调用setBeanFactory()
- 调用BeanPostProcessor的postProcessBeforeInitialization()
- 调用init-method方法或@PostConstruct注解方法
- 调用BeanPostProcessor的postProcessAfterInitialization()
- 使用Bean:Bean可以正常使用
- 销毁Bean:
- 调用destroy-method方法或@PreDestroy注解方法
- 如果Bean实现了DisposableBean,调用destroy()
-
循环依赖解决
- Spring通过三级缓存解决循环依赖
- singletonObjects:存储完全初始化的Bean
- earlySingletonObjects:存储原始Bean实例(未完成初始化)
- singletonFactories:存储Bean工厂,用于获取早期引用
- 当A依赖B、B依赖A时:
- 实例化A,将A的工厂放入singletonFactories
- 填充A的属性,发现需要B
- 实例化B,填充B的属性,发现需要A
- 从singletonFactories获取A的早期引用(未初始化)
- 完成B的初始化,放回singletonObjects
- 完成A的初始化
3. Spring Bean的作用域有哪些?
答案:
Spring Bean有以下几种作用域:
- singleton(单例):默认作用域,Spring容器中只有一个Bean实例,所有请求共享
- prototype(原型):每次请求都创建一个新的Bean实例
- request:每个HTTP请求创建一个Bean实例,仅适用于Web环境
- session:每个HTTP Session创建一个Bean实例,仅适用于Web环境
- application:每个ServletContext创建一个Bean实例,仅适用于Web环境
- websocket:每个WebSocket会话创建一个Bean实例,仅适用于Web环境
使用示例:
@Component
@Scope("prototype")
public class MyBean {
// 每次请求创建新实例
}
4. Spring中依赖注入的几种方式
答案:
Spring支持多种依赖注入方式:
-
构造器注入
@Component public class UserService { private final UserRepository repository; @Autowired public UserService(UserRepository repository) { this.repository = repository; } }- 优点:保证依赖不可变,适合必填依赖
- 推荐:优先使用构造器注入
-
Setter注入
@Component public class UserService { @Autowired private UserRepository repository; @Autowired public void setRepository(UserRepository repository) { this.repository = repository; } }- 优点:可选依赖,支持Bean的重新注入
- 适用:可选依赖或需要重新注入的场景
-
字段注入
@Component public class UserService { @Autowired private UserRepository repository; }- 优点:简洁,代码量少
- 缺点:不直观,难以测试,不利于不可变性
-
方法注入
@Component public class UserService { @Autowired public void init(UserRepository repository) { // 初始化逻辑 } } -
通过XML配置注入
<bean id="userService" class="com.example.UserService"> <property name="repository" ref="userRepository"/> </bean>
最佳实践:
- 优先使用构造器注入(确保依赖不可变)
- 可选依赖使用Setter注入
- 不推荐使用字段注入(不利于测试和维护)
5. Spring AOP的原理和应用场景
答案:
AOP(Aspect-Oriented Programming,面向切面编程) 是将横切关注点从业务逻辑中分离出来的技术。
原理:
-
动态代理
- Spring AOP默认使用JDK动态代理(针对接口)
- 如果没有接口,使用CGLIB(继承类)
- 可以通过配置强制使用CGLIB
-
核心概念
- Aspect(切面):横切关注点的模块化,如日志、事务
- Join Point(连接点):程序执行的某个特定位置,如方法调用、异常处理
- Pointcut(切入点):匹配连接点的表达式,决定切面在哪些地方执行
- Advice(通知):切面在特定连接点执行的动作
- Weaving(织入):将切面应用到目标对象的过程
-
通知类型
- @Before:前置通知,在方法执行前执行
- @After:后置通知,在方法执行后执行
- @AfterReturning:返回通知,在方法成功返回后执行
- @AfterThrowing:异常通知,在方法抛出异常后执行
- @Around:环绕通知,包裹方法执行,可以决定是否执行方法
-
应用场景
@Aspect @Component public class LogAspect { @Pointcut("execution(* com.example.service.*.*(..))") public void serviceMethod() {} @Before("serviceMethod()") public void logBefore(JoinPoint joinPoint) { System.out.println("方法执行前:" + joinPoint.getSignature().getName()); } @Around("serviceMethod()") public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable { long startTime = System.currentTimeMillis(); Object result = joinPoint.proceed(); long endTime = System.currentTimeMillis(); System.out.println("执行时间:" + (endTime - startTime) + "ms"); return result; } }
典型应用:
- 日志记录
- 事务管理
- 权限校验
- 性能监控
- 异常处理
6. Spring事务管理的原理
答案:
Spring事务管理 的核心是声明式事务,通过AOP实现。
原理:
-
事务传播行为(Propagation)
- REQUIRED(默认):如果当前有事务,则加入;否则创建新事务
- REQUIRES_NEW:创建新事务,挂起当前事务
- SUPPORTS:如果当前有事务,则加入;否则非事务执行
- NOT_SUPPORTED:非事务执行,挂起当前事务
- MANDATORY:必须在事务中执行,否则抛异常
- NEVER:必须非事务执行,否则抛异常
- NESTED:如果当前有事务,则在嵌套事务中执行
-
事务隔离级别(Isolation)
- DEFAULT:使用数据库默认隔离级别
- READ_UNCOMMITTED:可以读取未提交的数据(脏读)
- READ_COMMITTED:只能读取已提交的数据(避免脏读)
- REPEATABLE_READ:可重复读(避免脏读和不可重复读)
- SERIALIZABLE:串行化(最安全,性能最低)
-
事务注解
@Service public class UserService { @Transactional( propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class, timeout = 30 ) public void transferMoney(Long fromId, Long toId, BigDecimal amount) { // 转账逻辑 } } -
原理实现
- Spring通过动态代理实现事务管理
- 使用TransactionInterceptor作为通知
- PlatformTransactionManager是事务管理器接口
- 事务在方法调用前开始,方法正常返回后提交,异常时回滚
-
注意事项
- @Transactional只能作用于public方法
- 同一类中方法调用不会触发事务(self-invocation问题)
- 异常被捕获后不会触发回滚
- 建议指定rollbackFor以避免受检异常不回滚的问题
7. Spring MVC的工作流程
答案:
Spring MVC是一个基于请求的Web框架,工作流程如下:
- 客户端发送请求到DispatcherServlet(前端控制器)
- DispatcherServlet查询HandlerMapping,找到处理该请求的Controller
- HandlerMapping返回处理器执行链(包括Controller和拦截器)
- DispatcherServlet调用HandlerAdapter执行Controller
- Controller执行业务逻辑,返回ModelAndView
- DispatcherServlet将ModelAndView传递给ViewResolver
- ViewResolver解析视图,返回具体的View对象
- DispatcherServlet使用Model填充View,渲染页面
- DispatcherServlet将响应返回给客户端
核心组件:
| 组件 | 作用 |
|---|---|
| DispatcherServlet | 前端控制器,协调各组件 |
| HandlerMapping | 映射请求到处理器 |
| HandlerAdapter | 适配不同类型的处理器 |
| Controller | 处理请求,返回ModelAndView |
| ViewResolver | 解析视图名称到具体视图 |
| View | 渲染视图,生成响应 |
| Interceptor | 拦截器,处理预处理和后处理 |
示例:
@Controller
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/user/{id}")
public String getUser(@PathVariable Long id, Model model) {
User user = userService.getUserById(id);
model.addAttribute("user", user);
return "user/detail"; // ViewResolver会解析为/user/detail.jsp
}
}
8. Spring Boot自动配置原理
答案:
Spring Boot自动配置 是Spring Boot的核心特性,根据classpath上的依赖自动配置Spring应用。
原理:
-
@SpringBootApplication注解
@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }该注解是三个注解的组合:
@SpringBootConfiguration:标识为配置类@EnableAutoConfiguration:启用自动配置@ComponentScan:组件扫描
-
@EnableAutoConfiguration
- 通过
@Import(AutoConfigurationImportSelector.class)导入自动配置类 - AutoConfigurationImportSelector读取
META-INF/spring.factories文件 - 加载
EnableAutoConfiguration对应的所有配置类
- 通过
-
条件注解
@ConditionalOnClass:classpath上有该类时才生效@ConditionalOnMissingBean:容器中不存在该Bean时才生效@ConditionalOnProperty:配置属性满足条件时才生效@ConditionalOnWebApplication:Web应用时才生效
-
自动配置示例
@Configuration @ConditionalOnClass({DataSource.class, JdbcTemplate.class}) @AutoConfigureAfter(DataSourceAutoConfiguration.class) public class JdbcTemplateAutoConfiguration { @Bean @ConditionalOnMissingBean public JdbcTemplate jdbcTemplate(DataSource dataSource) { return new JdbcTemplate(dataSource); } } -
工作原理流程
启动Spring Boot → 读取@SpringBootApplication → 执行@EnableAutoConfiguration → 加载spring.factories → 筛选条件满足的配置类 → 注册Bean到容器 → 完成自动配置
9. Spring Boot常见的Starter有哪些?
答案:
Spring Boot提供了大量Starter,简化依赖管理:
Web开发:
spring-boot-starter-web:Web开发,包含Spring MVC、Tomcatspring-boot-starter-webflux:响应式Web开发
数据访问:
spring-boot-starter-data-jpa:JPA数据访问spring-boot-starter-jdbc:JDBC数据访问spring-boot-starter-data-redis:Redis数据访问spring-boot-starter-data-mongodb:MongoDB数据访问
消息队列:
spring-boot-starter-amqp:RabbitMQspring-boot-starter-activemq:ActiveMQ
安全:
spring-boot-starter-security:Spring Security
测试:
spring-boot-starter-test:测试支持,包含JUnit、Mockito等
工具:
spring-boot-starter-aop:AOP支持spring-boot-starter-cache:缓存支持spring-boot-starter-validation:参数校验
10. Spring中如何自定义Starter?
答案:
-
创建Spring Boot Starter项目
- 命名为:
my-starter
- 命名为:
-
创建自动配置类
@Configuration @ConditionalOnClass(MyService.class) @EnableConfigurationProperties(MyProperties.class) public class MyAutoConfiguration { @Bean @ConditionalOnMissingBean public MyService myService(MyProperties properties) { return new MyService(properties); } } -
创建属性配置类
@ConfigurationProperties(prefix = "my") public class MyProperties { private String name = "default"; private int timeout = 3000; // getter/setter } -
配置spring.factories
在META-INF/spring.factories文件中添加:org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.example.MyAutoConfiguration -
使用
在其他项目中引入依赖:<dependency> <groupId>com.example</groupId> <artifactId>my-starter</artifactId> <version>1.0.0</version> </dependency>
11. Spring中的BeanFactory和ApplicationContext有什么区别?
答案:
| 特性 | BeanFactory | ApplicationContext |
|---|---|---|
| 延迟加载 | 默认延迟加载 | 默认启动时加载所有Bean |
| 功能 | 基础IOC容器 | 功能更丰富 |
| AOP支持 | 需要手动配置 | 自动支持 |
| 事件发布 | 不支持 | 支持 |
| 国际化 | 不支持 | 支持 |
| 注解支持 | 需要额外配置 | 自动支持 |
使用建议:
- 大多数场景使用ApplicationContext
- 只有在资源受限的环境下考虑BeanFactory
12. Spring中如何解决循环依赖问题?
答案:
循环依赖是指Bean A依赖Bean B,Bean B又依赖Bean A的情况。
解决方式:
-
三级缓存机制
Spring通过三级缓存解决循环依赖:- singletonObjects:存储完全初始化的Bean
- earlySingletonObjects:存储早期Bean引用(未完成初始化)
- singletonFactories:存储Bean工厂,用于创建早期引用
-
解决流程
创建A → 发现需要B → 创建B → 发现需要A → 从singletonFactories获取A的早期引用 → 完成B → 完成A -
局限性
- 只解决单例、构造器注入的循环依赖
- 原型Bean无法解决循环依赖
- 构造器注入的多例Bean也无法解决
-
解决方案
- 使用
@Lazy注解延迟加载 - 改用Setter注入
- 重构代码,打破循环依赖
- 使用
13. Spring中如何实现插件机制?
答案:
Spring的插件机制基于BeanPostProcessor和注解实现。
-
BeanPostProcessor
@Component public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) { // 初始化前处理 return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) { // 初始化后处理 return bean; } } -
BeanFactoryPostProcessor
@Component public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { // 在Bean实例化前修改Bean定义 } } -
自定义注解
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface EnableMyPlugin { } @Import(MyPluginRegistrar.class) @Retention(RetentionPolicy.RUNTIME) public @interface EnableMyPlugin { }
14. Spring中如何优化启动速度?
答案:
-
延迟加载
@Lazy @Component public class MyService {} -
排除不需要的自动配置
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) public class Application {} -
使用Spring Boot DevTools
- 热部署,提高开发效率
-
减少组件扫描范围
@ComponentScan(basePackages = "com.example") -
禁用不需要的AutoConfiguration
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
15. Spring中如何自定义注解?
答案:
-
定义注解
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyAnnotation { String value() default ""; int timeout() default 30; } -
使用注解
@MyAnnotation(value = "test", timeout = 60) public void testMethod() {} -
处理注解
@Aspect @Component public class MyAspect { @Around("@annotation(myAnnotation)") public Object around(ProceedingJoinPoint joinPoint, MyAnnotation myAnnotation) throws Throwable { // 处理注解逻辑 return joinPoint.proceed(); } }
16. Spring中如何实现懒加载?
答案:
-
类级别懒加载
@Lazy @Component public class MyService {} -
Bean级别懒加载
@Bean @Lazy public MyService myService() { return new MyService(); } -
依赖懒加载
@Autowired @Lazy private MyService myService; -
全局懒加载
spring.main.lazy-initialization=true
17. Spring中如何管理多数据源?
答案:
-
配置多数据源
spring: datasource: primary: url: jdbc:mysql://localhost:3306/db1 username: root password: 123456 secondary: url: jdbc:mysql://localhost:3306/db2 username: root password: 123456 -
配置多数据源Bean
@Configuration public class DataSourceConfig { @Primary @Bean(name = "primaryDataSource") @ConfigurationProperties("spring.datasource.primary") public DataSource primaryDataSource() { return DataSourceBuilder.create().build(); } @Bean(name = "secondaryDataSource") @ConfigurationProperties("spring.datasource.secondary") public DataSource secondaryDataSource() { return DataSourceBuilder.create().build(); } } -
配置多个SqlSessionFactory
@Configuration public class MybatisConfig { @Primary @Bean public SqlSessionFactory primarySqlSessionFactory( @Qualifier("primaryDataSource") DataSource dataSource) throws Exception { SqlSessionFactoryBean factory = new SqlSessionFactoryBean(); factory.setDataSource(dataSource); return factory.getObject(); } @Bean public SqlSessionFactory secondarySqlSessionFactory( @Qualifier("secondaryDataSource") DataSource dataSource) throws Exception { SqlSessionFactoryBean factory = new SqlSessionFactoryBean; factory.setDataSource(dataSource); return factory.getObject(); } }
18. Spring中如何处理并发问题?
答案:
-
线程安全的Bean
- 尽量使用无状态Bean
- 避免使用实例变量
-
使用@Scope("prototype")
@Component @Scope("prototype") public class MyService {} -
使用ThreadLocal
public class UserContext { private static final ThreadLocal<String> USER = new ThreadLocal<>(); public static void set(String user) { USER.set(user); } public static String get() { return USER.get(); } public static void clear() { USER.remove(); } } -
使用并发工具类
- ConcurrentHashMap
- Atomic类
- CountDownLatch
- CyclicBarrier
19. Spring中如何进行性能监控?
答案:
-
Spring Boot Actuator
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>management: endpoints: web: exposure: include: health,info,metrics,threaddump,heapdump -
Micrometer
@Component public class MetricsConfig { private final MeterRegistry registry; public MetricsConfig(MeterRegistry registry) { this.registry = registry; } public void measureExecutionTime(String name, Runnable action) { Timer timer = Timer.builder(name) .description("Execution time") .register(registry); timer.record(action); } } -
Spring Boot Admin
- 可视化的监控面板
- 日志管理
- 性能监控
20. Spring中如何处理异常?
答案:
-
@ExceptionHandler
@RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(ResourceNotFoundException.class) public ResponseEntity<ErrorResponse> handleNotFound(ResourceNotFoundException ex) { return ResponseEntity.status(HttpStatus.NOT_FOUND) .body(new ErrorResponse(ex.getMessage())); } @ExceptionHandler(Exception.class) public ResponseEntity<ErrorResponse> handleException(Exception ex) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body(new ErrorResponse("系统异常")); } } -
自定义异常
public class BusinessException extends RuntimeException { private Integer code; private String message; public BusinessException(Integer code, String message) { super(message); this.code = code; this.message = message; } } -
使用@ResponseStatus
@ResponseStatus(HttpStatus.NOT_FOUND) public class ResourceNotFoundException extends RuntimeException {}
二、分布式系统(20题)
21. 什么是CAP定理?
答案:
CAP定理由Eric Brewer提出,指在分布式系统中,Consistency(一致性)、Availability(可用性)、Partition Tolerance(分区容错性)三者不可兼得。
-
Consistency(一致性)
- 所有节点在同一时刻看到的数据是一致的
- 数据更新后,所有读都能读到最新值
-
Availability(可用性)
- 每个请求都能在合理时间内收到响应
- 不保证响应是最新数据
-
Partition Tolerance(分区容错性)
- 系统在遇到网络分区时仍能继续工作
- 网络分区是分布式系统的常态
选择:
- CP:一致性和分区容错性(如HBase、Zookeeper)
- AP:可用性和分区容错性(如Cassandra、Dynamo)
- CA:一致性和可用性(单机系统,分布式中不存在)
22. 什么是BASE理论?
答案:
BASE理论是对CAP中可用性和一致性的权衡,是NoSQL数据库的设计原则。
-
Basic Availability(基本可用)
- 分布式系统在出现不可预测故障时,保证核心功能可用
- 允许损失部分可用性(如响应时间变长、功能降级)
-
Soft State(软状态)
- 允许系统存在中间状态
- 中间状态不影响系统整体可用性
-
Eventual Consistency(最终一致性)
- 系统在经过一段时间的同步后,数据最终会达到一致状态
- 不要求实时一致性
与CAP的关系:
- BASE是CAP的AP方案的延伸
- 强调在分布式系统中,可用性和分区容错性比强一致性更重要
23. 分布式锁的实现方案有哪些?
答案:
-
基于数据库
-- 唯一索引实现 INSERT IGNORE INTO lock_table (lock_name, create_time) VALUES ('order_lock', NOW()); -- 版本控制实现 UPDATE lock_table SET version = version + 1 WHERE lock_name = 'order_lock' AND version = 1;- 优点:简单,易于理解
- 缺点:性能差,存在单点问题
-
基于Zookeeper
// 创建临时顺序节点 String path = zooKeeper.create("/locks/order_lock", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); // 监听前一个节点 Stat stat = zooKeeper.exists(path.substring(0, path.lastIndexOf("/")) + path.substring(path.lastIndexOf("/") + 1).prev(), true);- 优点:强一致性,支持可重入
- 缺点:依赖Zookeeper集群,复杂度较高
-
基于Redis
// SET命令设置锁,NX表示不存在才设置,EX表示过期时间 String result = jedis.set("lock", "1", "NX", "EX", 10); if ("OK".equals(result)) { try { // 业务逻辑 } finally { // 删除锁(使用Lua脚本保证原子性) jedis.eval("if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end", Collections.singletonList("lock"), Collections.singletonList("1")); } }- 优点:性能好,实现简单
- 缺点:需要处理锁过期问题
-
基于Redisson
RLock lock = redisson.getLock("order_lock"); lock.lock(); try { // 业务逻辑 } finally { lock.unlock(); }- 支持看门狗机制,自动续期
- 支持可重入锁、公平锁、读写锁
24. 分布式事务有哪些解决方案?
答案:
-
2PC(两阶段提交)
- 准备阶段:事务参与者准备执行,但不提交
- 提交阶段:协调者决定是否提交
- 优点:强一致性
- 缺点:性能差,阻塞式事务,单点问题
-
TCC(尝试-确认-取消)
- Try:尝试执行,预留资源
- Confirm:确认执行,提交资源
- Cancel:取消执行,释放资源
- 优点:性能好,非阻塞
- 缺点:代码侵入性强,需要实现三个接口
-
消息最终一致性
发送方 → 本地事务 → 发送消息 → MQ → 接收方 → 本地事务- 优点:性能好,解耦
- 缺点:最终一致性,需要处理重复消费
-
Seata
- 提供AT、TCC、Saga等多种模式
- 支持多种事务场景
- 易于集成
25. 什么是分布式ID生成方案?
答案:
-
数据库自增ID
CREATE TABLE id_generator ( id BIGINT NOT NULL, value BIGINT NOT NULL, PRIMARY KEY (id) );- 优点:简单
- 缺点:单点,扩展性差
-
UUID
String id = UUID.randomUUID().toString().replace("-", "");- 优点:简单,全局唯一
- 缺点:无序,存储成本高,不适合数据库索引
-
Snowflake(雪花算法)
public class SnowflakeIdGenerator { private long workerId; private long datacenterId; private long sequence = 0L; private long lastTimestamp = -1L; public synchronized long nextId() { long timestamp = System.currentTimeMillis(); if (timestamp < lastTimestamp) { throw new RuntimeException("时钟回拨"); } if (timestamp == lastTimestamp) { sequence = (sequence + 1) & 4095; if (sequence == 0) { timestamp = waitNextMillis(timestamp); } } else { sequence = 0L; } lastTimestamp = timestamp; return ((timestamp - START_EPOCH) << 22) | (datacenterId << 17) | (workerId << 12) | sequence; } }- 结构:1位符号位 + 41位时间戳 + 5位数据中心 + 5位机器ID + 12位序列号
- 优点:趋势递增,高性能,无中心节点
- 缺点:依赖系统时钟,时钟回拨需要处理
-
号段模式
- 从数据库批量获取ID段
- 优点:性能好,可扩展
- 缺点:ID不连续
26. 什么是分布式会话方案?
答案:
-
Session共享
- 将Session存储到Redis
- 所有节点从Redis读取Session
-
Token机制
// 使用JWT生成Token String token = Jwts.builder() .setSubject(userId.toString()) .setExpiration(new Date(System.currentTimeMillis() + 3600000)) .signWith(SignatureAlgorithm.HS256, secret) .compact();- 优点:无状态,易于扩展
- 缺点:Token无法主动失效
-
Spring Session
@Configuration @EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1800) public class SessionConfig { }
27. 什么是分布式缓存?有哪些解决方案?
答案:
-
Redis
- 支持多种数据结构
- 持久化机制
- 集群模式
- 常用命令:GET、SET、EXPIRE、HGET、HSET等
-
Memcached
- 简单的KV存储
- 多线程处理
- 不支持持久化
-
本地缓存
// Caffeine Cache<String, Object> cache = Caffeine.newBuilder() .maximumSize(1000) .expireAfterWrite(10, TimeUnit.MINUTES) .build(); -
多级缓存
- L1:本地缓存(Caffeine)
- L2:分布式缓存(Redis)
28. 什么是分布式服务治理?
答案:
-
服务注册与发现
- Nacos:阿里巴巴开源,支持动态配置和服务发现
- Eureka:Netflix开源,AP模型
- Consul:HashiCorp开源,CP模型
- Zookeeper:CP模型
-
负载均衡
- 轮询
- 随机
- 加权
- 最小连接数
-
服务熔断与降级
- 熔断:当错误率达到阈值时,自动熔断,快速失败
- 降级:当服务不可用时,返回默认值或缓存数据
-
限流
- 令牌桶算法
- 漏桶算法
- 滑动窗口
29. 什么是RPC?有哪些实现?
答案:
RPC(Remote Procedure Call,远程过程调用) 是分布式系统的基本通信方式。
-
gRPC
- 基于HTTP/2和Protocol Buffers
- 高性能,支持多语言
- 双向流式通信
-
Dubbo
- 阿里巴巴开源,Java语言
- 支持多种协议:Dubbo、RMI、HTTP
- 支持多种序列化:Hessian、JSON、Kryo
-
Thrift
- Facebook开源
- 支持多种语言
- 多种传输协议
-
Spring Cloud OpenFeign
- 声明式HTTP客户端
- 与Spring Cloud无缝集成
30. 什么是服务网格(Service Mesh)?
答案:
Service Mesh 是一种解决微服务通信的基础设施层。
-
核心概念
- Sidecar:代理容器,与业务容器部署在同一Pod中
- 数据平面:负责实际的数据转发
- 控制平面:负责配置下发和管理
-
主流实现
- Istio:Google、IBM、 Lyft联合开源
- Linkerd:Buoyant开源
- Envoy:Lyft开源,底层代理
-
优势
- 业务代码无侵入
- 统一的服务治理能力
- 可观测性
31. 什么是微服务架构?有哪些优缺点?
答案:
微服务架构是一种将单一应用划分为一组小服务的方法。
-
特点
- 服务粒度小
- 独立部署
- 去中心化
- 容错性好
-
优点
- 技术栈灵活
- 易于扩展
- 独立部署
- 故障隔离
-
缺点
- 运维复杂
- 分布式事务
- 服务治理
- 测试困难
32. 什么是Docker容器技术?
答案:
Docker 是一个开源的应用容器引擎。
-
核心概念
- 镜像(Image):只读模板
- 容器(Container):镜像的运行实例
- 仓库(Registry):镜像存储仓库
-
常用命令
# 拉取镜像 docker pull nginx # 运行容器 docker run -d -p 80:80 nginx # 查看容器 docker ps -a # 进入容器 docker exec -it container_id bash -
Dockerfile
FROM openjdk:11-jre COPY target/app.jar app.jar EXPOSE 8080 ENTRYPOINT ["java", "-jar", "/app.jar"]
33. 什么是Kubernetes(K8s)?
答案:
Kubernetes 是一个容器编排平台。
-
核心概念
- Pod:最小部署单元
- Service:服务暴露
- Deployment:无状态应用部署
- StatefulSet:有状态应用部署
- ConfigMap:配置管理
- Secret:密钥管理
-
常用命令
# 查看Pod kubectl get pods # 查看Service kubectl get services # 部署应用 kubectl apply -f deployment.yaml
34. 什么是CI/CD?
答案:
CI/CD 是持续集成和持续部署。
-
CI(持续集成)
- 频繁合并代码到主干
- 自动化构建和测试
- 快速发现问题
-
CD(持续部署/交付)
- 自动化部署到生产环境
- 减少人工操作
- 提高发布效率
-
常用工具
- Jenkins
- GitLab CI
- GitHub Actions
- CircleCI
35. 什么是链路追踪?
答案:
链路追踪用于追踪请求在分布式系统中的调用链。
-
核心概念
- Trace ID:一次请求的唯一标识
- Span ID:一次调用的唯一标识
- Parent Span ID:父调用的ID
-
常用工具
- Jaeger:Uber开源
- Zipkin:Twitter开源
- SkyWalking:Apache开源
36. 什么是分布式消息队列?有哪些方案?
答案:
-
Kafka
- 高吞吐,持久化
- 适合日志收集、流处理
-
RocketMQ
- 阿里开源,支持事务消息
- 适合交易订单、消息堆积
-
RabbitMQ
- 灵活的路由机制
- 适合企业级应用
-
ActiveMQ
- 老牌MQ
- 功能丰富,但性能一般
37. 什么是分布式日志系统?
答案:
-
ELK Stack
- Elasticsearch:搜索引擎
- Logstash:日志收集和处理
- Kibana:日志可视化
-
EFK Stack
- 将Logstash替换为Fluentd
-
架构
应用 → Logback/Log4j → Filebeat/Fluentd → Kafka → Logstash → Elasticsearch → Kibana
38. 什么是分布式配置中心?
答案:
-
Spring Cloud Config
- 基于Git存储配置
- 支持配置版本管理
- 配置热更新
-
Nacos
- 阿里巴巴开源
- 支持动态配置和服务发现
- 简单易用
-
Apollo
- 携程开源
- 配置热更新
- 支持权限管理
39. 什么是分布式搜索?
答案:
-
Elasticsearch
- 基于Lucene
- 分布式搜索引擎
- 支持全文检索、聚合分析
-
Solr
- Apache开源
- 基于Lucene
- 企业级搜索引擎
40. 什么是分布式协调服务?
答案:
-
Zookeeper
- 分布式协调服务
- 提供配置管理、命名服务、分布式锁
- 基于ZAB协议
-
Consul
- HashiCorp开源
- 支持多数据中心
- 提供健康检查
-
etcd
- CoreOS开源
- K8s默认使用
- 基于Raft协议
三、高并发(20题)
41. JVM内存模型是怎样的?
答案:
JVM内存模型分为以下几个区域:
-
堆内存(Heap)
- 所有线程共享
- 存储对象实例
- 分为新生代和老年代
- 新生代:Eden + Two Survivor + Survivor
- 老年代:长期存活的对象
-
方法区(Method Area)
- 存储类信息、常量、静态变量
- JDK 8后称为元空间(Metaspace)
- 使用本地内存
-
虚拟机栈(Java Stack)
- 线程私有
- 存储方法调用的栈帧
- 每个方法对应一个栈帧
-
本地方法栈(Native Method Stack)
- 线程私有
- 为Native方法服务
-
程序计数器(Program Counter Register)
- 线程私有
- 记录当前执行的字节码指令地址
42. JVM垃圾回收算法有哪些?
答案:
-
标记-清除(Mark-Sweep)
- 标记所有需要回收的对象
- 统一清除
- 缺点:产生内存碎片
-
标记-复制(Mark-Copy)
- 将内存分为两半
- 每次只使用一半
- 存活对象复制到另一半
- 缺点:内存利用率低
-
标记-整理(Mark-Compact)
- 标记存活对象
- 整理到内存一端
- 直接清理边界外的内存
- 优点:无碎片
-
分代收集算法
- 新生代:使用复制算法
- 老年代:使用标记-清除或标记-整理
43. GC Roots有哪些?
答案:
GC Roots 是判断对象是否存活的起点:
-
虚拟机栈中引用的对象
- 局部变量表中的对象引用
-
方法区中类静态属性引用的对象
- static修饰的属性
-
方法区中常量引用的对象
- final修饰的常量
-
本地方法栈中JNI引用的对象
- Native方法引用的对象
44. 常见的垃圾收集器有哪些?
答案:
-
Serial Collector
- 单线程收集器
- 适合客户端模式
-
Parallel Scavenge
- 多线程收集器
- 关注吞吐量
-
Serial Old
- 单线程收集器
- 老年代收集器
-
Parallel Old
- 多线程收集器
- 老年代收集器
-
CMS(Concurrent Mark Sweep)
- 并发收集器
- 关注响应时间
- 缺点:产生碎片
-
G1
- 分区收集器
- 平衡吞吐量和响应时间
- JDK 9后成为默认收集器
-
ZGC
- 低延迟收集器
- pauses < 10ms
- JDK 11引入,JDK 15成为候选特性
45. 什么是多线程?如何创建线程?
答案:
-
继承Thread类
public class MyThread extends Thread { @Override public void run() { // 业务逻辑 } } -
实现Runnable接口
public class MyRunnable implements Runnable { @Override public void run() { // 业务逻辑 } } // 使用 new Thread(new MyRunnable()).start(); -
实现Callable接口
public class MyCallable implements Callable<String> { @Override public String call() throws Exception { return "result"; } } // 使用 FutureTask<String> futureTask = new FutureTask<>(new MyCallable()); new Thread(futureTask).start(); String result = futureTask.get(); -
使用线程池
ExecutorService executor = Executors.newFixedThreadPool(10); executor.submit(new MyRunnable());
46. 线程池的核心参数有哪些?
答案:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
- corePoolSize:核心线程数
- maximumPoolSize:最大线程数
- keepAliveTime:空闲线程存活时间
- unit:时间单位
- workQueue:任务队列
- ArrayBlockingQueue
- LinkedBlockingQueue
- SynchronousQueue
- PriorityBlockingQueue
- threadFactory:线程工厂
- handler:拒绝策略
- AbortPolicy:抛出异常
- CallerRunsPolicy:由调用者执行
- DiscardPolicy:丢弃任务
- DiscardOldestPolicy:丢弃最老的任务
47. 线程池的执行流程是什么?
答案:
1. 提交任务
2. 检查核心线程数
- 未达核心线程数:创建新线程执行
- 达到核心线程数:进入步骤3
3. 检查任务队列
- 队列未满:放入队列等待
- 队列已满:进入步骤4
4. 检查最大线程数
- 未达最大线程数:创建新线程执行
- 达到最大线程数:执行拒绝策略
48. 什么是volatile关键字?
答案:
volatile 是Java提供的轻量级同步机制。
-
保证可见性
- 一个线程修改了变量,其他线程立即可见
-
保证有序性
- 禁止指令重排序
-
不保证原子性
- i++ 不是原子操作
-
使用场景
// 单例模式(双重检查锁) public class Singleton { private static volatile Singleton instance; public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } } // 状态标志 private volatile boolean running = true;
49. 什么是synchronized关键字?
答案:
synchronized 是Java提供的同步机制。
-
修饰实例方法
- 锁当前对象实例
public synchronized void method() {} -
修饰静态方法
- 锁Class对象
public static synchronized void method() {} -
修饰代码块
- 锁指定对象
public void method() { synchronized (this) { // 业务逻辑 } } -
实现原理
- 对象头中的Mark Word
- 偏向锁 → 轻量级锁 → 重量级锁
-
锁升级过程
- 无锁状态
- 偏向锁:只有一个线程访问
- 轻量级锁:多线程竞争
- 重量级锁:竞争激烈,申请系统锁
50. ReentrantLock和synchronized有什么区别?
答案:
| 特性 | synchronized | ReentrantLock |
|---|---|---|
| 层面 | JVM层面 | API层面 |
| 锁释放 | 自动释放 | 需要手动释放 |
| 锁获取 | 无法中断 | 可中断获取 |
| 公平锁 | 非公平 | 可配置 |
| 条件变量 | 不支持 | 支持 |
| 性能 | JDK 6后优化,性能接近 | 略好 |
使用建议:
- 简单场景使用synchronized
- 需要高级功能使用ReentrantLock
51. 什么是CAS?有什么缺点?
答案:
CAS(Compare-And-Swap) 是一种无锁并发算法。
-
原理
- 比较并交换
- 有三个值:内存值V、旧预期值E、新值N
- 只有当V==E时,才将V改为N
-
Java实现
AtomicInteger atomicInteger = new AtomicInteger(0); atomicInteger.incrementAndGet(); // CAS操作 -
缺点
- ABA问题:值从A→B→A,CAS认为没有变化
- 自旋开销:长时间自旋消耗CPU
- 只能保证一个共享变量的原子性
52. ABA问题如何解决?
答案:
ABA问题是指值从A变为B再变回A,CAS无法感知。
解决方案:
-
使用AtomicStampedReference
AtomicStampedReference<Integer> reference = new AtomicStampedReference<>(1, 1); // 带版本号的CAS操作 Integer[] stamp = {1}; reference.compareAndSet(1, 2, stamp[0], stamp[0] + 1); -
使用版本号
- 每次修改增加版本号
- CAS时检查版本号
53. 什么是并发容器?
答案:
Java提供了一些线程安全的容器:
-
Vector
- 线程安全的List
- 方法使用synchronized修饰
-
Hashtable
- 线程安全的Map
- 不允许null键值
-
ConcurrentHashMap
- JDK 7:分段锁
- JDK 8:CAS + synchronized
-
CopyOnWriteArrayList
- 写时复制
- 适合读多写少的场景
-
BlockingQueue
- 阻塞队列
- ArrayBlockingQueue
- LinkedBlockingQueue
54. 什么是阻塞队列?有哪些实现?
答案:
BlockingQueue 是支持两个附加操作的队列:
- 阻塞获取:队列为空时,获取操作阻塞
- 阻塞插入:队列满时,插入操作阻塞
实现:
-
ArrayBlockingQueue
- 数组实现
- 有界队列
- 公平锁
-
LinkedBlockingQueue
- 链表实现
- 默认无界(Integer.MAX_VALUE)
- 两把锁(读写分离)
-
PriorityBlockingQueue
- 优先级队列
- 无界队列
-
SynchronousQueue
- 不存储元素
- 每次插入必须等待取出
55. 什么是ThreadLocal?如何使用?
答案:
ThreadLocal 提供线程局部变量。
-
使用示例
public class UserContext { private static final ThreadLocal<User> USER_THREAD_LOCAL = new ThreadLocal<>(); public static void set(User user) { USER_THREAD_LOCAL.set(user); } public static User get() { return USER_THREAD_LOCAL.get(); } public static void remove() { USER_THREAD_LOCAL.remove(); } } -
应用场景
- 用户会话管理
- 事务管理
- 数据库连接管理
-
内存泄漏问题
- ThreadLocalMap的key是弱引用
- 应该在使用后调用remove()
56. 什么是信号量?如何使用?
答案:
Semaphore 控制同时访问的线程数量。
Semaphore semaphore = new Semaphore(5); // 5个许可
// 获取许可
semaphore.acquire();
try {
// 业务逻辑
} finally {
// 释放许可
semaphore.release();
}
使用场景:
- 限流
- 资源池管理
57. 什么是CountDownLatch?如何使用?
答案:
CountDownLatch 允许一个或多个线程等待其他线程完成操作。
CountDownLatch latch = new CountDownLatch(3); // 需要等待3个线程
// 线程1、2、3执行
new Thread(() -> {
// 业务逻辑
latch.countDown(); // 计数减1
}).start();
// 主线程等待
latch.await(); // 阻塞直到计数为0
58. 什么是CyclicBarrier?如何使用?
答案:
CyclicBarrier 允许一组线程互相等待,到达屏障点后再继续执行。
CyclicBarrier barrier = new CyclicBarrier(3, () -> {
System.out.println("所有线程到达屏障");
});
for (int i = 0; i < 3; i++) {
new Thread(() -> {
// 业务逻辑
try {
barrier.await(); // 等待其他线程
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
与CountDownLatch的区别:
- CountDownLatch:计数只能减,不能重置
- CyclicBarrier:可以重置,可重复使用
59. 什么是Future和CompletableFuture?
答案:
-
Future
ExecutorService executor = Executors.newFixedThreadPool(10); Future<String> future = executor.submit(() -> "result"); String result = future.get(); // 阻塞获取结果 -
CompletableFuture
CompletableFuture<String> future = CompletableFuture .supplyAsync(() -> "result") .thenApply(result -> result.toUpperCase()) .exceptionally(ex -> "default"); String result = future.join(); // 非阻塞获取
优势:
- 支持链式调用
- 支持异常处理
- 支持组合多个Future
60. 什么是线程安全?如何实现线程安全?
答案:
-
不可变对象
- 使用final修饰
- 不暴露内部状态
-
线程封闭
- ThreadLocal
- 局部变量
-
同步机制
- synchronized
- ReentrantLock
- volatile
-
并发容器
- ConcurrentHashMap
- CopyOnWriteArrayList
-
原子类
- AtomicInteger
- LongAdder
四、微服务(20题)
61. Spring Cloud的核心组件有哪些?
答案:
-
Spring Cloud Netflix
- Eureka:服务注册与发现
- Ribbon:负载均衡
- Hystrix:熔断降级
- Zuul:API网关
- Feign:声明式HTTP客户端
-
Spring Cloud Alibaba
- Nacos:服务注册与配置中心
- Sentinel:流量控制
- Seata:分布式事务
- RocketMQ:消息队列
-
Spring Cloud Gateway
- 网关服务
- 路由转发
- 过滤器
-
Spring Cloud Config
- 配置中心
-
Spring Cloud OpenFeign
- 声明式服务调用
62. 什么是服务注册与发现?如何实现?
答案:
服务注册与发现是微服务的基础设施。
-
注册中心
- 服务提供者启动时向注册中心注册
- 服务消费者从注册中心获取服务列表
-
实现方案
- Eureka:AP模型,支持心跳检测
- Nacos:支持CP和AP切换
- Consul:CP模型,支持健康检查
- Zookeeper:CP模型
-
注册流程
服务提供者 → 注册中心 → 服务发现 → 服务消费者
63. 什么是负载均衡?有哪些策略?
答案:
负载均衡将请求分发到多个服务实例。
策略:
-
轮询(Round Robin)
- 依次分发到每个实例
-
随机(Random)
- 随机选择一个实例
-
加权轮询(Weighted Round Robin)
- 根据权重分配请求
-
最少连接(Least Connections)
- 选择连接数最少的实例
-
一致性哈希(Consistent Hashing)
- 相同请求路由到相同实例
64. 什么是熔断降级?如何实现?
答案:
熔断降级保护系统不被雪崩。
-
熔断
- 当错误率达到阈值时,自动熔断
- 快速失败,不调用下游服务
-
降级
- 当服务不可用时,返回默认值或缓存数据
-
Sentinel实现
@SentinelResource(value = "getUser", blockHandler = "getUserFallback") public User getUser(Long id) { // 业务逻辑 } public User getUserFallback(Long id, BlockException ex) { // 降级逻辑 return new User(); } -
Hystrix实现
@HystrixCommand(fallbackMethod = "getUserFallback") public User getUser(Long id) { // 业务逻辑 }
65. 什么是限流?有哪些算法?
答案:
限流控制单位时间内的请求数量。
算法:
-
计数器算法
- 统计单位时间内的请求数
- 超过阈值则拒绝
-
令牌桶算法
- 以固定速率产生令牌
- 请求获取令牌,获取不到则拒绝
-
漏桶算法
- 请求进入漏桶
- 以固定速率处理
- 超过容量则拒绝
-
滑动窗口
- 将时间窗口划分为多个小窗口
- 统计小窗口的请求数
66. 什么是API网关?有什么作用?
答案:
API网关是微服务的统一入口。
作用:
-
路由转发
- 根据请求路径转发到不同服务
-
负载均衡
- 分发请求到服务实例
-
鉴权
- Token验证
- 权限控制
-
限流
- 保护后端服务
-
日志
- 请求日志记录
-
监控
- 性能指标收集
实现:
- Spring Cloud Gateway
- Zuul
- Kong
- Nginx
67. 什么是服务调用?有哪些方式?
答案:
服务调用是微服务之间的通信方式。
-
HTTP调用
- RestTemplate
- WebClient
- OkHttp
-
RPC调用
- Dubbo
- gRPC
- Thrift
-
声明式调用
- Feign
- OpenFeign
Feign示例:
@FeignClient(name = "user-service")
public interface UserClient {
@GetMapping("/user/{id}")
User getUser(@PathVariable("id") Long id);
}
68. 什么是配置中心?如何实现?
答案:
配置中心统一管理应用配置。
实现方案:
-
Spring Cloud Config
- 基于Git存储配置
- 支持配置版本管理
- 支持配置热更新
-
Nacos
- 支持动态配置
- 支持服务发现
- 简单易用
-
Apollo
- 携程开源
- 配置热更新
- 支持权限管理
配置热更新:
@RefreshScope
@Component
public class ConfigBean {
@Value("${config.property}")
private String property;
}
69. 什么是链路追踪?如何实现?
答案:
链路追踪追踪请求在微服务间的调用链。
实现方案:
-
Spring Cloud Sleuth
- 与Zipkin集成
- 自动添加Trace ID
-
SkyWalking
- 高性能链路追踪
- 支持多种语言
-
Jaeger
- Uber开源
- 支持追踪、分析
实现:
spring:
sleuth:
sampler:
probability: 1.0
zipkin:
base-url: http://localhost:9411
70. 什么是服务网关?如何实现?
答案:
服务网关是微服务的统一入口。
Spring Cloud Gateway:
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("user-service", r -> r
.path("/api/user/**")
.filters(f -> f
.stripPrefix(1)
.addRequestHeader("X-Request-From", "gateway"))
.uri("lb://user-service"))
.build();
}
}
过滤器:
@Component
public class AuthFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
if (token == null || token.isEmpty()) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
}
71. 什么是服务熔断器?如何选择?
答案:
服务熔断器保护系统不被雪崩。
选择:
-
Hystrix(已停止维护)
- Netflix开源
- 功能丰富
- 已停止维护
-
Sentinel(推荐)
- 阿里巴巴开源
- 轻量级
- 功能强大
- 支持实时监控
-
Resilience4j
- 轻量级
- 响应式支持
推荐:
- 新项目使用Sentinel
- 响应式项目使用Resilience4j
72. 什么是服务网格?
答案:
服务网格是基础设施层。
核心:
- Sidecar代理
- 数据平面
- 控制平面
实现:
- Istio
- Linkerd
- Envoy
73. 什么是微服务治理?
答案:
微服务治理管理微服务生命周期。
治理内容:
- 服务注册与发现
- 负载均衡
- 熔断降级
- 限流
- 链路追踪
- 配置管理
- 日志管理
74. 什么是服务降级?如何实现?
答案:
服务降级当服务不可用时,返回默认值。
实现:
@SentinelResource(value = "getUser", fallback = "getUserFallback")
public User getUser(Long id) {
// 业务逻辑
}
public User getUserFallback(Long id, Exception ex) {
return new User();
}
75. 什么是服务限流?如何实现?
答案:
服务限流控制请求速率。
实现:
@SentinelResource(value = "getUser", blockHandler = "handleBlock")
public User getUser(Long id) {
// 业务逻辑
}
public User handleBlock(Long id, BlockException ex) {
return new User();
}
配置:
spring:
cloud:
sentinel:
eager: true
datasource:
ds1:
nacos:
server-addr: localhost:8848
data-id: gateway-flow-rules
group-id: DEFAULT_GROUP
rule-type: flow
76. 什么是分布式事务?有哪些方案?
答案:
分布式事务保证分布式系统的数据一致性。
方案:
-
2PC(两阶段提交)
- 强一致性
- 性能差
-
TCC(尝试-确认-取消)
- 高性能
- 代码侵入
-
消息最终一致性
- 解耦
- 最终一致
-
Seata
- 支持多种模式
- 易于集成
77. 什么是CAP理论?
答案:
见分布式系统部分。
78. 什么是BASE理论?
答案:
见分布式系统部分。
79. 什么是服务雪崩?如何预防?
答案:
服务雪崩是微服务的级联故障。
预防:
- 熔断降级
- 限流
- 超时控制
- 舱壁隔离
- 缓存
80. 什么是服务发现?如何实现?
答案:
见服务注册与发现部分。
五、中间件(20题)
81. Redis的数据结构有哪些?
答案:
-
String(字符串)
redis.set("key", "value"); redis.get("key"); -
List(列表)
redis.lpush("list", "value1"); redis.rpop("list"); -
Set(集合)
redis.sadd("set", "value1"); redis.smembers("set"); -
Sorted Set(有序集合)
redis.zadd("zset", 1, "value1"); redis.zrange("zset", 0, -1); -
Hash(哈希)
redis.hset("hash", "field", "value"); redis.hget("hash", "field");
82. Redis持久化机制有哪些?
答案:
-
RDB(快照)
- 定期保存数据快照
- 恢复速度快
- 可能丢失数据
-
AOF(追加日志)
- 记录每个写操作
- 数据安全性高
- 文件体积大
-
混合持久化
- RDB + AOF
- 结合两者优点
83. Redis缓存穿透、缓存击穿、缓存雪崩是什么?
答案:
-
缓存穿透
- 查询不存在的数据
- 解决方案:缓存空值、布隆过滤器
-
缓存击穿
- 热点Key过期
- 解决方案:永不过期、互斥锁
-
缓存雪崩
- 大量Key同时过期
- 解决方案:随机过期时间、多级缓存
84. Redis集群模式有哪些?
答案:
-
主从复制
- 一主多从
- 读写分离
-
哨兵模式
- 主从 + 监控
- 自动故障转移
-
Cluster集群
- 分布式存储
- 16384个哈希槽
85. Kafka的架构是什么?
答案:
-
Producer(生产者)
- 发送消息
-
Broker(代理)
- 消息存储
-
Consumer(消费者)
- 消费消息
-
Consumer Group(消费组)
- 负载均衡消费
-
Zookeeper
- 管理集群
86. Kafka如何保证消息不丢失?
答案:
-
生产者
props.put("acks", "all"); // 所有副本确认 props.put("retries", Integer.MAX_VALUE); // 无限重试 props.put("enable.idempotence", true); // 幂等 -
Broker
- 多副本同步
- 持久化
-
消费者
- 手动提交Offset
- 处理完再提交
87. RabbitMQ的交换机类型有哪些?
答案:
-
Direct Exchange
- 精确匹配Routing Key
-
Fanout Exchange
- 广播消息
- 忽略Routing Key
-
Topic Exchange
-
模式匹配
-
- 匹配一个词
-
匹配多个词
-
-
Headers Exchange
- 匹配消息头
88. RocketMQ的事务消息是什么?
答案:
事务消息保证本地事务和消息发送的一致性。
流程:
- 发送半消息
- 执行本地事务
- 提交或回滚消息
- Broker回查未确定消息
使用:
RocketMQTemplate rocketMQTemplate = new RocketMQTemplate();
LocalTransactionExecuter localExecuter = new LocalTransactionExecuter() {
@Override
public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
// 执行本地事务
return LocalTransactionState.COMMIT_MESSAGE;
}
};
rocketMQTemplate.sendMessageInTransaction("topic", message, null);
89. MySQL索引优化有哪些?
答案:
-
B+树索引
- 聚簇索引
- 非聚簇索引
-
索引原则
- 最左前缀原则
- 避免在索引列上做计算
- 使用覆盖索引
- 区分度高的列建索引
-
Explain分析
- type:访问类型
- key:使用的索引
- rows:扫描行数
- Extra:额外信息
90. MySQL事务隔离级别有哪些?
答案:
-
READ_UNCOMMITTED
- 可读取未提交数据
- 有脏读
-
READ_COMMITTED
- 只能读取已提交数据
- 避免脏读
-
REPEATABLE_READ
- 可重复读
- 避免脏读和不可重复读
-
SERIALIZABLE
- 串行化
- 最安全
91. MySQL分页优化有哪些?
答案:
-
子查询优化
SELECT * FROM table WHERE id >= (SELECT id FROM table LIMIT 10000, 1) LIMIT 10; -
延迟关联
SELECT t.* FROM table t INNER JOIN (SELECT id FROM table LIMIT 10000, 10) temp ON t.id = temp.id; -
覆盖索引
- 使用索引覆盖查询
- 避免回表
92. MySQL分库分表方案有哪些?
答案:
-
水平分表
- 按ID取模
- 按时间范围
-
垂直分表
- 常用字段和扩展字段分离
- 大字段分离
-
分库分表中间件
- ShardingSphere
- MyCAT
93. MongoDB的特点是什么?
答案:
-
文档存储
- BSON格式
- 灵活的模式
-
索引支持
- 单字段索引
- 复合索引
- 文本索引
- 地理空间索引
-
聚合框架
- MapReduce
- Aggregation Pipeline
-
高可用
- 副本集
- 分片集群
94. Elasticsearch的特点是什么?
答案:
-
全文检索
- 倒排索引
- 分词器
-
分布式
- 分片
- 副本
-
近实时
- 数据秒级可见
-
聚合分析
- 多维度分析
95. Zookeeper的特点是什么?
答案:
-
ZAB协议
- Zookeeper原子广播协议
- 保证一致性
-
数据结构
- 树形结构
- 节点带数据
-
节点类型
- 持久节点
- 临时节点
- 持久顺序节点
- 临时顺序节点
-
应用场景
- 配置管理
- 命名服务
- 分布式锁
- 集群管理
96. Nacos的特点是什么?
答案:
-
服务注册与发现
- 支持Nacos和Eureka
- 支持健康检查
-
配置管理
- 动态配置更新
- 配置版本管理
-
DNS服务
- 支持DNS协议
-
多环境支持
- 命名空间
- 分组
97. Sentinel的特点是什么?
答案:
-
流量控制
- 限流
- 降级
-
熔断降级
- 慢调用比例
- 异常比例
- 异常数
-
系统负载保护
- 自适应限流
-
实时监控
- metrics接口
- Dashboard
98. Seata的特点是什么?
答案:
-
多种事务模式
- AT模式
- TCC模式
- Saga模式
- XA模式
-
AT模式
- 无侵入
- 自动生成回滚日志
-
TCC模式
- 高性能
- 代码侵入
99. Dubbo的特点是什么?
答案:
-
高性能RPC
- 多种序列化
- 多种协议
-
服务治理
- 负载均衡
- 熔断降级
- 服务路由
-
服务发现
- 支持多种注册中心
-
监控
- Hessian服务
- Dubbo Admin
100. Spring Cloud Alibaba组件有哪些?
答案:
-
Nacos
- 服务注册与发现
- 配置中心
-
Sentinel
- 流量控制
- 熔断降级
-
Seata
- 分布式事务
-
RocketMQ
- 消息队列
-
Distributed Seata
- 分布式事务解决方案
总结
本文档整理了100道Java高级工程师面试题,涵盖:
- Spring基础框架(20题):IOC、AOP、事务、MVC、Boot等
- 分布式系统(20题):CAP、BASE、分布式锁、事务等
- 高并发(20题):JVM、多线程、并发容器、锁机制等
- 微服务(20题):Spring Cloud、服务治理、网关等
- 中间件(20题):Redis、Kafka、MQ、数据库等
建议学习方法:
- 先理解原理,再记忆细节
- 结合实际项目经验
- 动手实践,加深理解
- 定期复习,巩固记忆

浙公网安备 33010602011771号