SpringBoot源码分析
1、Spring和springboot是关系是什么?
Springboot是spring就是最核心的产品之一(是spring的分支项目),当然就包含springmvc。springmvc 只是spring 处理web层请求的一个模块。
Springboot是构建在spring基础之上的一个产品,其主要目的就是简化spring框架中繁复的配置问题,用什么方式来解决的呢?
用注解和类完成的
无论使用spring还是springboot开发,其本质来说,springboot都是在做一件事情,就把项目中的bean初始化放入到spring的ioc容器中,springboot是构建在spring基础之上的一个解决方案(框架)。springboot提供了非常丰富的的初始化bean的解决方案:比如:@Configuration+Bean、SelectorImport机制 、@Enablexxx开关类等。
springboot不管如何使用都脱离不了springioc容器。
2、SpringBoot什么时候把这些所谓机制加载到ioc容器?
package com.example;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.example.mapper")
public class StudyBootsAdminApplication {
public static void main(String[] args) {
SpringApplication.run(StudyBootsAdminApplication.class, args);
}
}
在执行main函数启动时,就会调用类加载器去加载对应的bean,全部放入到到ioc容器中
2.1 什么是类加载器
SpringApplication.run(AdminApplication.class, args);
中的:AdminApplication.class
传递了一个类,目的是为了触发类加载器和通过反射找到主类上的注解@SpringBootApplication
。
2.2 可以传递别的类吗?
不可以,因为传递别的类,没办法去加载项目中bean和加载starter机制的类。
因为主类上有一个注解@SpringBootApplication
,这个注解是核心注解。它会去加载项目中对应的所有的bean,包含项目@Configuration+@Bean的初始化、@Import机制(starter)这些类等等。
为什么要触发类加载器?
- 可以获取上下文的环境,获取系统的信息
- 会加载pom.xml所有的依赖jar中编译好的类
- 会加载jdk对应api
传递类的作用:为了触发类加载和通过反射找到主类上的核心注解
@SpringBootApplication
,然后再触发springboot中的机制,把项目中和pom.xml中的依赖(starter和其他的依赖jar)、以及jdk的api全部初始化到内存中。其中springboot中通过@Configuration+@Bean的初始化、@SelectorImport机制(starter)和扫包+注解、@ImportResource加载配置文件都会放入到ioc容器中。
3、Springboot是如何做到所谓的零配置(少量配置文件)呢?
3.1 传统ssm方式
-
xml – applicationContext.xml
<bean id="xxx" class="xxxx"> <bean id="xxx" class="xxxx"> <bean id="xxx" class="xxxx"> <bean id="xxx" class="xxxx"> <bean id="xxx" class="xxxx">
-
扫包 + 注解
<component-scan basePackeges="com.kuangstudy.service"> <component-scan basePackeges="com.kuangstudy.mapper"> <component-scan basePackeges="com.kuangstudy.controller">
注解:@Service、@Controller、@RestContoller、@Respostity、@Component等
3.2 SpringBoot改进
-
扫包(注解) + 注解
@ComponentScan + 注解:@Service、@Controller、@RestContoller、@Respostity、@Component等
-
@Configuration+@Bean 配置类 + @Bean初始化
-
@Import机制
@Import(配置类&selector即可实现类,你也可以写普通bean) @Import(RedisConfiguration.class) @Import(UserService.class) @Import(AxxxxSelector.class)
-
@ImportResource
@ImportResource("classpath:applicationContext.xml")
-
抛弃传统的xml方式
-
可以集合整合传统的xml方式 通过@ImportResource来整合即可。不建议混合使用。
4、springboot提供的注解@SpringBootApplication
能够解决什么?作用是什么?
@SpringBootApplication
是一个复合注解:
- @Configuration+@Bean
- @SelectorImport机制
- @ImportResource
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
@Target(ElementType.TYPE) :jdk注解中代表当前注解只能使用类上面,注解使用范围
@Retention(RetentionPolicy.RUNTIME):代表该注解类的,可以通过反射获取到注解信息。、
@Documented jdk注解文档
@Inherited 允许注解继承
核心注解
@SpringBootConfiguration 等价于:@Configuration(@Component) + @Bean
@EnableAutoConfiguration 这个就是开关注解 + @SelectorImport机制来加载bean到ioc容器中
@ComponentScan+注解(@Service、@Controller、@RestController、@Component 、@Repository)
@EnableAutoConfiguration 就是开关注解 + @SelectorImport机制来加载bean到ioc容器中。同时它也是去加载项目中starter机制的注解。为什么要使用:@SelectorImport机制 + @Eablexxxxx这些机制呢?
5、@Configuration+@Bean加载到ioc容器的规则
前提:@Configuration+@Bean 必须配合:@ComponentScan
才能把对象的bean放入到ioc容器中。
为什么要配置@ComponentScan才能发挥效果?
通过@Configuration注解的源码如下可以得知:原理是一个@Component
。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration
@Configuraiton注解的类
被@Configuraiton注解的类叫配置类:一般是用来初始化bean到ioc容器中的一种机制。但是这个机制必须要配置扫包==@ComponentScan
==才能发挥作用。
-
配置类相当于:applicationContext.xml
-
配置类中@Bean节点相当于:applicationContext.xml中节点。
package com.example.entity;
/**
* @Auther: 长颈鹿
* @Date: 2021/08/03/9:22
* @Description:
*/
public class User {
private Integer id;
private String nickname;
private String password;
}
package com.example.service;
import com.example.entity.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
/**
* @Auther: 长颈鹿
* @Date: 2021/08/03/9:23
* @Description:
*/
@Slf4j
public class UserService {
@Autowired
private User user;
public void saveUser() {
log.info("你保存的用户是:{}", user);
}
}
package com.example.config;
import com.example.entity.User;
import com.example.service.UserService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
/**
* @Auther: 长颈鹿
* @Date: 2021/08/03/9:34
* @Description:
*/
@Configuration
public class UserConfiguration {
@Bean
@Primary
public User getUser(){
User user = new User();
user.setId(1);
user.setNickname("刘大");
user.setPassword("123456");
return user;
}
@Bean
public UserService getUserService(){
return new UserService();
}
}
package com.example;
import com.example.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class StudyBootsSourceApplicationTests {
@Autowired
private UserService userService;
@Test
void contextLoads() {
userService.saveUser();
}
}
6、@ComponentScan+注解(@Service、@Controller、@RestController、@Component 、@Repository)
默认情况:@ComponentScan默认的扫包范围是当前启动类的包。
作用:把该包下com.example;
的所有的子包和子孙包下面所有的符合条件的类(@Service、@Controller、@RestController、@Component 、@Repository)和 @Configuration类全部加载到ioc容器中。
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration<