因为我忘性大所以就顺手做个笔记 希望二刷能让我学到一些新东西叭
留给我的时间已经8多了 希望到今年下半年我不至于去电子厂上班
这个注解是标志这个类归于springboot管理
@Configuration(proxyBeanMethods = true)
这个参数如果是true的话里面用的就都是IOC容器里面的同一个对象
如果是flase的话就每用一次就创建一个新的对象
/**
* 1、配置类里面使用@Bean标注在方法上给容器注册组件,默认也是单实例的
* 2、配置类本身也是组件
* 3、proxyBeanMethods:代理bean的方法
* Full(proxyBeanMethods = true)(保证每个@Bean方法被调用多少次返回的组件都是单实例的)(默认)
* Lite(proxyBeanMethods = false)(每个@Bean方法被调用多少次返回的组件都是新创建的)
*/
@Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件
public class MyConfig {
/**
* Full:外部无论对配置类中的这个组件注册方法调用多少次获取的都是之前注册容器中的单实例对象
* @return
*/
@Bean //给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例
public User user01(){
User zhangsan = new User("zhangsan", 18);
//user组件依赖了Pet组件
zhangsan.setPet(tomcatPet());
return zhangsan;
}
@Bean("tom")
public Pet tomcatPet(){
return new Pet("tomcat");
}
}
结果是
确实在IOC容器中能找到
mypersion是用Bean注入的
那个长的是通过Import注入的
这个注解的意思是如果IOC容器没有mypet这个对象的话这些bean就都不会注入
<beans ...">
<bean id="haha" class="com.lun.boot.bean.User">
<property name="name" value="zhangsan">property>
<property name="age" value="18">property>
bean>
<bean id="hehe" class="com.lun.boot.bean.Pet">
<property name="name" value="tomcat">property>
bean>
beans>
@ImportResource("classpath:beans.xml")
public class MyConfig {
...
}
public static void main(String[] args) {
//1、返回我们IOC容器
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
boolean haha = run.containsBean("haha");
boolean hehe = run.containsBean("hehe");
System.out.println("haha:"+haha);//true
System.out.println("hehe:"+hehe);//true
}
注入我们必须要把我们要注入的给放到springboot核心配置文件中去
@Data
@AllArgsConstructor
@NoArgsConstructor
@Component //把这个类放到容器中
@ConfigurationProperties(prefix="mycar") //读取配置文件中的mycar并把数值给赋给brand和price
public class Car {
private String brand;
private Integer price;
@Override
public String toString() {
return "Car{" +
"brand='" + brand + '\'' +
", price=" + price +
'}';
}
}
如果我们用第三方库的话我们不能再第三方库上面+@Component
所以我们可以再springboot的运行类上面加上@EnableConfigurationProperties
@SpringBootApplication 是由下面三个注解组成的
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication{}
这个注解实际上是一个@Configuration注解
这个注解是标志这个类归于springboot管理 前面已经说过这个注解了
代表当前的类是一个配置类
代表我们要扫描那些包
它实际上是一个 Import注解(作用是给容器中导入一个组件)
这个Registrar的作用是批量导入一系列的包 因为源码太长就不放了
既然它是指定包 导入那么它指定的是那个包?
答案当然是
这个包辣
这样也就解释了一个问题 为什么不在这个启动类下的包扫描不到
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
我们进入这个方法就可以看到这个configuration经过了一系列的操作
比如取出并且去掉相同的这些操作最终得到了我们要导入到容器中的组件
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);
}
}
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
我们进入getCandidateConfigurations()这个方法看一下 它是利用加载工厂配置的
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;
}
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
} else {
try {
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result = new LinkedMultiValueMap();
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();
while(var6.hasNext()) {
Entry<?, ?> entry = (Entry)var6.next();
String factoryTypeName = ((String)entry.getKey()).trim();
String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
int var10 = var9.length;
for(int var11 = 0; var11 < var10; ++var11) {
String factoryImplementationName = var9[var11];
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
cache.put(classLoader, result);
return result;
} catch (IOException var13) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
}
}
}
打个断点看看
看这个
我们的资源文件的位置就是在这里
也就是说默认扫描我们当前系统里面的所有
这个位置的文件
还有这个包
这就是上面我们加载的127个配置类
文件里面写死了springboot已启动要加载的127个配置类
这些配置类几乎覆盖了springboot的所有应用场景
我们在启动类里面看看到底加载了几个
加载了127个再加上我们自己加入的肯定不止129个 也就是说有一部分并没有进入到容器中
我们前面提到过 这个是条件注解
也就是说这个AOP只有在导入Advice这个包的前提之下才会加入容器中
给容器添加组件的一些注解