注解方式:使用 @Component 及衍生注解(@Controller/@Service/@Repository),配合组件扫描(@ComponentScan)自动注册;
配置类方式:在配置类中用 @Bean 注解手动注册(返回 Bean 实例的方法);
XML 配置方式:通过 XML 文件的 <bean> 标签定义 Bean,如 <bean id="userService" class="com.example.UserService"/>;
实现接口方式:实现 BeanDefinitionRegistryPostProcessor 接口,手动向容器注册 BeanDefinition;
工厂 Bean 方式:实现 FactoryBean 接口,通过其 getObject() 方法创建 Bean 并注册。
Spring 自动装配(autowire)主要有 5 种方式:
no:默认值,不自动装配,需手动通过 ref 或注解指定依赖;
byName:按属性名匹配容器中 Bean 的 id,属性名与 Bean 的 id 一致则自动注入;
byType:按属性类型匹配容器中同类型 Bean,若存在多个同类型 Bean 则报错;
constructor:按构造方法参数类型匹配,与 byType 逻辑类似,但针对构造器参数;
autodetect(已过时):优先按 constructor 装配,若无合适构造器则按 byType 装配。
注解方式的自动装配(@Autowired/@Resource)本质是 byType 或 byName 的简化实现。
@Qualifier 注解用于解决自动装配时 “同类型 Bean 存在多个” 的歧义问题:
当容器中存在多个同一类型的 Bean 时,仅用 @Autowired(默认 byType)会报错;
搭配 @Qualifier("beanId") 可指定按 Bean 的 id(或 name)注入,明确选择目标 Bean;
示例:@Autowired @Qualifier("userServiceV2") private UserService userService;,表示注入 id 为 userServiceV2 的 Bean。

