spring原理篇
由于楼主见识的局限性 故此小白和大佬都快跑
spring
1.起步依赖
<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
原理来自maven的依赖传递
2.自动配置
概述 :某些对象自动存入IOC容器
例子
比如:配置类GsonAutoConfiguration里面有一个bean,bean的名字叫gson,它的类型是Gson。 ->专门用来处理json数据
点击查看代码
@SpringBootTest
class ProgramApplicationTests {
@Autowired
private Gson gson;
@Test
void mmm()
{
String json = gson.toJson(Result.success());
System.out.println(json);
}
}
此处 我们没有手动将该gson对象放入ioc容器 但他确可以拿出来 这就是spring在启动时候 就完成了bean对象的创建
其实分析自动配置原理就是来解析在SpringBoot项目中,在引入依赖之后是如何将依赖jar包当中所定义的配置类以及bean加载到SpringIOC容器中的。
1.自写起步依赖
maven jar包
`@Component
public class TokenParser {
public void parse(){
System.out.println("TokenParser ... parse ...");
}
}`
@Autowired private ApplicationContext applicationContext; @Test public void testTokenParse(){ System.out.println(applicationContext.getBean(TokenParser.class)); }
报错 表示容器内没有找到这个bean
- 原因在我们之前讲解IOC的时候有提到过,在类上添加@Component注解来声明bean对象时,还需要保证@Component注解能被Spring的组件扫描到。
- SpringBoot项目中的@SpringBootApplication注解,具有包扫描的作用,但是它只会扫描启动类所在的当前包以及子包。
- 当前包:com.itheima, 第三方依赖中提供的包:com.example(扫描不到)
解决方法
- 方案1:@ComponentScan 组件扫描
- 方案2:@Import 导入(使用@Import导入的类会被Spring加载到IOC容器中
方案一 指定扫描
@ComponentScan({"com.example.program","com.example"})
但是每一个依赖包都要指定对应目录 太过麻烦 对此 进行方案2
@Import导入
1.普通类
@Import(TokenParser.class) 自己加入bean容器
2.配置类
点击查看代码
@Configuration
public class HeaderConfig {
@Bean
public HeaderParser headerParser(){
return new HeaderParser();
}
@Bean
public HeaderGenerator headerGenerator(){
return new HeaderGenerator();
}
}
启动类--放到任意地方都行的
@Import(HeaderConfig.class) //导入配置类
扫描到Bean 自动注册 其他地方就可以拿取该bean
3.使用@Import导入ImportSelector接口实现类:
点击查看代码
@Import(MyImportSelector.class)
public class MyImportSelector implements ImportSelector {
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.example.HeaderConfig"};//返回全类名
}
}
那两个 对象也会被加入进对应容器
你所提供的代码是Spring中ImportSelector接口的一个实现。ImportSelector接口是Spring的@Import注解处理的一部分,它允许我们动态加载(或导入)一些Spring的配置。
MyImportSelector类实现ImportSelector接口的selectImports方法,这个方法的作用是返回一个包含希望Spring加载的类全限定名称的字符串数组。
在你的例子中,selectImports方法返回一个字符串数组,包含一个元素"com.example.HeaderConfig"。这表示Spring会尝试将com.example.HeaderConfig这个类加载到Spring的应用上下文中。
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
我们使用@Import注解通过这三种方式都可以导入第三方依赖中所提供的bean或者是配置类。思考:如果基于以上方式完成自动配置,当要引入一个第三方依赖时,是不是还要知道第三方依赖中有哪些配置类和哪些Bean对象?
思考:当我们要使用第三方依赖,依赖中到底有哪些bean和配置类,谁最清楚?
- 答案:第三方依赖自身最清楚。
结论:我们不用自己指定要导入哪些bean对象和配置类了,让第三方依赖它自己来指定。‘’
怎么让第三方依赖自己指定bean对象和配置类?
- 比较常见的方案就是第三方依赖给我们提供一个注解,这个注解一般都以@EnableXxxx开头的注解,注解中封装的就是@Import注解
使用第三方依赖提供的 @EnableXxxxx注解
点击查看代码
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(MyImportSelector.class)//指定要导入哪些bean对象或配置类
public @interface EnableHeaderConfig {
}
前两个注解详解
@Retention: 这个注解决定了被修饰的注解信息在什么级别可用。
RetentionPolicy.SOURCE:注解只保留在源码中,编译时会被丢弃,不会写入字节码。
RetentionPolicy.CLASS:注解在编译时被保留在字节码中,但JVM加载类时不会将其加载到反射数据中,这是默认的生命周期。
RetentionPolicy.RUNTIME:注解在编译后也会被保存在字节码中,JVM加载类时将其加载到反射数据中,所以它们能在运行时被读取到。
因此,@Retention(RetentionPolicy.RUNTIME)意味着被修饰的注解在运行时仍然有效,可以通过反射机制读取到。
@Target: 这个注解用来指定被修饰的注解可以用在哪些元素上。元素类型包括:CONSTRUCTOR(构造器声明),FIELD(字段声明),LOCAL_VARIABLE(局部变量声明),METHOD(方法声明),PACKAGE(包声明),PARAMETER(参数声明), TYPE(类、接口或枚举声明)等。
所以,@Target(ElementType.TYPE)表示被修饰的注解只能用来修饰类、接口或枚举。
以上四种方式都可以完成导入操作,但是第4种方式会更方便更优雅,而这种方式也是SpringBoot当中所采用的方式。
源码跟踪
1.
@ServletComponentScan : 扫描servelt组件 过滤器 网址依赖webServlet
@SpringBootApplication :核心依赖 ->跟踪的依赖
@EnableHeaderConfig--自定义注解
2.
@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}
)}
)
解释 ---其实跟源码只需要关键词 但是第一层我还是都看一遍吧
@Target({ElementType.TYPE}):该注解意味着@SpringBootApplication只能用于类、接口或枚举类型。
@Retention(RetentionPolicy.RUNTIME):表示@SpringBootApplication注解会被保留在运行时,因此可以通过反射获取其信息。
@Documented:表明如果一个类使用了@SpringBootApplication注解,那么这个注解应该被包含在JavaDoc中。
@Inherited:表示@SpringBootApplication注解可以被子类继承。//配置类
@EnableAutoConfiguration:启动Spring Boot的自动配置机制。
@ComponentScan:使Spring Boot能够扫描当前类所在的包以及子包,查找Component,Configuration等。
-------倒数 2 依赖 是我们要看的bean自动注入 原理依赖都跟一遍看看
@EnableAutoConfiguration
@Target({ElementType.TYPE}) 元素
@Retention(RetentionPolicy.RUNTIME) 编译器是否存在
@Documented @Documented是Java中的一个元注解,用于标记另外的注解。它的作用是将被它标记的注解包含在JavaDoc中。这样当你生成JavaDoc时,所有被@Documented标记的注解都会被包含在生成的文档中。
@Inherited 这是一个Java元注解,表明这个注解可以被子类继承
@AutoConfigurationPackage 这是一个Spring Boot的内部注解,用于自动配置包扫描路径。Spring Boot将从声明@EnableAutoConfiguration的类的包开始,向下扫描包结构。
@Import({AutoConfigurationImportSelector.class}) 当然 我们需要看的还是这个注解
AutoConfigurationImportSelector.class
在META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports配置文件中指定了第三方依赖Gson的配置类:GsonAutoConfiguration
---这就是要加入ioc容器的类
这么多 不会累坏吗 spring怎么知道哪些要加入哪些不加入呢
org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration
->翻代码
@Bean
@ConditionalOnMissingBean
public Gson gson(GsonBuilder gsonBuilder) {
return gsonBuilder.create();
}
点击查看代码
@AutoConfiguration//表面该类是自动配置类
@ConditionalOnClass({Gson.class})//类的是否创建 类在类路径生效才生效
@EnableConfigurationProperties({GsonProperties.class})
public class GsonAutoConfiguration {
public GsonAutoConfiguration() {
}
@Bean
@ConditionalOnMissingBean//条件注解 这意味着只有当Spring容器中不存在类型为Gson 的Bean时,该方法返回的实例才会被注册为Bean。
public Gson gson(GsonBuilder gsonBuilder) {
return gsonBuilder.create();
}
条件注解详解
@Configuration
public class HeaderConfig {
@Bean
@ConditionalOnClass(name="io.jsonwebtoken.Jwts")//环境中存在指定的这个类,才会将该bean加入IOC容器
public HeaderParser headerParser(){
return new HeaderParser();
}
//省略其他代码...
}
理就是在配置类中定义一个@Bean标识的方法,而Spring会自动调用配置类中使用@Bean标识的方法,并把方法的返回值注册到IOC容器中。
@ConditionalOnMissingBean //不存在该类型的bean,才会将该bean加入IOC容器
@ConditionalOnMissingBean(name="deptController2")//不存在指定名称的bean,才会将该bean加入IOC容器
@ConditionalOnMissingBean(HeaderConfig.class)//不存在指定类型的bean,才会将bean加入IOC容器
@ConditionalOnProperty(name ="name",havingValue = "itheima")//配置文件中存在指定属性名与值,才会将bean加入IOC容器
百花争鸣的奇迹
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步