@SpringBootApplication註解分析
首先我們分析的就是入口類Application
的啟動註解@SpringBootApplication
,進入原始碼:
@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 { .... }
發現@SpringBootApplication
是一個複合註解,包括@ComponentScan
,和@SpringBootConfiguration
,@EnableAutoConfiguration
。
@SpringBootConfiguration
繼承自@Configuration
,二者功能也一致,標註當前類是配置類,並會將當前類內宣告的一個或多個以@Bean
註解標記的方法的例項納入到srping
容器中,並且例項名就是方法名。@EnableAutoConfiguration
的作用啟動自動的配置,@EnableAutoConfiguration
註解的意思就是Springboot
根據你新增的jar包來配置你專案的預設配置,比如根據spring-boot-starter-web
,來判斷你的專案是否需要添加了webmvc
和tomcat
,就會自動的幫你配置web專案中所需要的預設配置。在下面部落格會具體分析這個註解,快速入門的demo實際沒有用到該註解。@ComponentScan
,掃描當前包及其子包下被@Component
,@Controller
,@Service
,@Repository
註解標記的類並納入到spring容器中進行管理。是以前的<context:component-scan>
(以前使用在xml中使用的標籤,用來掃描包配置的平行支援)。所以本demo中的User為何會被spring
容器管理。
根據上面的理解,上面的入口類Application
,我們可以使用:
package com.zhihao.miao;
import com.zhihao.miao.bean.User;
import org.springframework.boot.SpringApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import java.util.Map;
@ComponentScan
public class Application {
@Bean
public Runnable createRunnable(){
return () -> System.out.println("spring boot is running");
}
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(Application.class,args);
context.getBean(Runnable.class).run();
System.out.println(context.getBean(User.class));
Map map = (Map) context.getBean("createMap");
int age = (int) map.get("age");
System.out.println("age=="+age);
}
}
使用@ComponentScan
註解代替@SpringBootApplication
註解,也可以正常執行程式。原因是@SpringBootApplication
中包含@ComponentScan
,並且springboot
會將入口類看作是一個@SpringBootConfiguration
標記的配置類,所以定義在入口類Application
中的Runnable
也可以納入到容器管理。
SpringBootApplication引數詳解
圖片.png
- Class<?>[] exclude() default {}:
根據class來排除,排除特定的類加入spring容器,傳入引數value型別是class型別。- String[] excludeName() default {}:
根據class name來排除,排除特定的類加入spring容器,傳入引數value型別是class的全類名字串陣列。- String[] scanBasePackages() default {}:
指定掃描包,引數是包名的字串陣列。- Class<?>[] scanBasePackageClasses() default {}:
掃描特定的包,引數類似是Class型別陣列。
看一個demo學會使用這些引數配置
在包下com.zhihao.miao.springboot定義一個啟動應用類(加上@SpringBootApplication註解)
package com.zhihao.miao.springboot;
import com.zhihao.miao.beans.Cat;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext context =SpringApplication.run(Application.class,args);
Cat cat = context.getBean(Cat.class);
System.out.println(cat);
}
}
在com.zhihao.miao.beans包下定義一個實體類,並且想將其納入到spring容器中,
public class Cat {
}
package com.zhihao.miao.beans;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyConfig {
@Bean
public Cat cat(){
return new Cat();
}
}
啟動啟動類,列印結果如下:
說明Cat類並沒有納入到spring容器中,這個結果也如我們所想,因為@SpringBootApplication只會掃描@SpringBootApplication註解標記類包下及其子包的類(特定註解標記,比如說@Controller,@Service,@Component,@Configuration和@Bean註解等等)納入到spring容器,很顯然MyConfig不在@SpringBootApplication註解標記類相同包下及其子包的類,所以需要我們去配置一下掃包路徑。
修改啟動類,@SpringBootApplication(scanBasePackages = "com.zhihao.miao"),指定掃描路徑:
package com.zhihao.miao.springboot;
import com.zhihao.miao.beans.Cat;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication(scanBasePackages = "com.zhihao.miao")
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext context =SpringApplication.run(Application.class,args);
Cat cat = context.getBean(Cat.class);
System.out.println(cat);
}
}
啟動並列印:
當然使用@SpringBootApplication(scanBasePackageClasses = MyConfig.class),指定scanBasePackageClasses引數的value值是你需要掃描的類也可以,結果一樣,不過如果多個配置類不在當前包及其子包下,則需要指定多個。
再看一個列子,
在上面的列子的相同包下(com.zhihao.miao.springboot)配置了People,並將其納入到spring容器中(@Component),我們知道@SpringBootApplication註解會掃描當前包及其子包,所以People類會納入到spring容器中去,我們需要將其排除在spring容器中,如何操作?
可以使用@SpringBootApplication的另外二個引數(exclude或excludeName)
package com.zhihao.miao.springboot;
import org.springframework.stereotype.Component;
@Component
public class People {
}
啟動類,
package com.zhihao.miao.springboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext context =SpringApplication.run(Application.class,args);
People people = context.getBean(People.class);
System.out.println(people);
}
}
啟動並列印結果:
然後修改@SpringBootApplication配置,
package com.zhihao.miao.springboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication(exclude = People.class)
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext context =SpringApplication.run(Application.class,args);
People people = context.getBean(People.class);
System.out.println(people);
}
}
很明顯啟動報錯。使用@excludeName註解也可以。如下,
@SpringBootApplication(excludeName = {"com.zhihao.miao.springboot.People"})
參考文件:
Springboot1.5.4官方文件
原文地址:https://www.cnblogs.com/duanxz/p/3756364.html