口语八股—— Spring 面试实战指南(终篇):常用注解篇、Spring中的设计模式

一、常用注解篇

1.1 Spring Boot常用注解有哪些?分别有什么作用?

✅ 正确回答思路:

我按功能分类来说明:

一、核心注解

1. @SpringBootApplication

这是Spring Boot的核心注解,组合了三个注解:

java 复制代码
@SpringBootApplication
// 等价于
@SpringBootConfiguration  // 相当于@Configuration
@EnableAutoConfiguration  // 开启自动配置
@ComponentScan  // 开启组件扫描
public class Application {
}

2. @Configuration

声明这是一个配置类,相当于XML配置文件:

java 复制代码
@Configuration
public class AppConfig {
    @Bean
    public User user() {
        return new User();
    }
}

3. @Bean

在@Configuration类中,声明一个Bean:

java 复制代码
@Bean(name = "user", initMethod = "init", destroyMethod = "destroy")
@Scope("singleton")
public User user() {
    return new User();
}

二、组件注解

1. @Component

通用的组件注解:

java 复制代码
@Component
public class MyComponent {
}

2. @Service

Service层的组件:

java 复制代码
@Service
public class UserService {
}

3. @Repository

DAO层的组件:

java 复制代码
@Repository
public class UserDao {
}

4. @Controller

Controller层的组件:

java 复制代码
@Controller
public class UserController {
}

5. @RestController

RESTful API的Controller,组合了@Controller和@ResponseBody:

java 复制代码
@RestController  // 等价于@Controller + @ResponseBody
@RequestMapping("/api/user")
public class UserController {
}

这四个注解(@Service、@Repository、@Controller、@RestController)本质上都是@Component,只是语义不同。

三、依赖注入注解

1. @Autowired

自动注入Bean:

java 复制代码
@Service
public class UserService {
    @Autowired  // 按类型注入
    private UserDao userDao;
}

2. @Qualifier

配合@Autowired,按名称注入:

java 复制代码
@Service
public class UserService {
    @Autowired
    @Qualifier("userDaoImpl")  // 按名称注入
    private UserDao userDao;
}

3. @Resource

Java标准注解,按名称注入:

java 复制代码
@Service
public class UserService {
    @Resource(name = "userDaoImpl")  // 按名称注入
    private UserDao userDao;
}

@Autowired vs @Resource:

注解 来源 默认方式 指定名称
@Autowired Spring 按类型 @Qualifier
@Resource Java标准 按名称 name属性

4. @Value

注入配置文件的值:

java 复制代码
@Service
public class UserService {
    @Value("${app.name}")  // 从application.yml读取
    private String appName;
    
    @Value("${app.version:1.0}")  // 默认值
    private String version;
    
    @Value("#{systemProperties['user.name']}")  // SpEL表达式
    private String userName;
}

四、配置属性注解

@ConfigurationProperties

批量注入配置:

java 复制代码
@ConfigurationProperties(prefix = "app")
@Component
public class AppProperties {
    private String name;
    private String version;
    private ServerConfig server;
    
    // getter/setter
    
    public static class ServerConfig {
        private String host;
        private int port;
        // getter/setter
    }
}

# application.yml
app:
  name: MyApp
  version: 1.0
  server:
    host: localhost
    port: 8080

五、Web相关注解

1. @RequestMapping

映射请求URL:

java 复制代码
@Controller
@RequestMapping("/user")
public class UserController {
    
    @RequestMapping(value = "/list", method = RequestMethod.GET)
    public String list() {
        return "user/list";
    }
}

2. @GetMapping、@PostMapping等

简化的请求映射:

java 复制代码
@RestController
@RequestMapping("/api/user")
public class UserController {
    
    @GetMapping("/{id}")  // GET请求
    public User getUser(@PathVariable Long id) {
        return userService.getUser(id);
    }
    
    @PostMapping  // POST请求
    public User addUser(@RequestBody User user) {
        return userService.addUser(user);
    }
    
    @PutMapping("/{id}")  // PUT请求
    public User updateUser(@PathVariable Long id, @RequestBody User user) {
        return userService.updateUser(id, user);
    }
    
    @DeleteMapping("/{id}")  // DELETE请求
    public void deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
    }
}

3. @PathVariable

获取URL路径参数:

java 复制代码
@GetMapping("/user/{id}")
public User getUser(@PathVariable Long id) {
    // URL: /user/123 → id = 123
}

