JDBC
我們可以通過使用 Spring Initializr 選擇所需要的模塊進行項目的創建:
- 依賴(通過上面創建的應用會自動配置依賴)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
- yaml配置
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://127.0.0.1:3306/jdbc
driver-class-name: com.mysql.jdbc.Driver
原理:
- 默認是用 org.apache.tomcat.jdbc.pool.DataSource 作爲數據源;
- 數據源的相關配置都在 DataSourceProperties 裏面;
自動配置都在 org.springframework.boot.autoconfigure.jdbc 下:
- 在 DataSourceConfiguration,根據配置創建數據源,默認使用Tomcat連接池;可以通過 spring.datasource.type 指定自定義的數據源類型,可用的數據源類型:
org.apache.tomcat.jdbc.pool.DataSource、HikariDataSource、BasicDataSource
也可以使用自定義的數據源,在 DataSourceConfiguration 下:
/**
* Generic DataSource configuration.
*/
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type")
static class Generic {
@Bean
public DataSource dataSource(DataSourceProperties properties) {
//使用DataSourceBuilder創建數據源,利用反射創建響應type的數據源,並且綁定相關屬性
return properties.initializeDataSourceBuilder().build();
}
}
- DataSourceInitializer 實現了 ApplicationListener,通過 runSchemaScripts() 運行建表語句;runDataScripts() 運行插入數據的sql語句,即可以對數據源中的數據進行初始化。
所以我們可以通過如下規則進行配置:
schema-.sql、data-.sql
默認規則:schema.sql,schema-all.sql;
指定位置可以使用:
schema:
- classpath:initializ.sql
- JdbcTemplateAutoConfiguration,這個自動配置就是爲我們操作數據庫提供的 JdbcTemaplate 進行自動配置,所以我們可以直接注入:
@Autowire
JdbcTemplate jdbcTemplate;
使用 Druid 數據源
- 依賴
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.20</version>
</dependency>
- 指定數據源類型
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://127.0.0.1:3306/jdbc
driver-class-name: com.mysql.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
- 除了上面的基本配置,對於其他連接池的配置,在 SpringBoot 自動配置的 properties 中並沒有,所以需要我們自己寫:
@Configuration
public class DruidConfig {
//將我們配置文件中的屬性(maxAcive、initialSize...)綁定到 DruidDataSource
@ConfigurationProperties(prefix = "spring.datasource")
@Bean
public DataSource druid(){
return new DruidDataSource();
}
}
- 還可以在我們的 DruidConfig 中配置監控:
//配置Druid的監控
//1、配置一個管理後臺的Servlet
@Bean
public ServletRegistrationBean statViewServlet(){
ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
Map<String,String> initParams = new HashMap<>();
initParams.put("loginUsername","admin");
initParams.put("loginPassword","123456");
initParams.put("allow","");//默認就是允許所有訪問
initParams.put("deny","192.168.15.21");
bean.setInitParameters(initParams);
return bean;
}
//2、配置一個web監控的filter
@Bean
public FilterRegistrationBean webStatFilter(){
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new WebStatFilter());
Map<String,String> initParams = new HashMap<>();
initParams.put("exclusions","*.js,*.css,/druid/*");
bean.setInitParameters(initParams);
bean.setUrlPatterns(Arrays.asList("/*"));
return bean;
}
MyBatis
整合步驟:
- 依賴(創建時自動配置)
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
- 配置數據源(參考 Druid 數據源)
- MyBatis 正常使用:數據庫建表、JavaBean、Mapper接口…
Mapper使用註解:
@Mapper
public interface DepartmentMapper {
@Select("select * from department where id=#{id}")
public Department getDeptById(Integer id);
@Delete("delete from department where id=#{id}")
public int deleteDeptById(Integer id);
@Options(useGeneratedKeys = true,keyProperty = "id")
@Insert("insert into department(departmentName) values(#{departmentName})")
public int insertDept(Department department);
@Update("update department set departmentName=#{departmentName} where id=#{id}")
public int updateDept(Department department);
}
我們還可以自定義MyBatis的配置規則,給容器中添加一個ConfigurationCustomizer:
@Configuration
public class MyBatisConfig {
@Bean
public ConfigurationCustomizer configurationCustomizer(){
return new ConfigurationCustomizer(){
@Override
public void customize(Configuration configuration) {
configuration.setMapUnderscoreToCamelCase(true);//開啓駝峯命名映射
}
};
}
}
除了使用 @Mapper 標識一個 Mapper 外,還可以在主類或者MyBatisCofig 上加上掃描註解:
@MapperScan(value = "com.moke.springboot.mapper")
@SpringBootApplication
public class SpringBootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootDemoApplication .class, args);
}
}
使用配置文件方式
mybatis:
config-location: classpath:mybatis/mybatis-config.xml #指定全局配置文件的位置
mapper-locations: classpath:mybatis/mapper/*.xml #指定sql映射文件的位置
Spring Data JPA
Spring 官網下的 Spring Data 項目的目的是爲了簡化構建基於 Spring 框架應用的數據訪問技術,包括關係數據庫以及非關係數據庫。
而 SpringData 爲我們提供使用統一的API來對數據訪問層進行操作:
接下來我們就來使用 SpringData JPA:
- 配置數據源:參考前文
- 編寫一個實體類(bean)
@Entity //告訴JPA這是一個實體類(和數據表映射的類)
@Table(name = "t_user") //@Table來指定和哪個數據表對應;如果省略默認表名就是user;
public class User {
@Id //這是一個主鍵
@GeneratedValue(strategy = GenerationType.IDENTITY)//自增主鍵
private Integer id;
@Column(name = "username",length = 50) //這是和數據表對應的一個列
private String username;
@Column //省略默認列名就是屬性名
private String password;
...
}
- 編寫一個Dao接口來操作實體類對應的數據表(Repository)
//繼承JpaRepository來完成對數據庫的操作
public interface UserRepository extends JpaRepository<User,Integer> {
}
- 基本配置(JpaProperties)
spring:
jpa:hibernate:
ddl‐auto: update # 自動更新或者創建數據表結構
show‐sql: true# 控制檯打印SQL語句
啓動配置原理
在之前的文章中我們學習了 自動配置原理,那麼 SpringBoot 又是如何啓動的呢?
在我們Main方法中調用了 SpringBootApplication 的 run 方法,其底層如下:
由此可知,啓動流程分爲兩步:
- 創建 SpringApplication 對象
SpringApplication 的構造方法中都調用了 initialize 方法,方法如下:
private void initialize(Object[] sources) {
//保存主配置類
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
//判斷當前是否一個web應用
this.webEnvironment = deduceWebEnvironment();
//從類路徑下找到META‐INF/spring.factories配置的所有ApplicationContextInitializer;然後保存起來
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
//從類路徑下找到ETA‐INF/spring.factories配置的所有ApplicationListener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//從多個配置類中找到有main方法的主配置類
this.mainApplicationClass = deduceMainApplicationClass();
}
- 運行run方法
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
configureHeadlessProperty();
//獲取SpringApplicationRunListeners;從類路徑下META-INF/spring.factories
SpringApplicationRunListeners listeners = getRunListeners(args);
//回調所有的獲取SpringApplicationRunListener.starting()方法
listeners.starting();
try {
//封裝命令行參數
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//準備環境
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
//創建環境完成後回調SpringApplicationRunListener.environmentPrepared();表示環境準備完成
Banner printedBanner = printBanner(environment);
//創建ApplicationContext;決定創建web的ioc還是普通的ioc
context = createApplicationContext();
analyzers = new FailureAnalyzers(context);
//準備上下文環境;將environment保存到ioc中;而且applyInitializers();
//applyInitializers():回調之前保存的所有的ApplicationContextInitializer的initialize方法
//回調所有的SpringApplicationRunListener的contextPrepared();
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//prepareContext運行完成以後回調所有的SpringApplicationRunListener的contextLoaded();
//刷新容器;ioc容器初始化(如果是web應用還會創建嵌入式的Tomcat);
//掃描,創建,加載所有組件的地方;(配置類,組件,自動配置)
//參考Spring源碼的refresh方法
refreshContext(context);
//從ioc容器中獲取所有的ApplicationRunner和CommandLineRunner進行回調
//ApplicationRunner先回調,CommandLineRunner再回調
afterRefresh(context, applicationArguments);
//所有的SpringApplicationRunListener回調finished方法
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
//整個SpringBoot應用啓動完成以後返回啓動的ioc容器;
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}
從 run 方法中,可以看到,SpringBoot 啓動過程中的幾個重要的事件回調:
- ApplicationContextInitializer、SpringApplicationRunListener:配置在META-INF/spring.factories
- ApplicationRunner、CommandLineRunner:只需要放在ioc容器中
ApplicationContextInitializer
作用:在 ConfigurableApplicationContext 類型(或者子類型)的 ApplicationContext 做 refresh 之前,允許我們對 ConfigurableApplicationContext 的實例做進一步的設置或者處理,簡單使用:
public class HelloApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("HelloApplicationContextInitializer..."+applicationContext);
}
}
SpringApplicationRunListener
作用:在 Spring Boot 啓動初始化的過程中可以通過 SpringApplicationRunListener 接口回調來讓用戶在啓動的各個流程中可以加入自己的邏輯。
public class HelloSpringApplicationRunListener implements SpringApplicationRunListener {
//必須有的構造器
public HelloSpringApplicationRunListener(SpringApplication application, String[] args){
}
@Override
public void starting() {
System.out.println("SpringApplicationRunListener...starting...");
}
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
Object o = environment.getSystemProperties().get("os.name");
System.out.println("SpringApplicationRunListener...environmentPrepared.."+o);
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
System.out.println("SpringApplicationRunListener...contextPrepared...");
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
System.out.println("SpringApplicationRunListener...contextLoaded...");
}
@Override
public void finished(ConfigurableApplicationContext context, Throwable exception) {
System.out.println("SpringApplicationRunListener...finished...");
}
}
上面兩種需要在 META-INF/spring.factories 中進行配置:
org.springframework.context.ApplicationContextInitializer=\
com.moke.springboot.listener.HelloApplicationContextInitializer
org.springframework.boot.SpringApplicationRunListener=\
com.moke.springboot.listener.HelloSpringApplicationRunListener
而接下來的兩個接口這都提供了一個run方法,這個run方法會在SpringApplication.run(…)執行完前被調用,允許我們在 SpringApplication 啓動後做一些事情。
ApplicationRunner
@Component
public class HelloApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("ApplicationRunner...run....");
}
}
CommandLineRunner
@Component
public class HelloCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("CommandLineRunner...run..."+ Arrays.asList(args));
}
}
自定義 starter
starter,即啓動器,可以爲我們 SpringBoot 應用中引入已有的自動配置類。
而 starter 只用來做依賴的,啓動器依賴於自動配置,所以實際上我們需要自定義的是自動配置模塊。
最後別人只需要引入 starter,就會進行相應的自動配置。
可以將以上分爲幾步:
- 啓動器模塊
新建一個空的 SpringBoot 項目,修改 pom.xml 文件:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.moke.starter</groupId>
<artifactId>moke-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
<!--啓動器-->
<dependencies>
<!--引入自動配置模塊-->
<dependency>
<groupId>com.moke.starter</groupId>
<artifactId>moke-spring-boot-starter-autoconfigurer</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
- 自動配置模塊
- 修改 pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.moke.starter</groupId>
<artifactId>moke-spring-boot-starter-autoconfigurer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>moke-spring-boot-starter-autoconfigurer</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.10.RELEASE</version>
<relativePath/>
</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>
<!--引入spring-boot-starter;所有starter的基本配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
</dependencies>
</project>
- 編寫自動配置類
- Properties 類
@ConfigurationProperties(prefix = "moke.hello") public class HelloProperties { private String prefix; private String suffix; public String getPrefix() { return prefix; } public void setPrefix(String prefix) { this.prefix = prefix; } public String getSuffix() { return suffix; } public void setSuffix(String suffix) { this.suffix = suffix; } }
- 所需要的功能
public class HelloService { HelloProperties helloProperties; public HelloProperties getHelloProperties() { return helloProperties; } public void setHelloProperties(HelloProperties helloProperties) { this.helloProperties = helloProperties; } public String sayHellAtguigu(String name){ return helloProperties.getPrefix()+"-" +name + helloProperties.getSuffix(); } }
- 自動配置類
@Configuration @ConditionalOnWebApplication //web應用才生效 @EnableConfigurationProperties(HelloProperties.class)//引入properties public class HelloServiceAutoConfiguration { @Autowired HelloProperties helloProperties; @Bean public HelloService helloService(){ HelloService service = new HelloService(); service.setHelloProperties(helloProperties); return service; } }
- META-INF/spring.factories 中添加自動配置類
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.moke.starter.HelloServiceAutoConfiguration
- starter 的使用:引入 自定義starter 即可
<dependency>
<groupId>com.moke.starter</groupId>
<artifactId>moke-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>