SpringBoot容器
1.@Configuration
告诉SpringBoot这是配置文件
@Configuration(proxyBeanMethods = true) public class MyConfig { @Bean//默认也是单实例的 public User user1() { return new User("ylc",22); } }
里面包含默认值proxyBeanMethods参数
proxyBeanMethods:代理bean的方法
- Full模式:proxyBeanMethods = true,通过方法调用依然指向原来的bean
- Lite模式:proxyBeanMethods = false,直接返回新实例对象
组件依赖(有二次调用)必须使用Full模式默认。其他默认是否Lite模式
/*这是一个Springboot应用*/ @SpringBootApplication(scanBasePackages = "com.ylc") public class MainApplication { public static void main(String[] args) { //返回IOC容器 ConfigurableApplicationContext context = SpringApplication.run(MainApplication.class,args); //从容器中获取组件 User user1 = context.getBean("user1", User.class); User user2 = context.getBean("user1", User.class); System.out.println(user1==user2); } }
最后为结果为true
不需要创建新组件时使用Lite模式,创建新组件时使用Full模式保证取得的组件为ioc中同一组件
2.@Import
@Import(DBHelper.class)//给容器中自动创建出这类型的组件、默认组件的名字就是全类名
3.@Condictional
条件装配:满足Conditional指定的条件才可以注入
例如@ConditionalOnBean
,在有某个bean的时候才会注入
如果注入b的时候需要依赖a那么它们直接就可以使用条件装配,这个发生在bean的注入之前
如果把该注解放在类上,不满足条件整个类里面包含的东西都不会注册到,存在先后顺序
4.@ImportResource
用于导入外部资源文件
@ImportResource("classpath:beans.xml")
5.@ConfigurationProperties
用于配置文件绑定
user.name="小明" user.age=12
5.1@Component+@ConfigurationProperties
只有这个组件是容器中的组件,才能使用容器提供的@ConfigurationProperties功能
@Component @ConfigurationProperties(prefix = "user")//user为配置文件的前缀名 public class User { public String name; public int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public User(String name, int age) { this.name = name; this.age = age; } public User() { } }
@RestController public class HelloWorldController { @Autowired User user; @RequestMapping("/GetUser") public User GetUser() { return user; } }
5.2 @EnableConfigurationProperties+@ConfigurationProperties
@EnableConfigurationProperties(Car.class) //1、开启Car配置绑定功能 //2、把这个Car这个组件自动注册到容器中 public class MyConfig { }
@ConfigurationProperties(prefix = "mycar") public class Car { public String CarType; public int Price; public Car(String carType, int price) { CarType = carType; Price = price; } public String getCarType() { return CarType; } public void setCarType(String carType) { CarType = carType; } public double getPrice() { return Price; } public void setPrice(int price) { Price = price; } public Car() { } }
6.@SpringBootApplication
@SpringBootApplication是一个合成注解,实际由以下注解组成
6.1 @SpringBootConfiguration
@SpringBootConfiguration
包含@Configuration注解表明这是一个配置类
6.2 @EnableAutoConfiguration(重要)
自动载入应用程序所需的所有Bean
@EnableAutoConfiguration
包含以下注解
6.2.1@AutoConfigurationPackage
将指定包下的所有组件导入进来,默认MainApplication类所在的包下
里面包含@Import({Registrar.class})
利用Registrar
给容器中导入一系列组件
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports { public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0])); } }
metadata
把注解源信息拿出来,然后通过getPackageNames
获取包名,把包名封装到数组里面,最后注册信息
6.2.2 @Import({AutoConfigurationImportSelector.class})
给容器中导入一个组件
AutoConfigurationImportSelector
类里面包含selectImports
方法,String[]最后用于存储要导入的包
public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!this.isEnabled(annotationMetadata)) { return NO_IMPORTS; } else { AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); } }
其中getAutoConfigurationEntry
方法,获取所有自动配置的集合
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) { if (!this.isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } else { AnnotationAttributes attributes = this.getAttributes(annotationMetadata); //获取所有候选的配置 然后将配置过滤 去重,最后再封装 List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes); configurations = this.removeDuplicates(configurations); Set<String> exclusions = this.getExclusions(annotationMetadata, attributes); this.checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = this.getConfigurationClassFilter().filter(configurations); this.fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions); } }
//获取所有候选的配置
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader()); Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct."); return configurations; }
其中loadFactoryNames
方法,利用工厂加载得到的所有组件
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) { ClassLoader classLoaderToUse = classLoader; if (classLoader == null) { classLoaderToUse = SpringFactoriesLoader.class.getClassLoader(); } String factoryTypeName = factoryType.getName(); return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList()); }
loadSpringFactories
这里搜索所有META-INF/spring.factories配置文件,将根据@EnableAutoConfiguration的完整类名org.springframework.boot.autoconfigure.EnableAutoConfiguration作为查找的Key,获取对应的一组@Configuration类,存储再Map中
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) { Enumeration urls = classLoader.getResources("META-INF/spring.factories"); }
从META-INF/spring.factories的位置来加载一个配置文件,默认扫描当前系统里面所有的信息
在spring-boot-autoconfigure-2.5.3.jar 包中的spring.factories文件中写死了SpringBoot启动要加载的所有配置
虽然所有自动配置启动的时候默认全部加载
xxxxAutoConfiguration 按照条件装配规则(@Conditional),最终会按需配置
6.3 @ComponentScan
@ComponentScan的功能其实就是自动扫描并加载符合条件的组件(比如@Component和@Repository等)或者bean定义,最终将这些bean定义加载到IoC容器中