@GetMapping("/user/{id}/order/{orderId}")
public Order getOrder(@PathVariable Long id, @PathVariable Long orderId) {
    // URL: /user/123/order/456 → id = 123, orderId = 456
}

4. @RequestParam

获取URL查询参数:

java 复制代码
@GetMapping("/user/search")
public List<User> search(
    @RequestParam String name,  // 必须有name参数
    @RequestParam(required = false) Integer age,  // age参数可选
    @RequestParam(defaultValue = "1") int page  // 默认值
) {
    // URL: /user/search?name=张三&age=25&page=2
}

5. @RequestBody

获取请求体(JSON):

java 复制代码
@PostMapping("/user")
public User addUser(@RequestBody User user) {
    // 请求体: {"name": "张三", "age": 25}
    // 自动转成User对象
}

6. @ResponseBody

返回JSON(而不是视图):

java 复制代码
@Controller
public class UserController {
    
    @GetMapping("/user/{id}")
    @ResponseBody  // 返回JSON
    public User getUser(@PathVariable Long id) {
        return userService.getUser(id);
    }
}

// @RestController = @Controller + @ResponseBody

六、事务注解

@Transactional

声明事务:

java 复制代码
@Service
public class UserService {
    
    @Transactional(
        propagation = Propagation.REQUIRED,  // 传播行为
        isolation = Isolation.DEFAULT,  // 隔离级别
        timeout = 30,  // 超时时间(秒)
        rollbackFor = Exception.class,  // 回滚的异常
        noRollbackFor = BusinessException.class  // 不回滚的异常
    )
    public void addUser(User user) {
        userDao.insert(user);
    }
}

七、AOP注解

1. @Aspect

声明切面:

java 复制代码
@Aspect
@Component
public class LogAspect {
}

2. @Pointcut

定义切点:

java

java 复制代码
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceLayer() {}

3. @Before、@After等

定义通知:

java 复制代码
@Aspect
@Component
public class LogAspect {
    
    @Before("execution(* com.example.service.*.*(..))")
    public void before(JoinPoint joinPoint) {
        System.out.println("方法执行前: " + joinPoint.getSignature());
    }
    
    @After("execution(* com.example.service.*.*(..))")
    public void after(JoinPoint joinPoint) {
        System.out.println("方法执行后: " + joinPoint.getSignature());
    }
    
    @Around("execution(* com.example.service.*.*(..))")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("环绕通知-前");
        Object result = pjp.proceed();
        System.out.println("环绕通知-后");
        return result;
    }
}

八、条件注解

1. @Conditional

按条件注册Bean:

java 复制代码
@Configuration
public class AppConfig {
    
    @Bean
    @Conditional(WindowsCondition.class)  // Windows系统才注册
    public DataSource windowsDataSource() {
        return new DataSource();
    }
}

public class WindowsCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return context.getEnvironment().getProperty("os.name").contains("Windows");
    }
}

2. @ConditionalOnProperty

配置文件有指定属性才生效:

java 复制代码
@Bean
@ConditionalOnProperty(name = "app.feature.enabled", havingValue = "true")
public FeatureService featureService() {
    return new FeatureService();
}

3. @ConditionalOnClass

类路径有指定类才生效:

java 复制代码
@Bean
@ConditionalOnClass(name = "com.mysql.cj.jdbc.Driver")
public DataSource dataSource() {
    return new DataSource();
}

九、异步和定时任务注解

1. @Async

异步执行:

java 复制代码
@Service
public class AsyncService {
    
    @Async  // 异步执行,立即返回
    public void sendEmail(String email) {
        // 发送邮件(耗时操作)
    }
    
    @Async
    public CompletableFuture<String> asyncMethod() {
        // 异步执行,返回Future
        return CompletableFuture.completedFuture("结果");
    }
}

// 启用异步
@EnableAsync
@SpringBootApplication
public class Application {
}

2. @Scheduled

定时任务:

java 复制代码
@Component
public class ScheduledTask {
    
    @Scheduled(cron = "0 0 2 * * ?")  // 每天凌晨2点执行
    public void dailyTask() {
        System.out.println("定时任务执行");
    }
    
    @Scheduled(fixedRate = 5000)  // 每5秒执行一次
    public void fixedRateTask() {
        System.out.println("固定频率任务");
    }
    
