SpringBootApplication
org.springframework.boot.autoconfigure.@SpringBootApplication 注解
新建一个 Spring Boot 项目,进入启动类,一定会有这个注解:
- 标记了它是一个 Spring Boot 应用
- 开启自动配置
/**
* 直接复制源码过来,下面一一分析每个注解的作用
*/
/**
* Indicates a {@link Configuration configuration} class that declares one or more
* {@link Bean @Bean} methods and also triggers {@link EnableAutoConfiguration
* auto-configuration} and {@link ComponentScan component scanning}. This is a convenience
* annotation that is equivalent to declaring {@code @Configuration},
* {@code @EnableAutoConfiguration} and {@code @ComponentScan}.
*
* @author Phillip Webb
* @author Stephane Nicoll
* @author Andy Wilkinson
* @since 1.2.0
*/
@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 {
/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
@AliasFor(annotation = EnableAutoConfiguration.class)
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)
String[] excludeName() default {};
/**
* Base packages to scan for annotated components. Use {@link #scanBasePackageClasses}
* for a type-safe alternative to String-based package names.
* <p>
* <strong>Note:</strong> this setting is an alias for
* {@link ComponentScan @ComponentScan} only. It has no effect on {@code @Entity}
* scanning or Spring Data {@link Repository} scanning. For those you should add
* {@link org.springframework.boot.autoconfigure.domain.EntityScan @EntityScan} and
* {@code @Enable...Repositories} annotations.
* @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.
* <p>
* <strong>Note:</strong> this setting is an alias for
* {@link ComponentScan @ComponentScan} only. It has no effect on {@code @Entity}
* scanning or Spring Data {@link Repository} scanning. For those you should add
* {@link org.springframework.boot.autoconfigure.domain.EntityScan @EntityScan} and
* {@code @Enable...Repositories} annotations.
* @return base packages to scan
* @since 1.3.0
*/
@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {};
/**
* The {@link BeanNameGenerator} class to be used for naming detected components
* within the Spring container.
* <p>
* The default value of the {@link BeanNameGenerator} interface itself indicates that
* the scanner used to process this {@code @SpringBootApplication} annotation should
* use its inherited bean name generator, e.g. the default
* {@link AnnotationBeanNameGenerator} or any custom instance supplied to the
* application context at bootstrap time.
* @return {@link BeanNameGenerator} to use
* @see SpringApplication#setBeanNameGenerator(BeanNameGenerator)
* @since 2.3.0
*/
@AliasFor(annotation = ComponentScan.class, attribute = "nameGenerator")
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
/**
* Specify whether {@link Bean @Bean} methods should get proxied in order to enforce
* bean lifecycle behavior, e.g. to return shared singleton bean instances even in
* case of direct {@code @Bean} method calls in user code. This feature requires
* method interception, implemented through a runtime-generated CGLIB subclass which
* comes with limitations such as the configuration class and its methods not being
* allowed to declare {@code final}.
* <p>
* The default is {@code true}, allowing for 'inter-bean references' within the
* configuration class as well as for external calls to this configuration's
* {@code @Bean} methods, e.g. from another configuration class. If this is not needed
* since each of this particular configuration's {@code @Bean} methods is
* self-contained and designed as a plain factory method for container use, switch
* this flag to {@code false} in order to avoid CGLIB subclass processing.
* <p>
* Turning off bean method interception effectively processes {@code @Bean} methods
* individually like when declared on non-{@code @Configuration} classes, a.k.a.
* "@Bean Lite Mode" (see {@link Bean @Bean's javadoc}). It is therefore behaviorally
* equivalent to removing the {@code @Configuration} stereotype.
* @since 2.2
* @return whether to proxy {@code @Bean} methods
*/
@AliasFor(annotation = Configuration.class)
boolean proxyBeanMethods() default true;
}
@Inherited
Java 自带的注解。使用此注解,只有在类上使用时才会有效,对方法,属性等其他无效
@SpringBootConfiguration
Spring Boot 自定义注解:
继承自@Configuration 注解,所以两者功能一致,可以将当前类声明的一个或多个以@Bean 注解标记的方法的实例纳入到 Spring 容器中,并且实例名就是方法名。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {
@AliasFor(
annotation = Configuration.class
)
boolean proxyBeanMethods() default true;
}
@ComponentScan
Spring 自定义注解
扫描指定路径下的Component(@Component/@Configuration/@Service 等等)
@EnableAutoConfiguration
Spring Boot 自定义注解
用于开启自动配置功能,是 spring-boot-autoconfigure 项目最核心的注解
/**
* Enable auto-configuration of the Spring Application Context, attempting to guess and
* configure beans that you are likely to need. Auto-configuration classes are usually
* applied based on your classpath and what beans you have defined. For example, if you
* have {@code tomcat-embedded.jar} on your classpath you are likely to want a
* {@link TomcatServletWebServerFactory} (unless you have defined your own
* {@link ServletWebServerFactory} bean).
* <p>
* When using {@link SpringBootApplication @SpringBootApplication}, the auto-configuration
* of the context is automatically enabled and adding this annotation has therefore no
* additional effect.
* <p>
* Auto-configuration tries to be as intelligent as possible and will back-away as you
* define more of your own configuration. You can always manually {@link #exclude()} any
* configuration that you never want to apply (use {@link #excludeName()} if you don't
* have access to them). You can also exclude them via the
* {@code spring.autoconfigure.exclude} property. Auto-configuration is always applied
* after user-defined beans have been registered.
* <p>
* The package of the class that is annotated with {@code @EnableAutoConfiguration},
* usually via {@code @SpringBootApplication}, has specific significance and is often used
* as a 'default'. For example, it will be used when scanning for {@code @Entity} classes.
* It is generally recommended that you place {@code @EnableAutoConfiguration} (if you're
* not using {@code @SpringBootApplication}) in a root package so that all sub-packages
* and classes can be searched.
* <p>
* Auto-configuration classes are regular Spring {@link Configuration @Configuration}
* beans. They are located using the {@link SpringFactoriesLoader} mechanism (keyed
* against this class). Generally auto-configuration beans are
* {@link Conditional @Conditional} beans (most often using
* {@link ConditionalOnClass @ConditionalOnClass} and
* {@link ConditionalOnMissingBean @ConditionalOnMissingBean} annotations).
*
* @author Phillip Webb
* @author Stephane Nicoll
* @since 1.0.0
* @see ConditionalOnBean
* @see ConditionalOnMissingBean
* @see ConditionalOnClass
* @see AutoConfigureAfter
* @see SpringBootApplication
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
/**
* Environment property that can be used to override when auto-configuration is
* enabled.
*/
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 {};
}
@AutoConfigurationPackage
主要功能是自动配置包,它会获取主程序类所在的包路径,并将包路径(包括子包)下的所有组件注册到Spring IOC 容器中
@Import(AutoConfigurationImportSelector.class)
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
///
}
处理EnableAutoConfiguration 注解的资源导入
getCandidateConfigurations
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
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;
}
加载指定类型 EnableAutoConfiguration 对应的,在 META-INF/spring.factories
里的类名的数组
到这里基本就结束了。。。
实现一个 Starter
概述
其实 Starter 的核心就是条件注解 @Conditional :当 classpath 下存在某一个 Class 时,某个配置才会生效。
定义自己的 Starter
搭建项目
Starter 其实就是一个普通的 Maven 项目,因此我们自定义 Starter ,创建一个普通的 Maven 项目,创建完成后,添加 Starter 的自动化配置类即可,如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<version>2.6.8</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.6.8</version>
</dependency>
自定义配置类
创建一个 HelloPropertie 类,用来接收 application.properties 中注入的值,如下:
HelloProperties
package diyproperties;
@ConfigurationProperties(prefix = "diystarter")
public class HelloProperties {
private static final String DEFAULT_NAME = "你好";
private static final String DEFAULT_MSG = "Hello World";
private String name = DEFAULT_NAME;
private String msg = DEFAULT_MSG;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
这个配置类就是将 application.properties 文件中前缀为 diyStarter 的属性注入到这个类对应的属性上 「prefix 的 Value 值不能有大写」
HelloService
package service;
public class HelloService {
private String msg;
private String name;
public String sayHello() {
return name + " say " + msg + " !";
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
HelloServiceAutoConfiguration
package config;
import diyproperties.HelloProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import service.HelloService;
@Configuration
@EnableConfigurationProperties(HelloProperties.class)
@ConditionalOnClass(HelloService.class)
public class HelloServiceAutoConfiguration {
@Autowired
HelloProperties helloProperties;
@Bean
HelloService helloService(){
HelloService helloService=new HelloService();
helloService.setName(helloProperties.getName());
helloService.setMsg(helloProperties.getMsg());
return helloService;
}
}
- Configuration 注解表明是一个配置类
- EnableConfigurationProperties 使我们之前配置的 ConfigurationProperties 生效,让配置的属性成功进入 Bean 中
- ConditionalOnClass 表示当项目当前 classpath 下存在 HelloService 时,后面配置才生效
- 自动配置类中首先注入 HelloProperties 这个实例中含有我们在 application.properties 中配置的相关数据
- 提供一个 HelloService 的实例,将 HelloProperties 中的值注入进去。
spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=config.HelloServiceAutoConfiguration
自动配置类基本完成。
只需要写 src/main/java 下 packge/类名
本地安装
IDEA 中,点击右边的 Maven Project ,选择 install 即可。双击完成后,这个 Starter 就安装到我们本地仓库了。
使用 Starter
<dependency>
<groupId>org.example</groupId>
<artifactId>diystarter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
install 之后,在 target/maven-archiver/pom.properties 中里面有 groupId / artifactId / version
@RunWith(SpringRunner.class)
@SpringBootTest
public class TestDiyStarter {
@Autowired
HelloService helloService;
@Test
public void contextLoads() {
System.out.println(helloService.sayHello());
}
}
整个自定义 starter 完成