首先是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的理解不夠深刻,隨着以后的學習,也會不斷的對博客中的內容進行修改,完善。)