1. 程式人生 > 程式設計 >SpringBoot : 給初學者的實用配置指引

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的屬性中:

    1. application.properties設定:app.name=test.app
    1. @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 外部配置

docs.spring.io/spring-boot…

優先順序如下:

  • 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自定義標籤配置的原始碼解析與實現