首先是springboot应用程序的入口类代码
@SpringBootApplication
public class HelloApplication {
public static void main(String[] args) {
SpringApplication.run(HelloApplication.class,args);
}
}
@SpringBootApplication注解的源码
/** *表明当前类是一个springboot项目 */
//标准该注解使用的目标,类,接口,抽象类等
@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 {
......
}
可以看出该注解是一个组合注解,主要由@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan三大注解组成,下面我们来一一分析这三大注解。
@SpringBootConfiguration
/**
* 表示当前类为一个SpringBoot应用程序
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
@AliasFor(annotation = Configuration.class)
boolean proxyBeanMethods() default true;
}
由上可以看出@SpringBootConfiguration注解作用是标注当前类是一个SpringBoot配置,所以在SpringBoot项目的main方法类中可以通过@Bean的方式注入bean。
@EnableAutoConfiguration
/**
* 启动Spring Application Context的自动配置,通过引入的jar(以启动器的方式),猜测需要自动配置
* 的bean
* 使用@SpringBootApplication注解时,将自动开启上下文的配置
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
/**
* Exclude specific auto-configuration classes such that they will never be applied. 排除特定的自动配置类,使其永远不会应用
* @return the classes to exclude
*/
Class<?>[] exclude() default {};
/**
* Exclude specific auto-configuration class names such that they will never be 排除特定的自动配置类名,使其永远不会应用
* applied.
* @return the class names to exclude
* @since 1.3.0
*/
String[] excludeName() default {};
}
该注解类似于Spring中其它的常见注解一样,字面意义为开启自动配置,但是该注解仍是一个组合注解,组成的两大注解一个是@AutoConfigurationPackage,@Import
@AutoConfigurationPackage
/**
* 表示自动配置包
* @Import注解,表示将AutoConfigurationPackages.Registrar导入容器中
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
}
AutoConfigurationPackages源码 参看博客(https://blog.csdn.net/andy_zhang2007/article/details/78652907)
/**
* Class for storing auto-configuration packages for reference later
* (e.g. by JPA entity scanner).
* 用于存储自动配置包以供以后参考的抽象类 (例如,通过JPA实体扫描器)
*/
public abstract class AutoConfigurationPackages {
//slfj日志
private static final Log logger = LogFactory.getLog(AutoConfigurationPackages.class);
private static final String BEAN = AutoConfigurationPackages.class.getName();
/**
* Determine if the auto-configuration base packages for the given
* bean factory are available.
* 确定给定bean工厂的自动配置基本软件包是否可用
* @param beanFactory the source bean factory
* @return true if there are auto-config packages available
*/
public static boolean has(BeanFactory beanFactory) {
return beanFactory.containsBean(BEAN) && !get(beanFactory).isEmpty();
}
/**
* Return the auto-configuration base packages for the given bean factory.
* 返回给定bean工厂的自动配置基本包
* @param beanFactory the source bean factory
* @return a list of auto-configuration packages
* @throws IllegalStateException if auto-configuration is not enabled
*/
public static List<String> get(BeanFactory beanFactory) {
try {
return beanFactory.getBean(BEAN, BasePackages.class).get();
}
catch (NoSuchBeanDefinitionException ex) {
throw new IllegalStateException("Unable to retrieve @EnableAutoConfiguration base packages");
}
}
/**
* Programmatically registers the auto-configuration package names. Subsequent
* invocations will add the given package names to those that have already been
* registered. You can use this method to manually define the base packages that will
* be used for a given {@link BeanDefinitionRegistry}. Generally it's recommended that
* you don't call this method directly, but instead rely on the default convention
* where the package name is set from your {@code @EnableAutoConfiguration}
* configuration class or classes.
* @param registry the bean definition registry
* @param packageNames the package names to set
*/
public static void register(BeanDefinitionRegistry registry, String... packageNames) {
if (registry.containsBeanDefinition(BEAN)) {
BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);
ConstructorArgumentValues constructorArguments = beanDefinition.getConstructorArgumentValues();
constructorArguments.addIndexedArgumentValue(0, addBasePackages(constructorArguments, packageNames));
}
else {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(BasePackages.class);
beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, packageNames);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(BEAN, beanDefinition);
}
}
private static String[] addBasePackages(ConstructorArgumentValues constructorArguments, String[] packageNames) {
String[] existing = (String[]) constructorArguments.getIndexedArgumentValue(0, String[].class).getValue();
Set<String> merged = new LinkedHashSet<>();
merged.addAll(Arrays.asList(existing));
merged.addAll(Arrays.asList(packageNames));
return StringUtils.toStringArray(merged);
}
/**
* {@link ImportBeanDefinitionRegistrar} to store the base package from
* the importing configuration.
* 用于存储导入配置的基本包
*/
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
register(registry, new PackageImport(metadata).getPackageName());
}
@Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new PackageImport(metadata));
}
}
/**
* Wrapper for a package import.
* 包装导入的包
*/
private static final class PackageImport {
private final String packageName;
PackageImport(AnnotationMetadata metadata) {
this.packageName = ClassUtils.getPackageName(metadata.getClassName());
}
String getPackageName() {
return this.packageName;
}
@Override
public boolean equals(Object obj) {
if (obj == null || getClass() != obj.getClass()) {
return false;
}
return this.packageName.equals(((PackageImport) obj).packageName);
}
@Override
public int hashCode() {
return this.packageName.hashCode();
}
@Override
public String toString() {
return "Package Import " + this.packageName;
}
}
/**
* Holder for the base package (name may be null to indicate no scanning).
*/
static final class BasePackages {
private final List<String> packages;
private boolean loggedBasePackageInfo;
BasePackages(String... names) {
List<String> packages = new ArrayList<>();
for (String name : names) {
if (StringUtils.hasText(name)) {
packages.add(name);
}
}
this.packages = packages;
}
List<String> get() {
if (!this.loggedBasePackageInfo) {
if (this.packages.isEmpty()) {
if (logger.isWarnEnabled()) {
logger.warn("@EnableAutoConfiguration was declared on a class "
+ "in the default package. Automatic @Repository and "
+ "@Entity scanning is not enabled.");
}
}
else {
if (logger.isDebugEnabled()) {
String packageNames = StringUtils.collectionToCommaDelimitedString(this.packages);
logger.debug("@EnableAutoConfiguration was declared on a class in the package '" + packageNames
+ "'. Automatic @Repository and @Entity scanning is enabled.");
}
}
this.loggedBasePackageInfo = true;
}
return this.packages;
}
}
}
@Import(AutoConfigurationImportSelector.class)
@Import表示导入AutoConfigurationImportSelector类中的元素。
AutoConfigurationImportSelector表示给容器导入非常多的自动配置类(xxxAutoConfiguration),给容器中导入这个场景需要的所有组件,并配置好这些组件
@ComponentScan配置扫描包范围,默认扫描当前类所在的包及其子包。
总结: @SpringBootApplication是springboot项目的核心注解,该注解是一个组合注解,由@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan三个注解组合而成,@SpringBootConfiguration注解表示当前类为一个SpringBoot配置类,所以可以在当前类中通过@Bean方式向容器中注入组件,@EnableAutoConfiguration注解则是表示开启自动配置,SpringBoot会根据我们导入的启动器猜测我们的需要的组件,帮我们自动导入和配置,@ComponentScan表示配置扫描包范围,默认扫描当前类所在包,以及其子包。
(由于笔者的水平有限,对SpringBoot的理解不够深刻,随着以后的学习,也会不断的对博客中的内容进行修改,完善。)
