自动配置
- condition
condition的match方法可以实现选择性的创建Bean操作
需求:
在Spring的IOC容器中有一个User的Bean,要求:
- 导入jedis坐标后,加载Bean,没导入,则不加载
需求实现:
@Configuration
public class UserConfig {
@Bean
@Conditional(ClassCondition.class)
public User user(){
return new User();
}
}
public class ClassCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//1.需求:导入Jedis坐标后创建Bean
//思路:判断redis.clients.jedis.Jedis.class文件是否存在
boolean flag = true;
try {
Class<?> cls = Class.forName("redis.clients.jedis.Jedis");
} catch (ClassNotFoundException e) {
flag = false;
}
return flag;
}
}
//Maven 帮你下载 jedis 的 jar 包,并加入到项目的 classpath 中,所以 JVM 才能加载到 Jedis 类,你才能在代码里使用它。
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
实现对应的类来实现condition接口,相当于是条件,里面有一个方法,这个方法决定了是否创建对应的Bean
- 将类的判断定义为动态的,判断哪个字节码文件存在可以动态指定
需求实现:
@Configuration
public class UserConfig {
@Bean
//@Conditional(ClassCondition.class)
@ConditionalOnClass("redis.clients.jedis.Jedis")
public User user(){
return new User();
}
}
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(ClassCondition.class)
public @interface ConditionOnClass {
String[] value();
}
public class ClassCondition implements Condition {
//contest:上下文对象,用于获取环境,IOC容器,classpath对象
//metadata:注解元对象,可以用于获取注解定义的属性值
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//获取注解属性值 value
Map<String, Object> map = metadata.getAnnotationAttributes(ConditionOnClass.class.getName());
//System.out.println(map);
String[] value = (String[]) map.get("value");
boolean flag = true;
try {
for (String className : value) {
Class<?> cls = Class.forName(className);
}
} catch (ClassNotFoundException e) {
flag = false;
}
return flag;
}
}
在用户配置类使用自定义的conditiononclass注解,然后在注解上配置conditional注解,并且修改conditional注解实现类的逻辑
在springboot里提供了很多ConditionOnxxx的接口
在springboo-autoconfigure的jar包里
@ConditionalOnProperty:判断配置文件中是否有对应属性和值才初始化 Bean
@ConditionalOnClass:判断环境中是否有对应字节码文件才初始化 Bean
@ConditionalOnMissingBean:判断环境中没有对应 Bean 才初始化 Bean
- Enable*注解
springboot提供了很多Enable开头的注解,这些注解都是用于动态启动某些功能的,底层原理上使用import注解导入一些配置类,实现Bean的动态加载
举例:
使用第三方jar包的Bean
在类上添加EnableUser,获取到对应的Bean
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(UserConfig.class)
public @interface EnableUser {
}
springboot告诉大家要写一个enable开头的注解去标记你要初始化的Bean,springboot初始化的时候就会去找这些标记
- import注解
-
使用import导入的类会被spring加载到IOC容器中,有四种用法
-
导入bean
-
导入配置类
-
导入importSelector实现类,一般用于加载配置文件中的类
-
导入importBeanDefinitionRegistrar
-
idea的全局搜索某个类的快捷键:shift连续按两次(mac)
- importSelector实现类
在启动类上添加
@import(MyImportSelector.class)
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.xx.domain.User", "com.xx.domain.Role"};
}
}
public interface ImportSelector {
/**
* Select and return the names of which class(es) should be imported based on
* the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
*/
//动态返回需要被 Spring 容器加载并注册的类的全限定名数组。
String[] selectImports(AnnotationMetadata importingClassMetadata);
}
4. enableautoconfiguration
步骤
-
@EnableAutoConfiguration注解内部使用@Import(AutoConfigurationImportSelector.class)来加载配置类。 -
配置文件位置:
META-INF/spring.factories,该配置文件中定义了大量的配置类,当 SpringBoot 应用启动时,会自动加载这些配置类,初始化 Bean。 -
并不是所有的 Bean 都会被初始化,在配置类中使用 Condition 来加载满足条件的 Bean。
监听机制
- 事件监听
springboot在项目启动的时候,会对几个监听器进行回调,我们可以实现这些监听器接口,在项目启动时完成一些操作
-
ApplicationContextInitializer:在 Spring 容器刷新之前执行,用于对上下文做初始化配置。-
```java public class MyApplicationContextInitializer implements ApplicationContextInitializer { @Override public void initialize(ConfigurableApplicationContext applicationContext) { System.out.println("ApplicationContextInitializer....initialized"); } } ```
-
作用:在项目还没有准备IOC容器之前,去检测资源是否存在
举例:
一、先理清核心概念:IOC 容器的 “准备阶段” vs “就绪阶段”
Spring Boot 启动流程中,IOC 容器(ApplicationContext)的生命周期可以简单分为两步:
容器准备阶段:只是创建了 ConfigurableApplicationContext 对象,但还没做任何核心初始化(比如扫描 Bean、加载配置、创建 Bean 实例);
容器就绪阶段:执行 refresh() 方法,完成 Bean 扫描、配置加载、依赖注入、Bean 初始化等核心操作,此时 IOC 容器才算真正可用。
ApplicationContextInitializer 的 initialize() 方法,就执行在容器准备阶段(创建后)、refresh () 执行前—— 也就是 “IOC 容器还没准备好” 的关键节点。
二、“检测资源是否存在” 的通俗理解
这句话的核心是:在 IOC 容器正式干活(加载 Bean、初始化组件)之前,先做 “前置检查”,避免容器启动到一半因为关键资源缺失而失败,典型场景比如:
public class CheckResourceInitializer implements ApplicationContextInitializer {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
// 检测核心配置文件是否存在
Resource resource = applicationContext.getResource("classpath:application-db.yml");
if (!resource.exists()) {
// 提前抛异常,终止启动,避免后续无效加载
throw new RuntimeException("核心配置文件 application-db.yml 不存在!");
}
System.out.println("核心配置文件检测通过");
}
}
-
SpringApplicationRunListener:监听 Spring Boot 应用启动的整个生命周期,在不同阶段触发回调。-
import org.springframework.boot.SpringApplicationRunListener; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.env.ConfigurableEnvironment; public class MySpringApplicationRunListener implements SpringApplicationRunListener { public MySpringApplicationRunListener(SpringApplication application, String[] args) { } @Override public void starting() { System.out.println("starting...项目启动中"); } @Override public void environmentPrepared(ConfigurableEnvironment environment) { System.out.println("environmentPrepared...环境对象开始准备"); } @Override public void contextPrepared(ConfigurableApplicationContext context) { System.out.println("contextPrepared...上下文对象开始准备"); } @Override public void contextLoaded(ConfigurableApplicationContext context) { System.out.println("contextLoaded...上下文对象开始加载"); } @Override public void started(ConfigurableApplicationContext context) { System.out.println("started...上下文对象刷新完成,应用启动完成"); } @Override public void running(ConfigurableApplicationContext context) { System.out.println("running...应用运行中,可接收请求"); } @Override public void failed(ConfigurableApplicationContext context, Throwable exception) { System.out.println("failed...应用启动失败,异常信息:" + exception.getMessage()); } }
-
-
CommandLineRunner和ApplicationRunner:在 Spring Boot 应用启动完成后执行,用于执行一些初始化任务,区别在于接收的参数类型不同。
作用:可以在spring启动的时候做缓存
启动流程分析
spring创建bean流程:
- JVM:new 对象 → 字段初始化 → 构造器体
- Spring:构造器结束后 → 再做 @Autowired 注入
你的问题就在于:在「字段初始化」这一步就访问了 @Autowired 字段,而这时 Spring 还没来得及给它注入,仍然是 null。
注解
Resource
概念:把spring容器里的对象注入到当前类中
使用方法:在属性上
@Resource
private UserService userService;
Component
概念:这个类是组件,spring可以创建对象并且管理它
使用方法:在类上
@Component
public class xx{}
controller层常用注解
RestController
概念:@Controller + @ResponseBody 的结合体,专门用于标识RESTful 风格的控制器,主要作用是处理 HTTP 请求并直接返回数据(如 JSON/XML),而非跳转页面。
RequestMapping
@RequestMapping 是 Spring MVC 中最基础、最核心的请求映射注解,作用是将特定的 HTTP 请求( URL 、请求方法、参数等)绑定到控制器的某个方法上,让 Spring 知道哪个方法来处理哪个请求。
GetMapping
限定仅处理 GET 请求的简化请求映射注解
RequestBody
@RequestBody 是 Spring MVC 中用于接收 HTTP 请求体中的数据(如 JSON/XML),并自动将其转换为对应的 Java 对象的注解
Valid
在参数上执行校验
Lazy
@Lazy 是 Spring 里一个控制 Bean 创建时机的注解。
不用的时候不创建,用到的时候才创建。解决循环依赖的问题
Lombok注解
两者均为Lombok注解,自动生成构造方法,简化代码:
-
@NoArgsConstructor:自动生成无参构造方法(无任何参数)。
-
@RequiredArgsConstructor:-
只为 final 字段和 @NonNull 标注的字段生成构造函数
-
其他字段不会被包含在构造函数中
- 适合用于依赖注入场景
-
-
@AllArgsConstructor:-
为所有字段生成构造函数
-
不管字段是否有 final 修饰符
-
包含类中的所有实例字段
-
Builder注解
提供构建者模式的支持
类
HttpServletRequest 是封装 HTTP 请求所有信息的核心接口(由 Web 容器实现),能获取请求行、参数、请求头、Cookie 等所有客户端请求数据;