Spring Framework
一种开发Java应用的框架
Spring Boot
在应用Spring Boot框架项目的结构中,除了对应Java的源代码外,在/src/main/resources目录下还应存在存放静态文件(如js等)的目录、存放html模板的目录以及各种配置文件。
Spring Boot默认使用的配置文件是application.yml,它的格式相比于properties更为简洁易读,通过缩进代表每一种配置的子配置。
例如,下面的properties配置:
1 2 3 4 5 6
| spring.application.name=${APP_NAME:unnamed}
spring.datasource.url=jdbc:mysql://localhost:3306/db spring.datasource.username=root spring.datasource.password=root spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
可更改为YAML格式:
1 2 3 4 5 6 7 8
| spring: application: name: ${APP_NAME:unnamed} datasource: url: jdbc:mysql://localhost:3306/db username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver
|
注意到这里的${APP_NAME:unnamed}代表先从系统的环境变量里查找APP_NAME这个变量,如果不存在则设为unnamed。
以某种特定的临时变量启动应用程序,可以通过如下方法:
1
| APP_NAME=mySpringApp java -jar app.jar
|
另一个必要的配置文件是日志配置文件logback-spring.xml或logback.xml,存放有关服务端日志记录的配置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| <?xml version="1.0" encoding="UTF-8"?> <configuration> <include resource="org/springframework/boot/logging/logback/defaults.xml" />
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>${CONSOLE_LOG_PATTERN}</pattern> <charset>utf8</charset> </encoder> </appender>
<appender name="APP_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender"> <encoder> <pattern>${FILE_LOG_PATTERN}</pattern> <charset>utf8</charset> </encoder> <file>app.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> <maxIndex>1</maxIndex> <fileNamePattern>app.log.%i</fileNamePattern> </rollingPolicy> <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> <MaxFileSize>1MB</MaxFileSize> </triggeringPolicy> </appender>
<root level="INFO"> <appender-ref ref="CONSOLE" /> <appender-ref ref="APP_LOG" /> </root> </configuration>
|
Java源代码存放于/src/main/java目录下,需要以package的形式存放。
Spring Boot要求存在main()方法的类必须要在包的根目录下,类的命名没有限制。注意在主类前添加一个@SpringBootApplication注解,以完成工程的自动配置和扫描。下面是一个示例:
1 2 3 4 5 6
| @SpringBootApplication public class App { public static void main(String[] args) throws Exception { SpringApplication.run(App.class,args); } }
|
如何映射静态文件的位置?可以添加一个名为WebMvcConfigurer的Bean:
1 2 3 4 5 6 7 8 9 10 11
| @Bean WebMvcConfigurer createWebMvcConfigurer() { return new WebMvcConfigurer() { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/static/**") .addResourceLocations("classpath:/static/"); } }; }
|
此时就可以直接运行Spring Boot程序了。
但是我们并没有像前面一样定义JdbcTemplate等Bean,它们是在哪里被装配的呢?
Spring Boot具有一大特点:AutoConfiguration,即自动创建和装配必要的Beans。
Profile条件
Spring Boot的YAML配置文件可以对每一种不同的Profile分别进行对应环境的配置。不同的配置应使用分隔符---隔开,且只应存在一个默认(default)配置。
下面是一个示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| spring: application: name: ${APP_NAME:unnamed}
server: port: ${APP_PORT:8080} --- spring: config: activate: on-profile: test
server: port: 8000 --- spring: config: activate: on-profile: production
server: port: 80
|
可以看到最开始的配置没有对on-profile参数进行设置,此项即为默认配置。
为了实现不同配置下的多态,我们可以定义一个接口或抽象类,再对不同的场景分别进行实现,并添加@Profile注解以供Spring识别。在没有提供配置的时候,默认选择default。
Conditional条件
@Conditional注解对于简单条件的使用过于繁琐,Spring Boot基于此将它进行了扩展以使使用更方便。
@ConditionalOnClass和@ConditionalOnMissingClass
根据是否存在指定的类以决定对应的Bean或配置类是否生效。
例:当同时存在ClassA和ClassB时才生效
1
| @ConditionalOnClass({ ClassA.class,ClassB.class })
|
@ConditionalOnBean和@ConditionalOnMissingBean
根据是否存在指定的Bean以决定对应的Bean或配置类是否生效。
例:当ClassA被实例化为Bean时才生效
1
| @ConditionalOnBean(ClassA.class)
|
@ConditionalOnProperty
根据配置文件中的设定决定对应的Bean或配置类是否生效。
例:当启用缓存配置时才生效
1
| @ConditionalOnProperty(name="app.cache.enabled",havingValue="true")
|
@ConditionalOnWebApplication和@ConditionalOnNotWebApplication
根据当前是否为Web环境决定Bean或配置类是否生效。
例:仅当为Web环境时生效
1
| @ConditionalOnWebApplication
|
@ConditionalOnExpression
当满足某个SpEL表达式时对应的Bean或配置类才生效。
例:同时满足启用缓存配置和指定的类存在两个条件
1 2 3
| @ConditionalOnExpression( "${app.cache.enabled}&&T(com.example.SomeClass).isAvailable()" )
|
@ConditionalOnResource
当某个指定的资源文件存在时对应的Bean或配置类才生效。
例:Classpath下存在config.properties文件才使Bean生效
1
| @ConditionalOnResource(resources="classpath:config.properties")
|
加载配置文件
我们知道,使用Spring加载文件时可以通过@Value注解注入。但是,如果在多个类中想要注入同一个配置内容时,重复使用@Value会导致不易调试和修改时难以维护的问题。因此,我们可以专门定义一个Bean来完成对配置文件的解析,再在需要加载配置的类中引入这个Bean。
对于这个Bean,假设我们有多个配置,如app.config下存在name、root-dir、server-addr等多个配置,我们需要把每个配置均注入Bean中。如果使用@Value注解会很麻烦。因此,Spring Boot提供了ConfigurationProperties注解,用于快速导入同一个配置项下的多个配置。只需要在配置类前添加即可:
1 2 3 4 5 6 7
| @Configuration @ConfigurationProperties("app.config") public class AppConfiguration { private String name; private String rootDir; private String serverAddr; }
|
需要注意的是,自动导入要求名称匹配。在YAML中的名称,转换到Java的变量时需要把短划线去掉并将其后面的字母改为大写字母。
这个Bean即可通过标准的方式注入其它类中。
过滤器(Filter)
Spring Boot提供了一个FilterRegistrationBean,在实例化时,它会调用其中的getFilter()函数,把返回的Filter注册到服务端容器中。
我们可以编写一个Bean,使其继承于FilterRegistrationBean,在其实例化时即可实现URL及认证等内容的过滤。