    @Scheduled(fixedDelay = 5000)  // 上次执行完5秒后再执行
    public void fixedDelayTask() {
        System.out.println("固定延迟任务");
    }
}

// 启用定时任务
@EnableScheduling
@SpringBootApplication
public class Application {
}

十、验证注解

JSR-303/JSR-380(Bean Validation)

java 复制代码
public class User {
    
    @NotNull(message = "ID不能为空")
    private Long id;
    
    @NotBlank(message = "用户名不能为空")
    @Size(min = 3, max = 20, message = "用户名长度3-20")
    private String username;
    
    @Email(message = "邮箱格式不正确")
    private String email;
    
    @Min(value = 18, message = "年龄不能小于18")
    @Max(value = 100, message = "年龄不能大于100")
    private Integer age;
    
    @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
    private String phone;
}

@RestController
public class UserController {
    
    @PostMapping("/user")
    public User addUser(@RequestBody @Validated User user) {  // @Validated触发验证
        return userService.addUser(user);
    }
}

💡 总结: Spring Boot常用注解分类:

  1. 核心: @SpringBootApplication、@Configuration、@Bean
  2. 组件: @Component、@Service、@Repository、@Controller、@RestController
  3. 注入: @Autowired、@Resource、@Value、@ConfigurationProperties
  4. Web: @RequestMapping、@GetMapping、@PathVariable、@RequestBody
  5. 事务: @Transactional
  6. AOP: @Aspect、@Before、@Around
  7. 条件: @ConditionalOnXxx
  8. 异步: @Async、@Scheduled
  9. 验证: @NotNull、@NotBlank、@Email

📌 二、Spring中的设计模式

2.1 Spring中用了哪些设计模式?

✅ 正确回答思路:

Spring框架大量使用了设计模式,我挑几个重要的说明:

一、工厂模式(Factory Pattern)

BeanFactory和ApplicationContext就是工厂:

java 复制代码
// BeanFactory: Spring的Bean工厂
BeanFactory factory = new XmlBeanFactory(new ClassPathResource("beans.xml"));
User user = (User) factory.getBean("user");

// ApplicationContext: 增强的工厂
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
User user = context.getBean(User.class);

Spring的FactoryBean:

java 复制代码
@Component
public class UserFactoryBean implements FactoryBean<User> {
    
    @Override
    public User getObject() throws Exception {
        // 自定义创建逻辑
        User user = new User();
        user.setName("张三");
        return user;
    }
    
    @Override
    public Class<?> getObjectType() {
        return User.class;
    }
    
    @Override
    public boolean isSingleton() {
        return true;
    }
}

// 使用
@Autowired
private User user;  // 注入的是getObject()返回的对象

二、单例模式(Singleton Pattern)

Spring Bean默认就是单例:

java 复制代码
@Service
@Scope("singleton")  // 默认就是singleton,可以不写
public class UserService {
}

Spring的单例和传统单例的区别:

  • 传统单例: JVM内只有一个实例
  • Spring单例: IOC容器内只有一个实例

Spring如何保证单例:

java 复制代码
// 伪代码:Spring的单例池
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

public Object getSingleton(String beanName) {
    Object singleton = singletonObjects.get(beanName);
    if (singleton == null) {
        synchronized (this.singletonObjects) {
            singleton = singletonObjects.get(beanName);
            if (singleton == null) {
                singleton = createBean(beanName);  // 创建Bean
                singletonObjects.put(beanName, singleton);
            }
        }
    }
    return singleton;
}

三、代理模式(Proxy Pattern)

Spring AOP就是基于代理模式:

  • JDK动态代理
  • CGLIB代理

前面讲过了,不再赘述。

四、模板方法模式(Template Method Pattern)

JdbcTemplate:

java 复制代码
@Repository
public class UserDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    public User findById(Long id) {
        // 模板方法:jdbcTemplate封装了JDBC的通用流程
        return jdbcTemplate.queryForObject(
            "SELECT * FROM user WHERE id = ?",
            new BeanPropertyRowMapper<>(User.class),
            id
        );
    }
}

jdbcTemplate.query()的实现(简化版):