核心共性:均为 Bean 注册注解,底层都基于 @Component,可被 @ComponentScan 扫描并注册到容器;
区别:语义不同,用于区分 Bean 的业务角色,便于代码分层和框架功能适配:
@Component:通用注解,无明确业务含义,适用于通用组件;
@Controller:用于 Web 层 Controller 类,Spring MVC 会识别此类并处理请求映射;
@Service:用于业务层 Service 类,标识业务逻辑组件;
@Repository:用于数据访问层 Dao 类,Spring 会为其自动处理数据库异常(转换为 Spring 统一异常)。
非 public 方法:Spring 事务基于 AOP 动态代理,默认只拦截 public 方法,非 public 方法的事务注解无效;
方法内部调用:同一类中方法 A 调用方法 B(B 有事务注解),因未经过代理对象,事务不生效;
异常类型不匹配:默认只回滚 RuntimeException 和 Error,若抛出检查型异常(如 IOException)且未指定 rollbackFor,事务不回滚;
未配置事务管理器:未在配置类中定义 PlatformTransactionManager,事务无执行载体;
事务传播行为不当:如使用 NOT_SUPPORTED(以非事务执行)、NEVER(禁止事务),会导致事务失效;
多线程调用:子线程中的事务与主线程事务独立,主线程事务无法控制子线程事务;
数据源不匹配:事务管理器配置的数据源与实际操作的数据源不一致,事务无法作用于目标数据库。
Spring 启动(以注解驱动为例)核心步骤:
初始化容器:创建 AnnotationConfigApplicationContext 实例,传入配置类;
资源定位与解析:扫描配置类及 @ComponentScan 指定包下的类,解析 @Bean、@Component 等注解,生成 BeanDefinition;
注册 BeanDefinition:将解析后的 BeanDefinition 存入 BeanDefinitionRegistry;
执行 BeanFactory 后置处理器:调用 BeanFactoryPostProcessor 接口实现类,修改或新增 BeanDefinition(如处理 @PropertySource);
注册 Bean 后置处理器:将 BeanPostProcessor 接口实现类注册到容器,用于后续 Bean 的初始化增强;
初始化单例 Bean:对非懒加载的单例 Bean,执行实例化、属性注入、初始化(@PostConstruct、InitializingBean),生成代理(若需 AOP),最终存入一级缓存;
容器就绪:发布 ContextRefreshedEvent 事件,容器启动完成,可对外提供 Bean 服务。
可能有,取决于 Bean 的状态:
若单例 Bean 是无状态的(无成员变量,或成员变量为常量、线程安全类),则无并发安全问题(如工具类、Controller 类,仅处理请求参数,不存储状态);
若单例 Bean 是有状态的(有可修改的成员变量,如 private int count),则多线程并发修改时会出现线程安全问题(如计数错误);
解决方式:使用线程安全的数据结构(如 AtomicInteger)、加锁(synchronized/Lock)、将有状态逻辑抽离到 ThreadLocal(每个线程独立存储状态)。
@Primary 注解用于解决自动装配时 “同类型 Bean 存在多个” 的优先级问题:
当容器中存在多个同一类型的 Bean,且未用 @Qualifier 指定时,@Primary 标记的 Bean 会被优先注入;
通常用于指定某类 Bean 的 “默认实现”,示例:
@Service @Primary // 默认注入的UserService
public class UserServiceImpl1 implements UserService {}
@Service // 非默认,需用@Qualifier指定
public class UserServiceImpl2 implements UserService {}
// 注入时会优先选择UserServiceImpl1
@Autowired private UserService userService;@Value 注解用于给 Bean 的字段或方法参数注入值,支持三种取值方式:
注入字面量:@Value("张三") private String name;;
注入系统属性:@Value("${user.dir}") private String userDir;(获取当前工作目录);
注入配置文件属性:配合 @PropertySource 加载自定义配置文件后,注入文件中的属性,如 @Value("${app.name}") private String appName;;
注入 SpEL 表达式:@Value("#{T(java.lang.Math).random()}") private double random;(生成随机数)。
11.Spring 中的 @Profile 注解的作用是什么?
@Profile 注解用于实现 “环境隔离”,指定 Bean 在特定环境下才会注册到容器:
常见环境:dev(开发)、test(测试)、prod(生产);
使用方式:
标记类或方法:@Profile("dev") @Service public class DevUserService implements UserService {},表示仅在 dev 环境注册该 Bean;
激活环境:通过 JVM 参数(-Dspring.profiles.active=dev)、配置文件(spring.profiles.active=dev)或代码(context.getEnvironment().setActiveProfiles("dev"))激活指定环境;
作用:避免不同环境的 Bean 相互干扰(如开发环境用测试数据库,生产环境用正式数据库)。
@PostConstruct:标记 Bean 初始化完成后执行的方法(属性注入后),用于 Bean 的初始化逻辑(如加载资源、初始化缓存),执行时机在 InitializingBean.afterPropertiesSet() 之前;
@PreDestroy:标记 Bean 销毁前执行的方法,用于 Bean 的资源释放逻辑(如关闭连接、释放文件句柄),执行时机在 DisposableBean.destroy() 之前;
示例:
@Service
public class UserService {
@PostConstruct
public void init() { System.out.println("Bean初始化后执行"); }
@PreDestroy
public void destroy() { System.out.println("Bean销毁前执行"); }
}@RequestBody:用于 Spring MVC 控制器方法的参数上,将 HTTP 请求体中的 JSON/XML 数据绑定到 Java 对象(需配合消息转换器,如 Jackson),适用于 POST/PUT 请求传递复杂参数;
示例:@PostMapping("/add") public void addUser(@RequestBody User user) {};
@ResponseBody:用于控制器方法上或返回值上,将方法返回的 Java 对象转换为 JSON/XML 数据,直接写入 HTTP 响应体,而非跳转视图,适用于 RESTful 接口返回数据;
示例:@GetMapping("/get") @ResponseBody public User getUser() { return new User(); }(或用 @RestController,其包含 @ResponseBody)。
@PathVariable 用于 Spring MVC 控制器方法的参数上,提取 URL 路径中的占位符参数:
URL 路径中用 {} 定义占位符,如 /user/{id};
注解通过参数名或 value 属性匹配占位符,将路径参数转换为指定类型的 Java 参数;
示例:
// 访问URL:/user/123,id参数会被赋值为123
@GetMapping("/user/{id}")
public User getUser(@PathVariable Integer id) { ... }
// 占位符名与参数名不一致时,需指定value
@GetMapping("/user/{userId}")
public User getUser(@PathVariable("userId") Integer id) { ... }@ModelAttribute 注解有两种核心作用:
方法级:标记的方法会在控制器所有方法执行前执行,其返回值会存入模型(Model),供视图或后续方法使用,常用于初始化公共数据(如页面共用的下拉框数据);
示例:
@ModelAttribute
public void loadCommonData(Model model) {
model.addAttribute("cityList", Arrays.asList("北京", "上海"));
}参数级:用于控制器方法参数上,将请求参数(URL 参数、表单参数)绑定到 Java 对象,并将该对象存入模型,默认模型属性名为类名首字母小写(如 User 对应 user);
示例:
@PostMapping("/update")
public String updateUser(@ModelAttribute User user) { ... }@ExceptionHandler 用于实现 “局部异常处理”,在控制器内部定义异常处理方法:
标记的方法会捕获当前控制器中抛出的指定类型异常,执行自定义处理逻辑(如返回错误页面、封装错误信息);
需指定捕获的异常类型(通过 value 属性),若未指定则捕获方法参数类型的异常;
示例:
@Controller
public class UserController {
// 捕获当前控制器中抛出的NullPointerException
@ExceptionHandler(NullPointerException.class)
public String handleNpe(Exception e, Model model) {
model.addAttribute("errorMsg", "空指针异常:" + e.getMessage());
return "error"; // 返回错误页面
}
}@ResponseStatus 注解用于指定 HTTP 响应状态码和原因短语,有两种使用场景:
1.标记异常类:当抛出该异常时,Spring MVC 会自动返回注解指定的 HTTP 状态码(如 404、500);
示例:
@ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "用户不存在")
public class UserNotFoundException extends RuntimeException {}
// 抛出该异常时,响应状态码为404,原因短语为“用户不存在”2.标记控制器方法:直接指定该方法返回响应的 HTTP 状态码(即使方法执行成功);
示例:
@GetMapping("/cookie")
public String getCookie(
@CookieValue("JSESSIONID") String sessionId,
@CookieValue(value = "username", required = false) String username) { ... }@RequestHeader:用于控制器方法参数上,提取 HTTP 请求头中的信息(如 User-Agent、Content-Type),支持指定默认值;
示例:
@GetMapping("/header")
public String getHeader(
@RequestHeader("User-Agent") String userAgent,
@RequestHeader(value = "Accept-Language", defaultValue = "zh-CN") String lang) { ... }@CookieValue:用于控制器方法参数上,提取 HTTP 请求中的 Cookie 值,支持指定默认值;
示例:
@GetMapping("/cookie")
public String getCookie(
@CookieValue("JSESSIONID") String sessionId,
@CookieValue(value = "username", required = false) String username) { ... }@SessionAttribute 用于控制器方法参数上,从 HTTP 会话(Session)中获取已存在的属性值:
注意:该注解仅 “读取” Session 中的属性,不主动将参数存入 Session(若需存入,需用 @SessionAttributes 或手动调用 session.setAttribute());
支持指定属性名(value)、是否必须存在(required)、默认值(defaultValue);
示例:
// 从Session中获取名为“loginUser”的属性,注入到user参数
@GetMapping("/userinfo")
public String getUserInfo(@SessionAttribute("loginUser") User user, Model model) {
model.addAttribute("user", user);
return "userinfo";
}
@Scheduled 是 Spring 用于实现定时任务的注解,标记在方法上可让方法按预设时间规则自动执行,无需手动触发。使用前需在配置类添加 @EnableScheduling 开启定时任务功能,支持三种核心时间配置方式:
fixedRate:固定频率执行,如 fixedRate = 5000 表示每 5 秒执行一次,无论上一次任务是否完成;
fixedDelay:固定延迟执行,如 fixedDelay = 5000 表示上一次任务执行完成后,间隔 5 秒再执行下一次;
cron:基于 cron 表达式配置复杂时间规则,如 cron = "0 0 8 ?" 表示每天早上 8 点执行。
该注解适合实现周期性任务,如定时数据同步、日志清理、报表生成等场景。
两者均为 Spring 缓存抽象的核心注解,用于简化缓存操作:
@Cacheable:标记在查询方法上,作用是 “查询时优先从缓存获取数据,若缓存无数据则执行方法并将结果存入缓存”。可通过 value 指定缓存名称,key 自定义缓存键(支持 SpEL 表达式),示例:@Cacheable(value = "userCache", key = "#id") 表示将 id 作为键,查询结果存入 userCache 缓存;
@CacheEvict:标记在修改 / 删除方法上,作用是 “清除缓存中的指定数据”,避免缓存与数据库数据不一致。可通过 value 指定缓存名称,key 指定要清除的缓存键,allEntries = true 表示清除该缓存下所有数据,示例:@CacheEvict(value = "userCache", key = "#id") 表示删除 userCache 中键为 id 的缓存数据。
使用前需通过 @EnableCaching 开启缓存功能,并配置缓存管理器(如 RedisCacheManager)。
@Conditional 是 Spring 用于实现 “条件化 Bean 注册” 的注解,可根据指定条件决定 Bean 是否注册到容器。其核心逻辑是:通过自定义实现 Condition 接口的类,重写 matches 方法判断条件是否满足,若满足则注册 Bean,否则不注册。使用方式有两种:
直接标记在 @Bean 方法或 @Component 类上,如 @Conditional(WindowsCondition.class) @Bean public UserService userService(),表示仅当 WindowsCondition 条件满足(如运行环境为 Windows)时,才注册 userService Bean;
使用 Spring 提供的派生注解(无需自定义 Condition),如 @ConditionalOnClass(类存在时)、@ConditionalOnBean(Bean 存在时)、@ConditionalOnProperty(配置属性满足时)。
该注解适合实现多环境适配,如不同环境注册不同的数据源 Bean。
@Lazy 注解用于控制 Bean 的初始化时机,实现 “懒加载”:
对单例 Bean:Spring 默认在容器启动时初始化所有单例 Bean,添加 @Lazy 后,Bean 会延迟到第一次被获取(如 context.getBean() 或依赖注入)时才初始化,减少容器启动时间和内存占用;
对原型 Bean:@Lazy 无实际作用,因原型 Bean 本身就是每次获取时才创建;
使用方式:标记在 @Component 类或 @Bean 方法上,如 @Lazy @Service public class UserService 或 @Bean @Lazy public UserDao userDao()。
适合场景:Bean 初始化耗时较长(如加载大量资源)、容器启动时非必需的 Bean,或希望减少启动阶段资源消耗的场景。
@PropertySource 用于加载自定义的外部属性文件(如 .properties 或 .yml 文件),将文件中的属性值注入到 Spring 环境(Environment)中,供 @Value 注解或 @ConfigurationProperties 注解使用。核心使用逻辑:
在配置类上添加 @PropertySource,指定属性文件路径,如 @PropertySource(value = "classpath:app.properties") 表示加载类路径下的 app.properties 文件;
若加载多个文件,可通过数组形式指定,如 @PropertySource(value = {"classpath:app.properties", "classpath:db.properties"});
加载后,可通过 @Value("${app.name}") 注入文件中的 app.name 属性,或通过 @ConfigurationProperties(prefix = "db") 绑定前缀为 db 的一组属性。
注意:@PropertySource 默认不支持加载 .yml 文件,需自定义 PropertySourceFactory 实现。
@EventListener 是 Spring 用于简化 “事件监听” 的注解,无需实现 ApplicationListener 接口,即可让方法成为事件监听器,响应指定类型的 Spring 事件。使用方式:
标记在 Bean 的方法上,方法参数指定要监听的事件类型(如 ApplicationEvent 及其子类),如:
java
@Service
public class UserService {
@EventListener
public void handleUserCreatedEvent(UserCreatedEvent event) {
// 处理用户创建事件,如发送通知
System.out.println("用户创建:" + event.getUserId());
}
}通过 classes 属性指定监听的事件类型(当方法无参数时),如 @EventListener(classes = UserDeletedEvent.class);
支持事件过滤,通过 condition 属性(SpEL 表达式)指定条件,如 @EventListener(condition = "#event.userId > 100") 表示仅处理 userId 大于 100 的事件。
事件发布需通过 ApplicationContext.publishEvent() 方法,如 context.publishEvent(new UserCreatedEvent(1L))。
@Async 是 Spring 用于实现 “异步方法调用” 的注解,标记在方法上可让方法在独立线程中执行,避免阻塞调用线程。其核心原理基于 AOP 动态代理:
开启异步功能:需在配置类添加 @EnableAsync 注解,Spring 会自动注册 AsyncAnnotationBeanPostProcessor 后置处理器;
生成代理对象:AsyncAnnotationBeanPostProcessor 会为带有 @Async 的 Bean 生成动态代理(JDK 或 CGLIB);
拦截方法调用:当调用异步方法时,代理对象会拦截调用请求,将方法执行任务提交到指定的线程池(默认是 SimpleAsyncTaskExecutor,但推荐自定义线程池);
线程池执行:线程池中的线程执行异步方法,调用线程无需等待结果,直接返回(若方法有返回值,需用 Future 或 CompletableFuture 接收)。
注意:异步方法不能在同一类中内部调用(因内部调用不经过代理对象),且方法返回值需为 void、Future 或 CompletableFuture。
Spring 和 Spring MVC 是 “父框架与子模块” 的关系,具体表现为:
归属关系:Spring MVC 是 Spring 框架的 Web 模块,是 Spring 在 Web 开发领域的具体实现,依赖 Spring 核心功能(如 IOC、AOP);
功能依赖:Spring MVC 的核心组件(如 Controller、HandlerMapping)均为 Spring Bean,由 Spring IOC 容器管理;其 AOP 功能(如请求拦截、事务控制)也依赖 Spring AOP 机制;
定位不同:Spring 是通用的企业级应用框架,提供 IOC、AOP、事务管理、数据访问等核心功能,可用于非 Web 应用(如桌面应用);Spring MVC 是专注于 Web 应用的 MVC 框架,用于处理 HTTP 请求、实现前后端交互,仅适用于 Web 场景;
整合关系:使用 Spring MVC 时,需先初始化 Spring 核心容器(父容器,管理 Service、Dao),再初始化 Spring MVC 容器(子容器,管理 Controller),子容器可访问父容器的 Bean,父容器不能访问子容器的 Bean。
Spring WebFlux:是 Spring 5 推出的响应式 Web 框架,基于响应式编程模型(Reactive Streams),支持非阻塞 I/O,可运行在 Netty、Undertow 等非 Servlet 容器,适合高并发、I/O 密集型 Web 应用(如实时推送、大数据流处理)。
与 Spring MVC 的核心区别:
Spring MVC 基于 MVC 模式,通过 7 个核心组件协同工作处理 HTTP 请求,各组件职责明确:
DispatcherServlet(前端控制器):整个流程的入口,统一接收 HTTP 请求,协调其他组件工作,避免组件间直接耦合;
HandlerMapping(处理器映射器):根据请求 URL 查找对应的 Handler(即 Controller 中的方法),返回包含 Handler 和拦截器的 HandlerExecutionChain;
HandlerAdapter(处理器适配器):适配不同类型的 Handler(如注解式 Controller、实现接口的 Controller),调用 Handler 处理请求,屏蔽 Handler 实现差异;
Handler(处理器):即业务处理器(通常是 Controller 中的方法),负责处理请求业务逻辑,返回 ModelAndView(数据模型 + 视图名);
ViewResolver(视图解析器):根据 ModelAndView 中的视图名,解析为具体的 View 对象(如 JSP、Thymeleaf 模板);
View(视图):接收模型数据,渲染页面(或生成 JSON/XML),将结果返回给客户端;
HandlerInterceptor(拦截器):在请求处理的预处理(Handler 执行前)、后处理(Handler 执行后)、完成处理(视图渲染后)阶段执行自定义逻辑,如权限校验、日志记录。
各组件的协作流程:DispatcherServlet → HandlerMapping → HandlerAdapter → Handler → ViewResolver → View → 响应客户端。