SpringApplication
Spring Boot 驅動 Spring 應用上下文的引導類web
@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })public @interface SpringBootApplication { ...}複製代碼
@ComponentScan
: 它是版本引入的? Spring Framework 3.1spring
@EnableAutoConfiguration
: 激活自動裝配 @Enable
-> @Enable
開頭的編程
@EnableWebMvc
bash
@EnableTransactionManagement
app
@EnableAspectJAutoProxy
框架
@EnableAsync
ide
@SpringBootConfiguration
: 等價於 @Configuration
-> Configuration Class 註解spring-boot
@Component
-> @ComponentScan
性能
處理類 -> ConfigurationClassParser
單元測試
掃描類 ->
ClassPathBeanDefinitionScanner
ClassPathScanningCandidateComponentProvider
protected void registerDefaultFilters() { this.includeFilters.add(new AnnotationTypeFilter(Component.class)); ... }複製代碼
Dubbo @Service
-> 2.5.7 -> new AnnotationTypeFilter(Service.class);
@Component
@Service
@Componentpublic @interface Service { ...}複製代碼
@Repository
@Componentpublic @interface Repository { ...}複製代碼
@Controller
@Componentpublic @interface Controller { ...}複製代碼
@Configuration
@Componentpublic @interface Configuration { ...}複製代碼
註解驅動上下文 AnnotationConfigApplicationContext
, Spring Framework 3.0 開始引入的
@Configurationpublic class SpringAnnotationDemo { public static void main(String[] args) { // XML 配置文件驅動 ClassPathXmlApplicationContext // Annotation 驅動 // 找 BeanDefinition // @Bean @Configuration AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); // 註冊一個 Configuration Class = SpringAnnotationDemo context.register(SpringAnnotationDemo.class); // 上下文啓動 context.refresh(); System.out.println(context.getBean(SpringAnnotationDemo.class)); }}複製代碼
@SpringBootApplication
標註當前一些功能
@SpringBootApplication
@SpringBootConfiguration
@Configuration
@Component
SpringApplication
Spring Boot 應用的引導
基本寫法
SpringApplication springApplication = new SpringApplication(MicroservicesProjectApplication.class); Map<String,Object> properties = new LinkedHashMap<>(); //隨機獲取端口號 properties.put("server.port",0); springApplication.setDefaultProperties(properties); springApplication.run(args);複製代碼
new SpringApplicationBuilder(MicroservicesProjectApplication.class) // Fluent API // 單元測試是 PORT = RANDOM .properties("server.port=0") // 隨機向 OS 要可用端口 .run(args);複製代碼
@SpringBootApplicationpublic class MicroservicesProjectApplication { public static void main(String[] args) { SpringApplication springApplication = new SpringApplication(MicroservicesProjectApplication.class); Map<String,Object> properties = new LinkedHashMap<>(); properties.put("server.port",0); springApplication.setDefaultProperties(properties); ConfigurableApplicationContext context = springApplication.run(args); // 有異常? System.out.println(context.getBean(MicroservicesProjectApplication.class)); }}複製代碼
@SpringBootApplicationpublic class MicroservicesProjectApplication { public static void main(String[] args) { SpringApplication springApplication = new SpringApplication(MicroservicesProjectApplication.class); Map<String, Object> properties = new LinkedHashMap<>(); properties.put("server.port", 0); springApplication.setDefaultProperties(properties); // 設置爲 非 web 應用 springApplication.setWebApplicationType(WebApplicationType.NONE); ConfigurableApplicationContext context = springApplication.run(args); // 有異常? System.out.println(context.getBean(MicroservicesProjectApplication.class)); // 輸出當前 Spring Boot 應用的 ApplicationContext 的類名 System.out.println("當前 Spring 應用上下文的類:" + context.getClass().getName()); }}複製代碼
輸出結果:
當前 Spring 應用上下文的類:org.springframework.context.annotation.AnnotationConfigApplicationContext複製代碼
當不加以設置 Web 類型,那麼它採用推斷:
-> SpringAppliation()
-> deduceWebApplicationType()
第一次推斷爲 WebApplicationType.SERVLET
WebApplicationType.NONE
: 非 Web 類型
Servlet
不存在
Spring Web 應用上下文 ConfigurableWebApplicationContext
不存在
spring-boot-starter-web
不存在
spring-boot-starter-webflux
不存在
WebApplicationType.REACTIVE
: Spring WebFlux
DispatcherHandler
spring-boot-starter-webflux
存在
Servlet
不存在
spring-boot-starter-web
不存在
WebApplicationType.SERVLET
: Spring MVC
spring-boot-starter-web
存在
設置 webApplicationType 屬性 爲 WebApplicationType.NONE
Spring 事件
Spring 內部發送事件
ContextRefreshedEvent
ApplicationContextEvent
ApplicationEvent
refresh()
-> finishRefresh()
-> publishEvent(new ContextRefreshedEvent(this));
ContextClosedEvent
ApplicationContextEvent
ApplicationEvent
close()
-> doClose()
-> publishEvent(new ContextClosedEvent(this));
自定義事件
PayloadApplicationEvent
Spring 事件 都是 ApplicationEvent
類型
發送 Spring 事件經過 ApplicationEventMulticaster#multicastEvent(ApplicationEvent, ResolvableType)
Spring 事件的類型 ApplicationEvent
Spring 事件監聽器 ApplicationListener
Spring 事件廣播器 ApplicationEventMulticaster
實現類:SimpleApplicationEventMulticaster
Spring 事件理解爲消息
ApplicationEvent
至關於消息內容
ApplicationListener
至關於消息消費者、訂閱者
ApplicationEventMulticaster
至關於消息生產者、發佈者
@EnableAutoConfigurationpublic class SpringBootEventDemo { public static void main(String[] args) { new SpringApplicationBuilder(SpringBootEventDemo.class) .listeners(event -> { // 增長監聽器 System.err.println("監聽到事件 : " + event.getClass().getSimpleName()); }) .run(args) .close(); ; // 運行 }}複製代碼
ApplicationStartingEvent(1)
ApplicationEnvironmentPreparedEvent(2)
ApplicationPreparedEvent(3)
ContextRefreshedEvent
ServletWebServerInitializedEvent
ApplicationStartedEvent(4)
ApplicationReadyEvent(5)
ContextClosedEvent
ApplicationFailedEvent (特殊狀況)(6)
Spring Boot 事件監聽器
org.springframework.context.ApplicationListener=\org.springframework.boot.ClearCachesApplicationListener,\org.springframework.boot.builder.ParentContextCloserApplicationListener,\org.springframework.boot.context.FileEncodingApplicationListener,\org.springframework.boot.context.config.AnsiOutputApplicationListener,\org.springframework.boot.context.config.ConfigFileApplicationListener,\org.springframework.boot.context.config.DelegatingApplicationListener,\org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\org.springframework.boot.context.logging.LoggingApplicationListener,\org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener複製代碼
ConfigFileApplicationListener
監聽 ApplicationEnvironmentPreparedEvent
事件
從而加載 application.properties
或者 application.yml
文件
Spring Boot 不少組件依賴於 Spring Boot 事件監聽器實現,本質是 Spring Framework 事件/監聽機制
SpringApplication
利用
Spring 應用上下文(ApplicationContext)
生命週期控制 註解驅動 Bean
Spring 事件/監聽(ApplicationEventMulticaster
)機制加載或者初始化組件
q1:webApplicationType分爲三種都有什麼實用地方
q2:框架底層的事件是單線程麼?業務實現是否能夠使用事件去實現?若是使用事件實現會不會是否是會有性能問題?
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster { @Nullable private Executor taskExecutor; ...}複製代碼