java 复制代码
public <T> T query(String sql, RowMapper<T> rowMapper, Object... args) {
    Connection conn = null;
    PreparedStatement ps = null;
    ResultSet rs = null;
    
    try {
        // 1. 获取连接(模板方法)
        conn = getConnection();
        
        // 2. 创建PreparedStatement(模板方法)
        ps = conn.prepareStatement(sql);
        
        // 3. 设置参数(模板方法)
        setParameters(ps, args);
        
        // 4. 执行查询(模板方法)
        rs = ps.executeQuery();
        
        // 5. 映射结果(钩子方法,由用户实现)
        return rowMapper.mapRow(rs, 0);
        
    } finally {
        // 6. 释放资源(模板方法)
        close(rs, ps, conn);
    }
}

五、观察者模式(Observer Pattern)

Spring的事件机制:

java 复制代码
// 1. 定义事件
public class UserRegisterEvent extends ApplicationEvent {
    private User user;
    
    public UserRegisterEvent(Object source, User user) {
        super(source);
        this.user = user;
    }
    
    public User getUser() {
        return user;
    }
}

// 2. 发布事件
@Service
public class UserService {
    @Autowired
    private ApplicationEventPublisher eventPublisher;
    
    public void register(User user) {
        // 注册用户
        userDao.insert(user);
        
        // 发布事件
        eventPublisher.publishEvent(new UserRegisterEvent(this, user));
    }
}

// 3. 监听事件
@Component
public class EmailListener implements ApplicationListener<UserRegisterEvent> {
    @Override
    public void onApplicationEvent(UserRegisterEvent event) {
        User user = event.getUser();
        // 发送注册邮件
        emailService.sendWelcomeEmail(user.getEmail());
    }
}

// 或者用@EventListener注解
@Component
public class PointsListener {
    @EventListener
    public void handleUserRegister(UserRegisterEvent event) {
        // 赠送注册积分
        pointsService.givePoints(event.getUser().getId(), 100);
    }
}

六、策略模式(Strategy Pattern)

Resource资源加载:

java 复制代码
// Resource接口:策略接口
public interface Resource {
    InputStream getInputStream() throws IOException;
}

// 不同的实现:具体策略
public class ClassPathResource implements Resource {
    // 从类路径加载
}

public class FileSystemResource implements Resource {
    // 从文件系统加载
}

public class UrlResource implements Resource {
    // 从URL加载
}

// 使用
Resource resource = new ClassPathResource("application.yml");
InputStream is = resource.getInputStream();

七、适配器模式(Adapter Pattern)

Spring MVC的HandlerAdapter:

java 复制代码
// HandlerAdapter接口
public interface HandlerAdapter {
    boolean supports(Object handler);
    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler);
}

// 不同的适配器
public class RequestMappingHandlerAdapter implements HandlerAdapter {
    // 适配@RequestMapping注解的方法
}

public class HttpRequestHandlerAdapter implements HandlerAdapter {
    // 适配HttpRequestHandler接口
}

public class SimpleControllerHandlerAdapter implements HandlerAdapter {
    // 适配Controller接口
}

DispatcherServlet选择合适的适配器:

java 复制代码
HandlerAdapter adapter = getHandlerAdapter(handler);
ModelAndView mav = adapter.handle(request, response, handler);

八、装饰器模式(Decorator Pattern)

Spring的BeanWrapper:

java 复制代码
BeanWrapper wrapper = new BeanWrapperImpl(user);
wrapper.setPropertyValue("name", "张三");  // 增强了属性访问

九、责任链模式(Chain of Responsibility Pattern)

Spring MVC的拦截器链:

java 复制代码
public class HandlerExecutionChain {
    private final Object handler;
    private HandlerInterceptor[] interceptors;
    
    boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) {
        // 责任链模式:依次执行拦截器
        for (HandlerInterceptor interceptor : interceptors) {
            if (!interceptor.preHandle(request, response, handler)) {
                return false;
            }
        }
        return true;
    }
}

十、总结表格

设计模式 应用场景 示例
工厂模式 创建Bean BeanFactory、FactoryBean
单例模式 Bean作用域 singleton Bean
代理模式 AOP JDK动态代理、CGLIB
模板方法 封装通用流程 JdbcTemplate、RestTemplate
观察者模式 事件机制 ApplicationEvent、ApplicationListener
策略模式 不同实现方式 Resource加载
适配器模式 适配不同类型 HandlerAdapter
装饰器模式 增强功能 BeanWrapper
责任链模式 多个处理器 拦截器链

💡 总结: Spring框架大量使用了设计模式,这些设计模式让Spring具备了:

  • 灵活性: 可以轻松扩展和替换
  • 解耦性: 各个模块职责清晰
  • 可维护性: 代码结构清晰,易于理解

