一、@SpringBootApplication
@SpringBootApplication
是SpringBoot最核心的注解,一般标注在启动类的上面,它包含了@ComponentScan
、@SpringBootConfiguration
、@EnableAutoConfiguration
,下面逐一分析这三个注解。
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(JkExperimentApplication.class, args);
}
}
二、@ComponentScan、@Component
1. IoC容器扫描Bean
@Component
是标明哪个类被扫描进入Spring IoC容器。@ComponentScan
则是标明采用何种策略去扫描标记了@Component
的类型,注意:只会扫描当前包和其子包。
举个栗子:采用自定义策略进行扫描。
//自定义排查的扫描类
@ComponentScan(
excludeFilters = {
@Filter(type = FilterType.CUSTOM,classes = {TypeExcludeFilter.class}),
@Filter(type = FilterType.CUSTOM,classes = {AutoConfigurationExcludeFilter.class})
}
)
public @interface SpringBootApplication {
}
@Component
public class Cat implements Animal {
...
}
@Component
public class Dog implements Animal {
...
}
2.从IoC容器中读取Bean(依赖注入)
通过@Autowired
依赖注入从而获取容器中的实例。
Spring IoC容器是通过getBean方法获取对应Bean的,而getBean又支持根据类型(by type)或者根据名称(byname)。首先@Autowired
会根据类型找到对应的Bean,如果对应类型的Bean不是唯一的,那么它会根据其属性名称和Bean的名称进行匹配。如果匹配得上,就会使用该Bean;如果还无法匹配,就会抛出异常。
执行下面代码,IoC容器会抛出异常,因为Animal有Cat和Dog两种Bean。
@Autowired
private Animal animal=null;
解决方案1:
@Autowired
private Animal dog=null;
解决方案2:@Primary
,它是一个修改优先权的注解。
@Component
@Primary
public class Dog implements Animal {
...
}
注意:有时候@Primary也可以使用在多个类上,也许无论是猫还是狗都可能带上@Primary注解,其结果是IoC容器还是无法区分采用哪个Bean的实例进行注入。
解决方案3:@Quelifier
,与@Autowired
组合在一起使用。通过指定名称,再和类型一起找到Bean。
//在属性中使用
@Autowired
@Quelifier("dog")
private Animal animal=null;
//在构造方法中使用
@Component
public class Man implements Person {
private Animal animal=null;
public Man(@Autowired @Quelifier("dog") Animal animal){
this.animal=animal;
}
}
三、@SpringBootConfiguration
@SpringBootConfiguration
是一个复合注解,引入了@Configuration
。@Configuration
用于定义配置类,可以通过注解@Value
去获取application.properties
里面的配置项。
被注解的类内部也可以包含有一个或多个被@Bean
注解的方法,这些方法将会被AnnotationConfigApplication
或AnnotationConfigWebApplication
类进行扫描,并用于构建bean定义,初始化Spring IoC容器。
//MyConfiguration
@Configuration
public class MyConfiguration {
public MyConfiguration(){
System.out.println("容器初始化中....");
}
@Value("${user.name}")
private String userName;
@Bean
public User getUser(){
User user = new User();
user.setName(this.userName);
user.setPwd("123456");
return user;
}
}
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfiguration.class);
//从ioc 容器中获取bean
User user = (User) applicationContext.getBean("getUser");
System.out.println( user.toString());
}
四、@EnableAutoConfiguration@ComponentScan
只能扫描当前包和子包,只能加载当前包和子包的@Configuration
(@Configuration
引入了@Component
)。 而@EnableAutoConfiguration
可以帮助SpringBoot应用将所有符合条件的包括依赖的jar包的@Configuration配置都加载到当前SpringBoot创建并使用的IoC容器。@EnableAutoConfiguration
源码:
package org.springframework.boot.autoconfigure;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
其中最关键的要属@Import(AutoConfigurationImportSelector.class)
,在AutoConfigurationImportSelector
类中可以看到通过 SpringFactoriesLoader.loadFactoryNames()
把 spring-boot-autoconfigure.jar
和其他依赖jar包的/META-INF/spring.factorie
文件中标注的类都加载到容器中,(spring.factores:用来指导SpringBoot找到指定的配置文件。),
然后将其中对应的配置项通过反射实例化为对应标注了@Configration
的IoC容器配置类,最后汇总并加载到Spring框架的IoC容器中。