• springboot学习笔记(二)


    首先我们来看一看,springboot启动类
    @RestController//@ResponseBody+@Controller
    @SpringBootApplication
    public class HelloWorldApplication {

    public static void main(String[] args) {
    SpringApplication.run(HelloWorldApplication.class, args);
    }

    @RequestMapping("/")
    public String helloSpring() {
    System.out.println("Hello");
    return "Hello springBoot";
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    没错引起我们关注的就是@SpringBootApplication这个注解,它是一个组合注解,接下来我们来看看@SpringBootApplication这个注解组成。

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented //配置类
    @Inherited //子类如果想使用父类注解信息,必须要使用此注解
    @SpringBootConfiguration //springboot配置
    @EnableAutoConfiguration //自动配置
    @ComponentScan(excludeFilters = {
    @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
    @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
    public @interface SpringBootApplication {

    /**
    * Exclude specific auto-configuration classes such that they will never be applied.
    * 排除指定的自动配置
    * @return the classes to exclude
    */
    @AliasFor(annotation = EnableAutoConfiguration.class, attribute = "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
    */
    @AliasFor(annotation = EnableAutoConfiguration.class, attribute = "excludeName")
    String[] excludeName() default {};

    /**
    * Base packages to scan for annotated components. Use {@link #scanBasePackageClasses}
    * for a type-safe alternative to String-based package names.
    * 扫描指定的基本包
    * @return base packages to scan
    * @since 1.3.0
    */
    @AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
    String[] scanBasePackages() default {};

    /**
    * Type-safe alternative to {@link #scanBasePackages} for specifying the packages to
    * scan for annotated components. The package of each class specified will be scanned.
    * <p>
    * Consider creating a special no-op marker class or interface in each package that
    * serves no purpose other than being referenced by this attribute.
    * @return base packages to scan
    * @since 1.3.0
    */
    @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
    Class<?>[] scanBasePackageClasses() default {};

    }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    可以看到@SpringBootApplication注解主要由@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan等注解组成,核心功能由@EnableAutoConfiguration注解提供。
    来看看它的源码

    @SuppressWarnings("deprecation")
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @AutoConfigurationPackage
    @Import(EnableAutoConfigurationImportSelector.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 {};

    }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    可以看到这里的关键是@Import注解导入的配置功能。还有排除自动配置使用的“exclude”方法是在这里定义的。

    接着看看@Import注解

    @Deprecated
    public class EnableAutoConfigurationImportSelector
    extends AutoConfigurationImportSelector {

    @Override
    protected boolean isEnabled(AnnotationMetadata metadata) {
    if (getClass().equals(EnableAutoConfigurationImportSelector.class)) {
    return getEnvironment().getProperty(
    EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class,
    true);
    }
    return true;
    }

    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    看到它继承了AutoConfigurationImportSelector这个类,还有是否是当前类的一个判断方法,是的话返回当前类的配置信息。
    接着看继承类AutoConfigurationImportSelector

    public class AutoConfigurationImportSelector
    implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
    BeanFactoryAware, EnvironmentAware, Ordered {

    private static final String[] NO_IMPORTS = {};

    private static final Log logger = LogFactory
    .getLog(AutoConfigurationImportSelector.class);

    private ConfigurableListableBeanFactory beanFactory;

    private Environment environment;

    private ClassLoader beanClassLoader;

    private ResourceLoader resourceLoader;

    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
    return NO_IMPORTS;
    }
    try {
    //从配置文件中加载信息
    AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
    .loadMetadata(this.beanClassLoader);

    AnnotationAttributes attributes = getAttributes(annotationMetadata);
    //得到所有的候选配置类
    List<String> configurations = getCandidateConfigurations(annotationMetadata,
    attributes);
    //去重
    configurations = removeDuplicates(configurations);
    //最初按字母排序,再按order排序
    configurations = sort(configurations, autoConfigurationMetadata);
    //返回不需要的配置项
    Set<String> exclusions = getExclusions(annotationMetadata, attributes);
    checkExcludedClasses(configurations, exclusions);
    //剔除不需要的配置
    configurations.removeAll(exclusions);
    //最后在进行一步过滤
    configurations = filter(configurations, autoConfigurationMetadata);
    //导入自动配置的监听器不为空,设置并初始化beanClassLoader,beanFactory,environment,resourceLoader
    fireAutoConfigurationImportEvents(configurations, exclusions);
    //返回最终需要的配置类
    return configurations.toArray(new String[configurations.size()]);
    }
    catch (IOException ex) {
    throw new IllegalStateException(ex);
    }
    }

    protected boolean isEnabled(AnnotationMetadata metadata) {
    return true;
    }

    /**
    * Return the appropriate {@link AnnotationAttributes} from the
    * {@link AnnotationMetadata}. By default this method will return attributes for
    * {@link #getAnnotationClass()}.
    * @param metadata the annotation metadata
    * @return annotation attributes
    */
    protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
    String name = getAnnotationClass().getName();
    AnnotationAttributes attributes = AnnotationAttributes
    .fromMap(metadata.getAnnotationAttributes(name, true));
    Assert.notNull(attributes,
    "No auto-configuration attributes found. Is " + metadata.getClassName()
    + " annotated with " + ClassUtils.getShortName(name) + "?");
    return attributes;
    }

    /**
    * Return the source annotation class used by the selector.
    * @return the annotation class
    */
    protected Class<?> getAnnotationClass() {
    return EnableAutoConfiguration.class;
    }

    /**
    * Return the auto-configuration class names that should be considered. By default
    * this method will load candidates using {@link SpringFactoriesLoader} with
    * {@link #getSpringFactoriesLoaderFactoryClass()}.
    * @param metadata the source metadata
    * @param attributes the {@link #getAttributes(AnnotationMetadata) annotation
    * attributes}
    * @return a list of candidate configurations
    */
    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
    AnnotationAttributes attributes) {
    //此方法用来扫描META-INF/spring.factories文件中的jar包
    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
    getSpringFactoriesLoaderFactoryClass(), 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;
    }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    好至此认识了@SpringBootApplication
    总结一下:

    首先是@enableautoconfiguration,@SpringBootApplication被@enableautoconfiguration注解.
    @enableautoconfiguration又被@import注解
    @import导入了EnableAutoConfigurationImportSelector(导入选择器),真正起作用的是AutoConfigurationImportSelector,getCandidateConfigurations方法用来扫描META-INF、spring.factories下的jar包,selectImports方法返回需要的配置类。
    核心注解
    先来看看spring.factories文件


    打开一个AutoConfiguration文件,都会有以下条件注解


    来看一个具体的条件注解,@ConditionOnWebAppLication

    @Target({ ElementType.TYPE, ElementType.METHOD })
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Conditional(OnWebApplicationCondition.class)
    public @interface ConditionalOnWebApplication {

    }
    1
    2
    3
    4
    5
    6
    7
    来看看它的具体实现类

    class OnWebApplicationCondition extends SpringBootCondition {

    private static final String WEB_CONTEXT_CLASS = "org.springframework.web.context."
    + "support.GenericWebApplicationContext";

    @Override
    public ConditionOutcome getMatchOutcome(ConditionContext context,
    AnnotatedTypeMetadata metadata) {
    //判断是否是元注解类
    boolean required = metadata
    .isAnnotated(ConditionalOnWebApplication.class.getName());
    //进行条件匹配结果
    ConditionOutcome outcome = isWebApplication(context, metadata, required);
    if (required && !outcome.isMatch()) {
    return ConditionOutcome.noMatch(outcome.getConditionMessage());
    }
    if (!required && outcome.isMatch()) {
    return ConditionOutcome.noMatch(outcome.getConditionMessage());
    }
    //返回匹配成功的条件信息
    return ConditionOutcome.match(outcome.getConditionMessage());
    }

    private ConditionOutcome isWebApplication(ConditionContext context,
    AnnotatedTypeMetadata metadata, boolean required) {
    ConditionMessage.Builder message = ConditionMessage.forCondition(
    ConditionalOnWebApplication.class, required ? "(required)" : "");
    //是否有webApplicationClasse实例
    if (!ClassUtils.isPresent(WEB_CONTEXT_CLASS, context.getClassLoader())) {
    return ConditionOutcome
    .noMatch(message.didNotFind("web application classes").atAll());
    }
    //容器是否有名为scopes的session
    if (context.getBeanFactory() != null) {
    String[] scopes = context.getBeanFactory().getRegisteredScopeNames();
    if (ObjectUtils.containsElement(scopes, "session")) {
    return ConditionOutcome.match(message.foundExactly("'session' scope"));
    }
    }
    //验证当前容器环境
    if (context.getEnvironment() instanceof StandardServletEnvironment) {
    return ConditionOutcome
    .match(message.foundExactly("StandardServletEnvironment"));
    }
    //当前ResourceLoader为WebApplicationContext
    if (context.getResourceLoader() instanceof WebApplicationContext) {
    return ConditionOutcome.match(message.foundExactly("WebApplicationContext"));
    }
    return ConditionOutcome.noMatch(message.because("not a web application"));
    }

    }

    --------------------- 

  • 相关阅读:
    grid 布局
    数组对象
    定义换页时表现
    判断一个对象是否为空
    内存管理 内存泄漏
    arguments对象
    String类型
    对象 实例
    iOS 之 UIWebView
    iOS 之 内嵌网页
  • 原文地址:https://www.cnblogs.com/hyhy904/p/11007504.html
Copyright © 2020-2023  润新知