SpringBoot : 給初學者的實用配置指引
一 基本使用
1 pom.xml
SpringBoot可以通過parent或dependencyManagement兩種方式引入。
1.1 parent方式
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.10.RELEASE</version>
</parent>
複製程式碼
因為很多時候我們需要引入自己專案的parent,所以這種引入方式不推薦。
1.2 dependencyManagement方式
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId >
<version>2.1.10.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
複製程式碼
dependencyManagement方式不幹擾自己的專案結構,推薦這種方式引入。
2 程式碼
//@EnableAutoConfiguration // 啟動自動配置
//@ComponentScan //掃描目錄
//@Configuration // 配置bean
@SpringBootApplication
public class SampleApp {
public static void main(String[] args){
SpringApplication app = new SpringApplication(SampleApp.class);
app.setBannerMode(Banner.Mode.OFF); // 關閉banner
app.run(args);
}
}
複製程式碼
或直接執行SpringApplication.run(SampleApp.class,args);
也可以啟動。
啟動標註說明:
-
@EnableAutoConfiguration : 啟用自動配置,可以指定exclude或excludeName進行指定或排除。 自動配置的模組可以參考:docs.spring.io/spring-boot…
-
@ComponentScan : 指定掃描目錄,如果不指定basePackages,則從當前類所在的包開始掃描
-
@Configuration : 配置bean的類,標註了@Configuration的類中,可以用@Bean宣告bean。
-
@SpringBootApplication = @EnableAutoConfiguration + @ComponentScan + @Configuration
二 宣告Bean
宣告bean有三種方式:
1 @Configuration & @Bean
在ComponentScan的basePackages目錄(預設為當前類所在的包)中,在類上標註@Configuration,使用@Bean標註方法來宣告bean。
@Bean中不指定name時,方法名會被作為bean的id。
@Configuration
public class Services {
@Bean
public UserService userService(){ // Bean的id是userService
return new UserService();
}
@Bean(name = "userService2") // Bean的id是userService2
public UserService getUserService(){
return new UserService();
}
}
複製程式碼
對於不在ComponentScan包中的,可以使用 @Import 引入
@SpringBootApplication
@Import({AnotherBeanConfiguration1.class,AnotherBeanConfiguration2.class})
public class SampleApp{
}
複製程式碼
2 @Service標註
在ComponentScan的包中,使用@Service標註類,bean的id預設是首字母小寫的類名。可以通過@Service的value指定。
@Service //bean的id是userService
public class UserService {
}
複製程式碼
3 xml方式
用@ImportResource引入xml檔案
@SpringBootApplication
@ImportResource(locations = {"classpath:/spring/*.xml"})
public class SampleApp{
}
複製程式碼
三 屬性檔案
所有的系統屬性可參考:docs.spring.io/spring-boot…
1 屬性檔案載入目錄
如果不呼叫SpringApplication.setDefaultProperties
,SpringBoot會從下面目錄載入application.properties:
- 1 當前目錄下的/config
- 2 當前目錄
- 3 classpath下的/config
- 4 classpath根目錄
引入額外的屬性檔案:
啟動類上新增標註:@PropertySource(value = {"classpath:/config/jdbc.properties"})
。
2 屬性檔案讀取
2.1 使用 @Value
多用於取單個屬性值,按照下面步驟可以將屬性檔案中的值讀取到Bean的屬性中:
-
- application.properties設定:
app.name=test.app
- application.properties設定:
-
- @Value("${app.name}") private String appName;
即可實現appName = "test.app"
。
屬性檔案, YAML檔案, 環境變數, 命令列引數中配置的值,都可通過@Value獲取。
2.2 使用 @ConfigurationProperties
例如,在application.properties中設定:
test.compnayinfo.id=123
test.compnayinfo.name=testname
複製程式碼
那麼在程式碼中可以這樣讀取屬性:
@Component
@ConfigurationProperties(prefix = "test.compnayinfo")
public class CompanyInfo{
private Integer id;
private String name;
// setters / getters
}
複製程式碼
通過指定ConfigurationProperties的prefix,CompanyInfo這個Bean的屬性值,已被屬性檔案裡的值初始化。
3 外部配置
優先順序如下:
- 1.Command line arguments. 如 --server.port=9000
- 2.Java System properties (System.getProperties()).
- 3.OS environment variables.
- 4.jar包外的 (application-{profile}.properties and YAML variants).
- 5.jar包內的 (application-{profile}.properties and YAML variants).
- 6.jar包外的 (application.properties and YAML variants).
- 7.jar包內的 (application.properties and YAML variants).
- 8.@PropertySource annotations on your @Configuration classes.
- 9.Default properties (預設是application.properties,可以通過呼叫SpringApplication.setDefaultProperties指定).
4 其它
命令列指定屬性檔案目錄:
java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties
Profile-specific properties:
- 1 application-{profile}.properties : 會覆蓋application.properties的屬性。
- 2 application.properties中指定:spring.profiles.active=profileName,或 在程式碼中指定 SpringApplication.setAdditionalProfiles(...)
Placeholders: app.name=MyApp app.description=${app.name} xxxxxx
四 Servlet Filters
宣告一個FilterRegistrationBean即可:
@Configuration
public class Filters {
@Bean
public FilterRegistrationBean filterRegistrationBean1(){
FilterRegistrationBean bean = new FilterRegistrationBean(new Filter() {
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("init filterRegistrationBean1");
}
public void doFilter(ServletRequest servletRequest,ServletResponse servletResponse,FilterChain filterChain) throws IOException,ServletException {
logger.info("doFilter filterRegistrationBean1");
filterChain.doFilter(servletRequest,servletResponse);
}
public void destroy() {
}
});
bean.setName("filterRegistrationBean1");
bean.setUrlPatterns(Collections.singletonList("/*"));
bean.setOrder(2);
return bean;
}
}
複製程式碼
五 Spring攔截器
繼承WebMvcConfigurerAdapter,並在覆蓋的addInterceptors方法中,新增HandlerInterceptorAdapter物件即可。
@Configuration
public class Interceptors extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new HandlerInterceptorAdapter() {
@Override
public boolean preHandle(HttpServletRequest request,HttpServletResponse response,Object handler) throws Exception {
System.out.println("first interceptor");
return super.preHandle(request,response,handler);
}
});
}
}
複製程式碼
六 https:
一般我們都是在nginx中啟用https,不需要在java應用中啟動。但如果需要,可以按照以下方式處理:
生成keystore:keytool -genkey -alias testkeystore -keystore keystore.jks -keyalg RSA
1 僅使用https(不使用http方式)
在屬性檔案中配置:
server.port=8443
server.ssl.key-store=classpath:keystore.jks
server.ssl.key-store-password=secret
server.ssl.key-password=another-secret
複製程式碼
2 新增https支援
需要新增一個支援https的connector,參考: docs.spring.io/spring-boot…
@Configuration
public class SampleTomcatTwoConnectorsService {
@Bean
public EmbeddedServletContainerFactory servletContainer() {
TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory();
tomcat.addAdditionalTomcatConnectors(createSslConnector());
return tomcat;
}
private Connector createSslConnector() {
Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
try {
File keystore = new ClassPathResource("test.keystore").getFile();
connector.setScheme("https");
connector.setSecure(true);
connector.setPort(8443);
protocol.setSSLEnabled(true);
protocol.setKeystoreFile(keystore.getAbsolutePath());
protocol.setKeystorePass("111111");
protocol.setKeyAlias("testkeystore");
}
catch (IOException ex) {
ex.printStackTrace();
}
return connector;
}
}
複製程式碼
七 靜態檔案及freemarker
1 靜態檔案
如果目錄為 resources/static:
則application.properties中配置: spring.mvc.static-path-pattern=/static/**
2 freemarker配置
預設的freemarker目錄:resources/freemarker,ftl檔案放到該目錄下即可。
application.properties中 spring.freemarker.*的配置:
spring.freemarker.cache=true
spring.freemarker.check-template-location=true
spring.freemarker.content-type=text/html
spring.freemarker.enabled=true
spring.freemarker.settings.template_update_delay=0
spring.freemarker.settings.default_encoding=UTF-8
複製程式碼
八 幾個有用的tips
1 PostConstruct
java.annotation.PostConstruct標註,Bean屬性設定完之後呼叫,效果同InitializingBean.afterPropertiesSet。
2 PreDestroy:
java.annotation.PreDestroy標註,Bean銷燬前呼叫,一般用於釋放資源 。效果同DisposableBean.destroy。
3 Runtime.addShutdownHook
以下幾種場景被呼叫:
1)程式正常結束退出
2)System.exit()
3)Ctrl+C
4)系統關閉
5)kill pid (kill -9 pid 不會呼叫hook)
如果想對Spring有一些更深入些的瞭解,可以參考之前的幾篇文章:Spring載入過程及核心類, Spring啟動和Bean建立過程中的可擴充套件介面, Spring自定義標籤配置的原始碼解析與實現 。