最近三年Java开发岗位的招聘要求发生了显著变化。五年前,掌握SSM框架(Spring+SpringMVC+MyBatis)和基础CRUD操作就能找到不错的工作,但现在情况完全不同。根据我参与的近百场技术面试反馈,90%的面试官会深入考察Spring框架原理和实际应用能力。
典型的大厂Spring面试题包括:
这些问题的背后,反映的是企业对开发者技术深度的要求。只会使用框架API的开发者,在微服务架构、云原生转型等场景下会面临巨大挑战。这也是为什么阿里P7及以上岗位的JD中,明确要求候选人具备"深入理解Spring框架设计思想"的能力。
传统Java开发中,对象创建和依赖管理是程序员的职责。比如要构建一个订单服务:
java复制// 传统方式
OrderDao orderDao = new OrderDaoImpl();
PaymentService payment = new PaymentService(orderDao);
OrderService service = new OrderService(orderDao, payment);
Spring的IoC容器通过BeanFactory和ApplicationContext接口体系,实现了控制反转。其核心实现涉及:
手写简易IoC容器的关键步骤:
java复制public class MiniContainer {
private Map<String, Object> beans = new ConcurrentHashMap<>();
public void registerBean(String name, Object bean) {
beans.put(name, bean);
// 处理依赖注入
injectDependencies(bean);
}
private void injectDependencies(Object bean) {
// 通过反射实现字段注入
Field[] fields = bean.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Autowired.class)) {
Object dependency = beans.get(field.getType().getName());
field.setAccessible(true);
field.set(bean, dependency);
}
}
}
}
Spring AOP的底层基于动态代理实现,主要处理场景包括:
JDK动态代理与CGLIB对比:
| 特性 | JDK动态代理 | CGLIB |
|---|---|---|
| 代理方式 | 接口代理 | 子类继承 |
| 性能 | 调用快,创建慢 | 创建快,调用稍慢 |
| 限制 | 必须实现接口 | 不能代理final类/方法 |
| Spring默认选择 | 有接口时使用 | 无接口时使用 |
实际项目中,我们常需要自定义切面处理业务日志:
java复制@Aspect
@Component
public class BizLogAspect {
@Pointcut("execution(* com.example..service.*.*(..))")
public void serviceLayer() {}
@Around("serviceLayer()")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object result = joinPoint.proceed();
long duration = System.currentTimeMillis() - start;
LogEntry entry = new LogEntry(
joinPoint.getSignature().getName(),
duration,
new Date()
);
logRepository.save(entry);
return result;
}
}
Spring Boot的自动配置通过@EnableAutoConfiguration实现,其核心机制是:
自定义Starter的开发步骤:
java复制@AutoConfiguration
@ConditionalOnClass(MyService.class)
@EnableConfigurationProperties(MyProperties.class)
public class MyAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public MyService myService(MyProperties properties) {
return new MyService(properties);
}
}
高并发场景下的Spring Boot优化方案:
JVM参数调优:
bash复制# 生产环境推荐配置
-Xms2g -Xmx2g -XX:MetaspaceSize=256m
-XX:MaxMetaspaceSize=256m -XX:+UseG1GC
-XX:MaxGCPauseMillis=200
Tomcat优化(application.yml):
yaml复制server:
tomcat:
max-threads: 200
min-spare-threads: 20
accept-count: 100
connection-timeout: 5000
缓存配置:
java复制@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
CaffeineCacheManager manager = new CaffeineCacheManager();
manager.setCaffeine(Caffeine.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES)
.maximumSize(1000));
return manager;
}
}
Nacos相比Eureka的优势:
服务注册示例:
java复制@SpringBootApplication
@EnableDiscoveryClient
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
配置中心使用:
java复制@RefreshScope
@RestController
public class ConfigController {
@Value("${order.discount.rate:0.9}")
private double discountRate;
@GetMapping("/rate")
public double getRate() {
return discountRate;
}
}
Seata的AT模式工作流程:
关键配置:
properties复制# seata配置
seata.tx-service-group=my_tx_group
seata.service.vgroup-mapping.my_tx_group=default
seata.enable-auto-data-source-proxy=true
业务代码示例:
java复制@GlobalTransactional
public void createOrder(OrderRequest request) {
// 扣减库存
storageService.deduct(request.getSku(), request.getCount());
// 创建订单
orderDao.create(request);
// 扣减余额
accountService.debit(request.getUserId(), request.getAmount());
}
基于JWT的授权服务器实现:
java复制@Configuration
@EnableAuthorizationServer
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("webapp")
.secret(passwordEncoder.encode("secret"))
.authorizedGrantTypes("password", "refresh_token")
.scopes("read", "write")
.accessTokenValiditySeconds(3600);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints.authenticationManager(authenticationManager)
.tokenStore(tokenStore())
.accessTokenConverter(jwtAccessTokenConverter());
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("my-secret-key");
return converter;
}
}
java复制@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/public/**").permitAll()
.antMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated();
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.tokenServices(tokenServices());
}
@Bean
public ResourceServerTokenServices tokenServices() {
RemoteTokenServices services = new RemoteTokenServices();
services.setCheckTokenEndpointUrl("http://auth-server/oauth/check_token");
services.setClientId("resource-server");
services.setClientSecret("secret");
return services;
}
}
三级缓存解决循环依赖的机制:
处理流程示例:
code复制A创建 -> 放入三级缓存 -> 需要B
B创建 -> 放入三级缓存 -> 需要A
从三级缓存拿到A的工厂 -> 获取早期A对象 -> 放入二级缓存
B完成初始化 -> 放入一级缓存
A继续注入B -> A完成初始化 -> 放入一级缓存
七种传播行为对比:
| 传播行为类型 | 说明 |
|---|---|
| REQUIRED(默认) | 当前有事务则加入,没有则新建 |
| REQUIRES_NEW | 新建事务,挂起当前事务(独立提交回滚) |
| NESTED | 嵌套事务,外层异常时内层会回滚 |
| SUPPORTS | 当前有事务则加入,没有则以非事务运行 |
| NOT_SUPPORTED | 以非事务方式执行,挂起当前事务 |
| MANDATORY | 必须在事务中运行,否则抛出异常 |
| NEVER | 必须在非事务环境下运行,否则抛出异常 |
实际项目中的选择建议:
建议的系统学习路径:
基础阶段(2-4周):
进阶阶段(4-6周):
高级阶段(持续):
推荐的学习资源组合:
我在指导团队新人时发现,那些能快速成长的开发者都有一个共同点:不仅会使用框架API,更能通过源码理解设计思想。比如学习Spring事务时,不要仅满足于@Transactional的使用,而应该深入探究TransactionInterceptor如何与AOP体系协作,以及不同数据源情况下的事务同步机制。