Shiro: 1.4.0
JDK: 1.8
SpringBoot: 1.5.10.RELEASE
SpringBoot 启动会扫描以下位置的 application.properties 或 application.yml 文件作为 SpringBoot 的默认配置文件。
1 | - file:./config/ |
优先级从高到低
所有位置的文件都会被加载,高优先级配置的内容会覆盖低优先级配置的内容,若内容不同,则会都加载
改变配置优先级
通过配置 spring.config.location
来改变默认配置
JDK: 1.8
SpringBoot: 1.5.10.RELEASE
Profile 是 Spring 针对不同环境提供不同配置功能的支持,可以通过激活指定参数等方式快速切换环境配置。
properties
applicaiton.properties
1 | server.port=8081 |
application-dev.properties
1 | server.port=8082 |
application-prod.properties
1 | server.port=8083 |
yml
application.yml
1 | server: |
application-dev.yml
1 | server: |
application-prod.yml
1 | server: |
YAML 可以通过 ---
表示多个文档块,并且通过 spring.profiles 指定各个文档块的 profiles 环境
1 | server: |
在默认配置文件中指定
application.properties:
1 | spring.profiles.active=dev |
application.ym:
1 | spring: |
命令行指定
1 | --spring.profiles.active=dev |
1 | java -jar XXX.jar --spring.profiles.active=dev |
JVM 参数指定
1 | -Dspring.profiles.active=dev |
本次选择的 SpringBoot 版本是1.5.9.RELEASE
打开 IDEA ,点击 File -> New -> Project -> Spring Initializr
选择Project SDK: JDK 1.8
选择Initializr Service URL: Default
点击 Next,等待一会,有时会提示 Initialization failed,重新尝试即可
修改Group、Artifact 即可,可以适当调整一下Package
添加起步依赖:Web starter 依赖
配置工程名称及工程存放路径
生成的项目目录结构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
32
33
34<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
默认的pom.xml 文件内主要内容:
parent 标签表示从 spring-boot-starter-parent 继承的版本号
properties 标签内定义编码格式,jdk 版本
dependencies 标签表示使用哪些起步依赖
build 标签表示使用哪些插件
1 | package com.example.springboot.hello; |
@SpringBootApplication 注解是一个组合注解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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55package org.springframework.boot.autoconfigure;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.core.annotation.AliasFor;
@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 {
@AliasFor(
annotation = EnableAutoConfiguration.class,
attribute = "exclude"
)
Class<?>[] exclude() default {};
@AliasFor(
annotation = EnableAutoConfiguration.class,
attribute = "excludeName"
)
String[] excludeName() default {};
@AliasFor(
annotation = ComponentScan.class,
attribute = "basePackages"
)
String[] scanBasePackages() default {};
@AliasFor(
annotation = ComponentScan.class,
attribute = "basePackageClasses"
)
Class<?>[] scanBasePackageClasses() default {};
}
其包含如下三个注解:
@Configuration : 表示该类使用Spring基于Java配置
@ComponentScan : 启用组件扫描
@EnableAutoConfiguration : Spring Boot 魔力来源,启用自动配置
src/main/java/com/example/springboot/hello/controller/HellController.java1
2
3
4
5
6
7
8
9
10
11
12
13
14
15package com.example.springboot.hello.controller;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
@RestController
public class HelloController {
@RequestMapping(value = "/index", method = RequestMethod.GET)
public String index() {
return "Greetings from Spring Boot!";
}
}
@RestController 注解表示该Controller是RESTful风格接口
@RequestMapping 注解定义请求URL和请求方法
有很多种方式可以运行 SpringBoot Application。
开发过程中可以直接执行 Application main 方法,或者 通过maven install 方式启动
打包可以通过maven package 打包
打包后运行可以通过java -jar XXX.jar 方式运行可执行 jar 包
一般控制台可以看到如下输出: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 . ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.5.9.RELEASE)
2017-11-29 14:46:28.397 INFO 9916 --- [ main] c.e.s.hello.SpringBootHelloApplication : Starting SpringBootHelloApplication on DESKTOP-1MESJ85 with PID 9916 (started by Richard in D:\lxmuse-spring-boot\building an application with spring boot\spring-boot-hello)
2017-11-29 14:46:28.400 INFO 9916 --- [ main] c.e.s.hello.SpringBootHelloApplication : No active profile set, falling back to default profiles: default
2017-11-29 14:46:28.492 INFO 9916 --- [ main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@5e955596: startup date [Wed Nov 29 14:46:28 CST 2017]; root of context hierarchy
2017-11-29 14:46:29.600 INFO 9916 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2017-11-29 14:46:29.608 INFO 9916 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2017-11-29 14:46:29.609 INFO 9916 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.23
2017-11-29 14:46:29.672 INFO 9916 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2017-11-29 14:46:29.673 INFO 9916 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1187 ms
2017-11-29 14:46:29.761 INFO 9916 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
2017-11-29 14:46:29.764 INFO 9916 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
2017-11-29 14:46:29.764 INFO 9916 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2017-11-29 14:46:29.765 INFO 9916 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2017-11-29 14:46:29.765 INFO 9916 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*]
2017-11-29 14:46:29.999 INFO 9916 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@5e955596: startup date [Wed Nov 29 14:46:28 CST 2017]; root of context hierarchy
2017-11-29 14:46:30.037 INFO 9916 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/index],methods=[GET]}" onto public java.lang.String com.example.springboot.hello.controller.HelloController.index()
2017-11-29 14:46:30.040 INFO 9916 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2017-11-29 14:46:30.041 INFO 9916 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2017-11-29 14:46:30.062 INFO 9916 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-11-29 14:46:30.062 INFO 9916 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-11-29 14:46:30.085 INFO 9916 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-11-29 14:46:30.168 INFO 9916 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2017-11-29 14:46:30.206 INFO 9916 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2017-11-29 14:46:30.212 INFO 9916 --- [ main] c.e.s.hello.SpringBootHelloApplication : Started SpringBootHelloApplication in 2.122 seconds (JVM running for 3.326)
同理有很多种方式可以访问 SpringBoot Application。
如果是 GET 请求,可以直接通过浏览器访问
如果是 其他 请求,可以使用浏览器REST client 模拟请求,或者使用 PostMan 等软件模拟请求
使用 PostMan 发起 GET 请求,地址是:localhost:8080/index
SpringBoot 工程默认的地址是localhost:8080
可以看到返回结果是 Greetings from Spring Boot!
1 | package com.example.springboot.hello; |
也可以对 HelloController 做单独的单元测试: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
32
33
34
35
36
37
38
39
40
41package com.example.springboot.hello.controller;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
import java.net.URL;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.embedded.LocalServerPort;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class HelloControllerTest {
@LocalServerPort
private int port;
private URL base;
@Autowired
private TestRestTemplate template;
@Before
public void setUp() throws Exception {
this.base = new URL("http://localhost:" + port + "/index");
}
@Test
public void testIndex() throws Exception {
ResponseEntity<String> response = template.getForEntity(base.toString(),
String.class);
assertThat(response.getBody(), equalTo("Greetings from Spring Boot!"));
}
}
具体代码已上传GitHub-lxmuse
是否 Lazy 初始化: 是
是否多线程安全: 否
实现难度: 容易
该方式最大的问题就是不支持多线程
1 | public class Singleton { |
是否 Lazy 初始化: 是
是否多线程安全: 是
实现难度: 容易
该方式最大的问题是效率低,因为加锁仅仅只是对第一调用起效,99% 情况下实际不需要同步
1 | public class Singleton { |
是否 Lazy 初始化: 否
是否多线程安全: 是
实现难度: 容易
该方式最大的问题是类加载时就初始化,浪费内存
1 | public class Singleton { |
JDK 版本: JDK 1.5+
是否 Lazy 初始化: 是
是否多线程安全: 是
实现难度: 一般
该方式最大的问题是需要 JDK 1.5 及 JDK 1.5 以后
1 | public class Singleton { |
是否 Lazy 初始化: 是
是否多线程安全: 是
实现难度: 一般
1 | public class Singleton { |
该方式和 饿汉式 不同之处是支持 Lazy 初始化的,只有当第一次被调用时才会初始化
JDK 版本: JDK 1.5+
是否 Lazy 初始化: 否
是否多线程安全: 是
实现难度: 容易
该方式是 Effective Java 作者 Josh Bloch 推荐的方式,是实现单例模式最佳的方式。简洁,自动支持序列化机制,绝对防止多次实例化。最大的问题是需要 JDK 1.5 及 JDK 1.5 以后
1 | public enum Singleton { |
一般情况下,不建议使用第 1 种和第 2 种懒汉方式,建议使用第 3 种饿汉方式。只有在要明确实现 lazy loading 效果时,才会使用第 5 种登记方式。如果涉及到反序列化创建对象时,可以尝试使用第 6 种枚举方式。如果有其他特殊的需求,可以考虑使用第 4 种双检锁方式。
单例模式是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
单例模式的标准定义如下:
Ensure a class has only one instance, and provide a global point of access to it.
确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
注意:
实现关键:构造函数是私有的
单例模式通用代码
1 | public class Singleton { |
单例模式的优点
单例模式的缺点
单例模式使用场景
单例模式的注意事项
Java 中每个原始类型都有一个对应的包装类型:
基本类型 | 包装类型 |
---|---|
boolean | Boolean |
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Char |
包装类的必要性:
包装类与基本类型的转换
包装类与基本类型的转换代码结构都是类似的,每种包装类都有一个静态方法 valueOf() 接受基本类型,返回引用类型,也有一个实例方法 xxValue() 方法返回对应的基本类型。
以 boolean 和 Boolean 转换为例:
1 | boolean b1 = false; |
装箱:将基本类型转换为包装类型的过程
拆箱:将包装类型转换为基本类型的过程
Java 5 引入了自动装箱和自动拆箱的机制,该机制由编译器提供,实际依旧调用了对应的valueOf()方法和 xxxValue() 方法。
每种包装类也支持通过构造函数实例化,但是不推荐使用,构造函数会创建一个新对象,而很多包装类内部都会缓存包装类对象。
包装类的共同点
Number类
Number 类是所有包装类的抽象类,定义了如下方法,用于包装类返回任意类型的基本数据类型:
1 | byte byteValue(); |
不可变性
包装类都是不可变类:
Spring Framework:4.3.14.RELEASE
Spring IOC 容器可以管理容器中 Bean 的生命周期。
容器中 Bean 的生命周期:
这样一个类:
1 |
|
1 | <?xml version="1.0" encoding="UTF-8" ?> |
在容器启动时,可以看到 构造函数 Car() 最先被执行,然后是 SetBrand() 方法被执行,其次是 init() 方法被执行,当容器被关闭时,destrory() 方法被执行。
Spring Framework 中 bean 标签中有 init-method 属性和 destroy-method 属性分别用于指定 Bean 的 init 方法和 destroy 方法。
Spring Framework 在 beans 标签还提供了 default-init-method 属性和 default-destroy-method 属性用于批量指定 Bean 的默认 init 方法和 destroy 方法。
1 |
|
1 | <?xml version="1.0" encoding="UTF-8" ?> |
但是如果两者一起使用,那么 default-init-method 和 default-destroy-method 方法会被忽略
Spring Framework 还提供了 InitializingBean 接口,用于在 Bean 实例化完成后进行额外处理。
1 |
|
在容器启动时,可以看到 构造函数 Smart() 最先被执行,然后是 SetBrand() 方法被执行,之后 afterPropertiesSet 也会被执行。
那么 InitializingBean 和 default-init-method、default-destroy-method 可否一起作用呢?
1 | package com.example.spring; |
通过测试,发现两者可以一起工作,且 afterPropertiesSet() 方法会优先执行。
那么 InitializingBean 和 init-method、destroy-method 可否一起作用呢?
1 | import org.springframework.beans.factory.InitializingBean; |
通过测试,发现两者可以一起工作,且 afterPropertiesSet() 方法会优先执行。
同理 Spring Framework 还提供了 DisposableBean 接口 做类似的 destroy-method 方法和 default-destroy-method 方法
总结:
Initialization callbacks
Destruction callbacks
Spring Framework:4.3.14.RELEASE
p 命名空间
p 命名空间是简化 property 标签的
1 | <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans |
包含引用属性:
1 | <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans |
c 命名空间
c 命名空间是简化 constructor-arg 标签
1 | <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:c="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans |
使用索引:
1 | <bean id="foo" class="x.y.Foo" c:_0-ref="bar" c:_1-ref="baz"/> |
级联属性
1 | <bean id="foo" class="foo.Bar"> |
depends-on属性
depends-on 属性用于显式声明依赖初始化的先后顺序
1 | <bean id="beanOne" class="ExampleBean" depends-on="manager"/> |
上述说明在实例化 beanOne 前需要先实例化 manager
1 | <bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao"> |
lazy-init属性
容器启动时默认对 Bean 进行初始化。 lazy-init 可以对 Bean 设置延迟初始化,当第一次访问时再去初始化。
1 | <bean id="lazy" class="com.foo.ExpensiveToCreateBean" lazy-init="true"/> |
还可以批量设置启用:
1 | <beans default-lazy-init="true"> |
Spring Framework:4.3.14.RELEASE
在了解了依赖注入后接着来详细演示不同情景的依赖注入。
属性值直接注入
原始类型,字符串等可以直接属性值注入
1 | <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> |
Spring Framework 可以自动将字符串的属性值按最佳的匹配方式为对应的属性进行转换
为了简化配置,Spring Framework 提供了 P 属性命名空间:
1 | <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> |
Spring Framework 还支持 Properties 属性方式注入:
1 | <bean id="mappings" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> |
引用属性注入
使用 ref 属性:
1 | <bean id="user" class="com.example.spring.User"> |
使用 ref 子标签:
1 | <bean id="theTargetBean" class="..."/> |
使用 idref 子标签:
1 | <bean id="theTargetBean" class="..."/> |
直接使用 value 属性:
1 | <bean id="theTargetBean" class="..." /> |
内部类
1 | <bean id="outer" class="..."> |
内部类 Bean 没有 id 属性,不可以被其他 Bean 引用
集合注入
集合注入支持 list、 set、 map、 properteis
集合元素可以是原始类型和引用类型
1 | <bean id="moreComplexObject" class="example.ComplexObject"> |
支持集合合并:
1 | <beans> |
同理 list map set 均可以支持集合合并,且子集会继承并覆盖父集的值
必须在子集上指定 merge 属性值为 true
null 和 空字符串注入
1 | <bean class="ExampleBean"> |
1 | <bean class="ExampleBean"> |
tag:
缺失模块。
1、请确保node版本大于6.2
2、在博客根目录(注意不是yilia根目录)执行以下命令:
npm i hexo-generator-json-content --save
3、在根目录_config.yml里添加配置:
jsonContent: meta: false pages: false posts: title: true date: true path: true text: false raw: false content: false slug: false updated: false comments: false link: false permalink: false excerpt: false categories: false tags: true