💡 面试加分项: "Spring框架是学习设计模式的最佳实践,通过阅读Spring源码,可以深入理解这些设计模式的实际应用。"


📌 三、面试回答技巧总结

1. 分层次回答

  • 先说"是什么"(概念)
  • 再说"为什么"(原理)
  • 最后说"怎么用"(实践)

2. 结合实际项目

  • 不要只说理论,一定要说"我在项目中..."
  • 说具体的场景和解决方案
  • 体现你真正用过Spring

3. 对比说明

  • 比如说IOC: 传统方式 vs IOC方式
  • 说代理: JDK动态代理 vs CGLIB
  • 对比能体现你理解深度

4. 画图辅助(如果可以)

  • IOC容器启动流程
  • SpringMVC请求处理流程
  • Bean生命周期
  • 能让面试官更直观理解

5. 适当展示深度

  • 可以提到源码中的关键类
  • 比如"AutoConfigurationImportSelector加载自动配置类"
  • 但不要过度炫技,说不清楚反而减分

6. 诚实应对不会的

  • 不会就说不会,但可以说"我的理解是..."
  • 或者说"这个问题我回去研究一下"
  • 表现出学习的态度

7. 控制时间

  • 每个问题2-3分钟
  • 不要太简短(显得不懂),也不要太啰嗦
  • 看面试官反应,如果他想深入,会追问的

8. 高频必考题 一定要准备的:

  • IOC和DI
  • AOP原理(JDK动态代理vs CGLIB)
  • Bean生命周期
  • 三级缓存解决循环依赖
  • 事务传播行为
  • 事务失效场景
  • SpringMVC流程
  • Spring Boot自动配置原理

📌 四、总结

这篇Spring面试八股文,我尽量用"人话"把技术点讲清楚,并且提供了大量实际代码和项目经验。

重点回顾:

1. Spring核心

  • IOC(控制反转)和DI(依赖注入)
  • IOC容器启动流程
  • 三级缓存解决循环依赖

2. AOP

  • AOP概念和应用场景
  • JDK动态代理 vs CGLIB代理
  • Spring AOP实现原理

3. 事务

  • 7种事务传播行为
  • 事务失效的9种情况

4. Spring MVC

  • SpringMVC的9步工作流程
  • 拦截器vs过滤器

5. Spring Boot

  • 自动配置原理(spring.factories + @ConditionalOnXxx)
  • 启动流程

6. Bean生命周期

  • 实例化→属性赋值→Aware回调→初始化→使用→销毁

7. 常用注解

  • @SpringBootApplication、@Autowired、@Transactional等

8. 设计模式

  • 工厂、单例、代理、模板方法、观察者等

最后的建议:

  • 理解比背诵重要: 理解了原理,才能灵活回答
  • 实战经验比理论重要: 能说出"我在项目中..."更有说服力
  • 能说出"为什么"比知道"是什么"重要: 体现你的深度

如果这篇文章对你有帮助,记得收藏起来,面试前看一遍,效果更佳!

相关推荐
百锦再2 小时前
Java重入锁(ReentrantLock)全面解析:从入门到源码深度剖析
java·开发语言·struts·spring·kafka·tomcat·intellij-idea
yuezhilangniao2 小时前
win10环境变量完全指南:Java、Maven、Android、Flutter -含我的环境备份
android·java·maven
追随者永远是胜利者2 小时前
(LeetCode-Hot100)32. 最长有效括号
java·算法·leetcode·职场和发展·go
lifallen2 小时前
CDQ 分治 (CDQ Divide and Conquer)
java·数据结构·算法
笨蛋不要掉眼泪2 小时前
OpenFeign远程调用详解:声明式实现、第三方API集成与负载均衡对比
java·运维·负载均衡
yaoxin5211232 小时前
326. Java Stream API - 实现自定义的 toList() 与 toSet() 收集器
java·开发语言
追随者永远是胜利者2 小时前
(LeetCode-Hot100)31. 下一个排列
java·算法·leetcode·职场和发展·go
木斯佳2 小时前
前端八股文面经大全:腾讯WXG技术架构前端面试(2025-11-19)·面经深度解析
前端·面试·架构
2501_901147832 小时前
DDP(分布式训练)核心知识点学习笔记
笔记·分布式·学习·面试