基本概念:
Spring Boot讓我們的Spring應用變的更輕量化。比如:你可以僅僅依靠一個Java類來運行一個Spring引用。你也可以打包你的應用爲jar並通過使用java -jar來運行你的Spring Web應用。
Spring Boot的主要優點:
爲所有Spring開發者更快的入門
開箱即用,提供各種默認配置來簡化項目配置
內嵌式容器簡化Web項目
沒有冗餘代碼生成和XML配置的要求。
基礎程序搭建過程解析:
(1)首先進行創建基礎項目maven web工程,注意打包方式爲jar文件。
(2)配置環境信息:pom文件依賴
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.3.RELEASE</version>
</parent>
<dependencies>
<!—SpringBoot web 組件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
備註:
spring-boot-starter-parent作用:
在pom.xml中引入spring-boot-start-parent,spring官方的解釋叫stater poms,它可以提供dependency management,也就是說依賴管理,引入以後在申明其它dependency的時候就不需要version了,後面可以看到。
spring-boot-starter-web作用
springweb 核心組件
spring-boot-maven-plugin作用
如果我們要直接Main啓動spring,那麼以下plugin必須要添加,否則是無法啓動的。如果使用maven 的spring-boot:run的話是不需要此配置的。
基礎程序: HelloWorld
/*
1 在上加上RestController 表示修飾該Controller所有的方法返回JSON格式,直接可以編寫
Restful接口
2 @EnableAutoConfiguration
註解:作用在於讓 Spring Boot 根據應用所聲明的依賴來對 Spring 框架進行自動配置, 這個註解告訴Spring Boot根據添加的jar依賴猜測你想如何配置Spring。由於spring-boot-starter-web添加了Tomcat和Spring MVC,所以auto-configuration將假定你正在開發一個web應用並相應地對Spring進行設置。
*/
@RestController
@EnableAutoConfiguration
public class HelloController {
@RequestMapping("/hello")
public String index() {
return "Hello World";
}
public static void main(String[] args) {
//SpringBoot的啓動類
SpringApplication.run(HelloController.class, args);
}
}
之後進行在瀏覽器初入相應的地址,即可完成訪問查看到返回的效果
啓動方式二:
//設置掃描包的範圍
@ComponentScan(basePackages = "com.xiaojun.controller")
@EnableAutoConfiguration
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
WEB基礎目錄結構:
在我們開發Web應用的時候,需要引用大量的js、css、圖片等靜態資源。
默認配置
Spring Boot默認提供靜態資源目錄位置需置於classpath下,目錄名需符合如下規則:
/static
/public
/resources
/META-INF/resources
舉例:我們可以在src/main/resources/目錄下創建static,在該位置放置一個圖片文件。啓動程序後,嘗試訪問http://localhost:8080/D.jpg。如能顯示圖片,配置成功。
系統異常處理:
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(RuntimeException.class)
@ResponseBody
public Map<String, Object> exceptionHandler() {
Map<String, Object> map = new HashMap<String, Object>();
map.put("errorCode", "400");
map.put("errorMsg", "系統異常!");
return map;
}
}
註解備註:
@ExceptionHandler 表示攔截異常
@ControllerAdvice 是 controller 的一個輔助類,最常用的就是作爲全局異常處理的切面類
@ControllerAdvice 可以指定掃描範圍
@ControllerAdvice 約定了幾種可行的返回值,如果是直接返回 model 類的話,需要使用 @ResponseBody 進行 json 轉換
返回 String,表示跳到某個 view
返回 modelAndView
返回 model + @ResponseBody
web頁面渲染處理:
渲染Web頁面
在之前的示例中,我們都是通過@RestController來處理請求,所以返回的內容爲json對象。那麼如果需要渲染html頁面的時候,要如何實現呢?
模板引擎
在動態HTML實現上Spring Boot依然可以完美勝任,並且提供了多種模板引擎的默認配置支持,所以在推薦的模板引擎下,我們可以很快的上手開發動態網站。
Spring Boot提供了默認配置的模板引擎主要有以下幾種:
Thymeleaf
FreeMarker
Velocity
Groovy
Mustache
Spring Boot建議使用這些模板引擎,避免使用JSP,若一定要使用JSP將無法實現Spring Boot的多種特性,具體可見後文:支持JSP的配置
當你使用上述模板引擎中的任何一個,它們默認的模板配置路徑爲:src/main/resources/templates。當然也可以修改這個路徑,具體如何修改,可在後續各模板引擎的配置屬性中查詢並修改。
FreeMarker基礎配置:
<!-- 引入freeMarker的依賴包. -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
application.properties配置
########################################################
###FREEMARKER (FreeMarkerAutoConfiguration)
########################################################
spring.freemarker.allow-request-override=false
spring.freemarker.cache=true
spring.freemarker.check-template-location=true
spring.freemarker.charset=UTF-8
spring.freemarker.content-type=text/html
spring.freemarker.expose-request-attributes=false
spring.freemarker.expose-session-attributes=false
spring.freemarker.expose-spring-macro-helpers=false
#spring.freemarker.prefix=
#spring.freemarker.request-context-attribute=
#spring.freemarker.settings.*=
spring.freemarker.suffix=.ftl
spring.freemarker.template-loader-path=classpath:/templates/
#comma-separated list
#spring.freemarker.view-names= # whitelist of view names that can be resolved
測試代碼段:
@RequestMapping("/index")
public String index(Map<String, Object> map) {
map.put("name","###小俊###");
map.put("sex",1);
List<String> userlist=new ArrayList<String>();
userlist.add("王五");
userlist.add("張三");
userlist.add("李四");
map.put("userlist",userlist);
return "index";
}
前臺常用點:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8" />
<title>首頁</title>
</head>
<body>
${name}
<#if sex==1>
男
<#elseif sex==2>
女
<#else>
其他
</#if>
<#list userlist as user>
${user}
</#list>
</body>
</html>
集成JSP:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.3.RELEASE</version>
</parent>
<dependencies>
<!-- SpringBoot 核心組件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
</dependencies>
視圖解析器配置:
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
SpringBoot整合Mybatis:
pom.xml依賴配置
主要配置的點:
1、org.mybatis.spring.boot
2、mysql-connector-java
3、org.springframework.boot(配置SpringBoot web)
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.2.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.21</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
application.properties文件配置:
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
測試代碼實現類:
public interface UserMapper {
@Select("SELECT * FROM USERS WHERE NAME = #{name}")
User findByName(@Param("name") String name);
@Insert("INSERT INTO USERS(NAME, AGE) VALUES(#{name}, #{age})")
int insert(@Param("name") String name, @Param("age") Integer age);
}
//配置掃描的包路徑
@ComponentScan(basePackages = "com.xiaojun")
@MapperScan(basePackages = "com.xiaojun.mapper")
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
SpringBoot整合多數據源開發:
首先解釋下多數據源的概念:所謂多數據源就是在系統之中有配置多個數據庫
application.properties
spring.datasource.test1.driverClassName = com.mysql.jdbc.Driver
spring.datasource.test1.url = jdbc:mysql://localhost:3306/test01?useUnicode=true&characterEncoding=utf-8
spring.datasource.test1.username = root
spring.datasource.test1.password = root
spring.datasource.test2.driverClassName = com.mysql.jdbc.Driver
spring.datasource.test2.url = jdbc:mysql://localhost:3306/test02?useUnicode=true&characterEncoding=utf-8
spring.datasource.test2.username = root
spring.datasource.test2.password = root
application.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-4.1.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.1.xsd"
default-lazy-init="false">
<aop:aspectj-autoproxy/>
<context:component-scan base-package="xxx.xxx.xxx"/>
<!-- 定時器開關 開始 -->
<task:annotation-driven />
<!-- 引入配置文件 -->
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:jdbc.properties" />
</bean>
<bean id="adminDataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="driverClassName" value="${admin.jdbc.driver}" />
<property name="url" value="${admin.jdbc.url}" />
<property name="username" value="${admin.jdbc.username}" />
<property name="password" value="${admin.jdbc.password}" />
<!-- 初始化連接大小 -->
<property name="initialSize" value="${admin.jdbc.initialSize}"></property>
<!-- 連接池最大數量 -->
<property name="maxActive" value="${admin.jdbc.maxActive}"></property>
<!-- 連接池最大空閒 -->
<property name="maxIdle" value="${admin.jdbc.maxIdle}"></property>
<!-- 連接池最小空閒 -->
<property name="minIdle" value="${admin.jdbc.minIdle}"></property>
<!-- 獲取連接最大等待時間 -->
<property name="maxWait" value="${admin.jdbc.maxWait}"></property>
<!-- 配置間隔多久才進行一次檢測,檢測需要關閉的空閒連接,單位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<!-- 配置一個連接在池中最小生存的時間,單位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="300000" />
<property name="validationQuery" value="SELECT 'x'" />
<property name="testWhileIdle" value="true" />
<property name="testOnBorrow" value="true" />
<property name="testOnReturn" value="true" />
<!-- 打開PSCache,並且指定每個連接上PSCache的大小 -->
<property name="poolPreparedStatements" value="true" />
<property name="maxPoolPreparedStatementPerConnectionSize" value="20" />
<!-- 配置監控統計攔截的filters -->
<property name="filters" value="stat,log4j" />
</bean>
<bean id="appDataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="driverClassName" value="${app.jdbc.driver}" />
<property name="url" value="${app.jdbc.url}" />
<property name="username" value="${app.jdbc.username}" />
<property name="password" value="${app.jdbc.password}" />
<!-- 初始化連接大小 -->
<property name="initialSize" value="${app.jdbc.initialSize}"></property>
<!-- 連接池最大數量 -->
<property name="maxActive" value="${app.jdbc.maxActive}"></property>
<!-- 連接池最大空閒 -->
<property name="maxIdle" value="${app.jdbc.maxIdle}"></property>
<!-- 連接池最小空閒 -->
<property name="minIdle" value="${app.jdbc.minIdle}"></property>
<!-- 獲取連接最大等待時間 -->
<property name="maxWait" value="${app.jdbc.maxWait}"></property>
<!-- 配置間隔多久才進行一次檢測,檢測需要關閉的空閒連接,單位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<!-- 配置一個連接在池中最小生存的時間,單位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="300000" />
<property name="validationQuery" value="SELECT 'x'" />
<property name="testWhileIdle" value="true" />
<property name="testOnBorrow" value="true" />
<property name="testOnReturn" value="true" />
<!-- 打開PSCache,並且指定每個連接上PSCache的大小 -->
<property name="poolPreparedStatements" value="true" />
<property name="maxPoolPreparedStatementPerConnectionSize" value="20" />
<!-- 配置監控統計攔截的filters -->
<property name="filters" value="stat,log4j" />
</bean>
<bean id="multipleDataSource" class="xxx.xxx.xxx....MultipleDataSource">
<property name="defaultTargetDataSource" ref="adminDataSource"/>
<property name="targetDataSources">
<map>
<entry key="adminDataSource" value-ref="adminDataSource"/>
<entry key="appDataSource" value-ref="appDataSource"/>
</map>
</property>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="multipleDataSource" />
<property name="mapperLocations" value="classpath*:mapper/*.xml"></property>
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
<property name="plugins">
<array>
<bean class="com.github.pagehelper.PageHelper">
<property name="properties">
<value>
dialect=mysql
reasonable=true
</value>
</property>
</bean>
</array>
</property>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="xxx.xxx.xxx.mapper,yyy.yyy.yyy.yyy.mapper" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="multipleDataSource"/>
</beans>
DataSource類
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
* 設置切換數據庫數據源
*/
/*
備註:
我們就簡單的配置好了兩個數據源,一個屬於admin的,一個屬於app
,默認是接入admin的數據源。在MultipleDataSource
中的靜態屬性值分別對應在application.xml中配置好的bean id。
因爲可能具體的業務操作是通過引入已經寫好dao、service層,
包括sql映射文件的jar包,因此mybatis的mapper掃描我們可以通過,
分割來配置掃描多個包,xml的掃描也配置掃描全部jar包下的所有文件,
classpath*:mapper/*.xml。這樣後臺管理其實只要寫個Controller來接受請求,
所有的業務調用都引用相應工程的jar包,相對來說還是挺方便的。
以上的配置已經可以讓項目跑起來,對於操作admin數據源自有的表來說不會報什麼錯,
當操作到app數據源的表就會報在admin數據庫中不存在某某表,這是因爲我們還沒有對數據源的切換進行配置,本來以爲一路下來會順風順水,但最重要的也是最折騰的地方在於下面的數據源切換上。
*/
public class MultipleDataSource extends AbstractRoutingDataSource {
public static final String DATA_SOURCE_ADMIN = "adminDataSource";
public static final String DATA_SOURCE_APP = "appDataSource";
private static final ThreadLocal<String> dataSourceKey = new InheritableThreadLocal<String>();
public static void setDataSourceKey(String dataSource) {
dataSourceKey.set(dataSource);
}
@Override
protected Object determineCurrentLookupKey() {
return dataSourceKey.get();
}
public static void removeDataSourceKey(){
dataSourceKey.remove();
}
}
以AOP方式進行切換數據源操作
import java.lang.reflect.Proxy;
import org.apache.commons.lang.ClassUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
/**
* 數據源切換AOP
*/
@Component
@Aspect
public class MultipleDataSourceInterceptor {
/**
* 攔截器對所有的業務實現類請求之前進行數據源切換
* 特別注意,由於用到了多數據源,Mapper的調用最好只在*ServiceImpl,不然調用到非默認數據源的表時,會報表不存在的異常
* @param joinPoint
* @throws Throwable
*/
@Before( "execution(* xxx.xxx.xxx..*.*ServiceImpl.*(..))")
public void setDataSoruce(JoinPoint joinPoint) throws Throwable {
Class<?> clazz = joinPoint.getTarget().getClass();
String className = clazz.getName();
if (ClassUtils.isAssignable(clazz, Proxy.class)) {
className = joinPoint.getSignature().getDeclaringTypeName();
}
//對類名含有business的設置爲app數據源,否則默認爲後臺的數據源
if(className.contains(".business.")){
MultipleDataSource.setDataSourceKey(MultipleDataSource.DATA_SOURCE_APP);
}else{
MultipleDataSource.setDataSourceKey(MultipleDataSource.DATA_SOURCE_ADMIN);
}
}
/**
* 當操作完成時,釋放當前的數據源
* 如果不釋放,頻繁點擊時會發生數據源衝突,本是另一個數據源的表,結果跑到另外一個數據源去,報表不存在
* @param joinPoint
* @throws Throwable
*/
@After( "execution(* xxx.xxx.xxx..*.*ServiceImpl.*(..))")
public void removeDataSoruce(JoinPoint joinPoint) throws Throwable {
MultipleDataSource.removeDataSourceKey();
}
}
第二種解決方案:運用註解結合報名的方式進行
properties配置文件信息
# Mysql 1
mysql.datasource.test.url = jdbc:mysql://localhost:3306/test01?useUnicode=true&characterEncoding=utf-8
mysql.datasource.test.username = root
mysql.datasource.test.password = root
mysql.datasource.test.minPoolSize = 3
mysql.datasource.test.maxPoolSize = 25
mysql.datasource.test.maxLifetime = 20000
mysql.datasource.test.borrowConnectionTimeout = 30
mysql.datasource.test.loginTimeout = 30
mysql.datasource.test.maintenanceInterval = 60
mysql.datasource.test.maxIdleTime = 60
mysql.datasource.test.testQuery = select 1
# Mysql 2
mysql.datasource.test2.url =jdbc:mysql://localhost:3306/test02?useUnicode=true&characterEncoding=utf-8
mysql.datasource.test2.username =root
mysql.datasource.test2.password =root
mysql.datasource.test2.minPoolSize = 3
mysql.datasource.test2.maxPoolSize = 25
mysql.datasource.test2.maxLifetime = 20000
mysql.datasource.test2.borrowConnectionTimeout = 30
mysql.datasource.test2.loginTimeout = 30
mysql.datasource.test2.maintenanceInterval = 60
mysql.datasource.test2.maxIdleTime = 60
mysql.datasource.test2.testQuery = select 1
基礎Bean讀取配置信息
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "mysql.datasource.test")
public class DBConfig1 {
private String url;
private String username;
private String password;
private int minPoolSize;
private int maxPoolSize;
private int maxLifetime;
private int borrowConnectionTimeout;
private int loginTimeout;
private int maintenanceInterval;
private int maxIdleTime;
private String testQuery;
}
//分別編寫不同Bean信息來進行耦合不同的數據源信息
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "mysql.datasource.test1")
public class DBConfig2 {
private String url;
private String username;
private String password;
private int minPoolSize;
private int maxPoolSize;
private int maxLifetime;
private int borrowConnectionTimeout;
private int loginTimeout;
private int maintenanceInterval;
private int maxIdleTime;
private String testQuery;
}
創建多數據源基本信息
@Configuration
// basePackages 最好分開配置 如果放在同一個文件夾可能會報錯
@MapperScan(basePackages = "com.itmayiedu.test01", sqlSessionTemplateRef = "testSqlSessionTemplate")
public class TestMyBatisConfig1 {
// 配置數據源
@Primary
@Bean(name = "testDataSource")
public DataSource testDataSource(DBConfig1 testConfig) throws SQLException {
MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
mysqlXaDataSource.setUrl(testConfig.getUrl());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
mysqlXaDataSource.setPassword(testConfig.getPassword());
mysqlXaDataSource.setUser(testConfig.getUsername());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
xaDataSource.setXaDataSource(mysqlXaDataSource);
xaDataSource.setUniqueResourceName("testDataSource");
xaDataSource.setMinPoolSize(testConfig.getMinPoolSize());
xaDataSource.setMaxPoolSize(testConfig.getMaxPoolSize());
xaDataSource.setMaxLifetime(testConfig.getMaxLifetime());
xaDataSource.setBorrowConnectionTimeout(testConfig.getBorrowConnectionTimeout());
xaDataSource.setLoginTimeout(testConfig.getLoginTimeout());
xaDataSource.setMaintenanceInterval(testConfig.getMaintenanceInterval());
xaDataSource.setMaxIdleTime(testConfig.getMaxIdleTime());
xaDataSource.setTestQuery(testConfig.getTestQuery());
return xaDataSource;
}
@Bean(name = "testSqlSessionFactory")
public SqlSessionFactory testSqlSessionFactory(@Qualifier("testDataSource") DataSource dataSource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
return bean.getObject();
}
@Bean(name = "testSqlSessionTemplate")
public SqlSessionTemplate testSqlSessionTemplate(
@Qualifier("testSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
package com.itmayiedu.datasource;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.atomikos.jdbc.AtomikosDataSourceBean;
import com.itmayiedu.config.DBConfig1;
import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource;
@Configuration
// basePackages 最好分開配置 如果放在同一個文件夾可能會報錯
@MapperScan(basePackages = "com.itmayiedu.test02", sqlSessionTemplateRef = "test2SqlSessionTemplate")
public class TestMyBatisConfig2 {
// 配置數據源
@Bean(name = "test2DataSource")
public DataSource testDataSource(DBConfig1 testConfig) throws SQLException {
MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
mysqlXaDataSource.setUrl(testConfig.getUrl());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
mysqlXaDataSource.setPassword(testConfig.getPassword());
mysqlXaDataSource.setUser(testConfig.getUsername());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
xaDataSource.setXaDataSource(mysqlXaDataSource);
xaDataSource.setUniqueResourceName("test2DataSource");
xaDataSource.setMinPoolSize(testConfig.getMinPoolSize());
xaDataSource.setMaxPoolSize(testConfig.getMaxPoolSize());
xaDataSource.setMaxLifetime(testConfig.getMaxLifetime());
xaDataSource.setBorrowConnectionTimeout(testConfig.getBorrowConnectionTimeout());
xaDataSource.setLoginTimeout(testConfig.getLoginTimeout());
xaDataSource.setMaintenanceInterval(testConfig.getMaintenanceInterval());
xaDataSource.setMaxIdleTime(testConfig.getMaxIdleTime());
xaDataSource.setTestQuery(testConfig.getTestQuery());
return xaDataSource;
}
@Bean(name = "test2SqlSessionFactory")
public SqlSessionFactory testSqlSessionFactory(@Qualifier("test2DataSource") DataSource dataSource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
return bean.getObject();
}
@Bean(name = "test2SqlSessionTemplate")
public SqlSessionTemplate testSqlSessionTemplate(
@Qualifier("test2SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
SpringBoot日誌處理(AOP切面)
基礎配置信息
pom文件依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
切面處理:
@Aspect
@Component
public class WebLogAspect {
private Logger logger = LoggerFactory.getLogger(getClass());
@Pointcut("execution(public * com.itmayiedu.controller..*.*(..))")
public void webLog() {
}
@Before("webLog()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
// 接收到請求,記錄請求內容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// 記錄下請求內容
logger.info("URL : " + request.getRequestURL().toString());
logger.info("HTTP_METHOD : " + request.getMethod());
logger.info("IP : " + request.getRemoteAddr());
Enumeration<String> enu = request.getParameterNames();
while (enu.hasMoreElements()) {
String name = (String) enu.nextElement();
logger.info("name:{},value:{}", name, request.getParameter(name));
}
}
@AfterReturning(returning = "ret", pointcut = "webLog()")
public void doAfterReturning(Object ret) throws Throwable {
// 處理完請求,返回內容
logger.info("RESPONSE : " + ret);
}
}
SpringBoot集成Ehcache緩存
使用目的 爲了減緩數據庫的壓力 主要來自數據檢索 默認首次查詢直接走DB 完後寫進緩存 下次查詢相同的邏輯 直接走緩存以此來進行達到減輕DB壓力的目的。
- 好處:
1)提高性能;2)減緩數據庫壓力;3)提高系統併發處理能力
- 使用緩存容易出現的問題:
1)處理邏輯變得複雜;2)使用不當,容易引起緩存和數據庫數據不一致的問題
- 數據不一致性問題:
緩存操作與數據庫操作不是原子操作,當一方操作成功、另一方操作失敗時就會造成數據不一致問題
基礎環境信息配置:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
在application.xml中進行配置
<!-- 啓用緩存註解功能,這個是必須的,否則註解不會生效,另外,該註解一定要聲明在spring主配置文件中才會生效 -->
<cache:annotation-driven cache-manager="ehcacheManager"/>
<!-- cacheManager工廠類,指定ehcache.xml的位置 -->
<bean id="ehcacheManagerFactory" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache.xml" />
</bean>
<!-- 聲明cacheManager -->
<bean id="ehcacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="ehcacheManagerFactory" />
</bean>
需要格外進行聲明一個ehcache的xml文件
1. <!--
2. name:緩存名稱。
3. maxElementsInMemory:緩存最大個數。
4. eternal:對象是否永久有效,一但設置了,timeout將不起作用。
5. timeToIdleSeconds:設置對象在失效前的允許閒置時間(單位:秒)。僅當eternal=false對象不是永久有效時使用,可選屬性,默認值是0,也就是可閒置時間無窮大。
6. timeToLiveSeconds:設置對象在失效前允許存活時間(單位:秒)。最大時間介於創建時間和失效時間之間。僅當eternal=false對象不是永久有效時使用,默認是0.,也就是對象存活時間無窮大。
7. overflowToDisk:當內存中對象數量達到maxElementsInMemory時,Ehcache將會對象寫到磁盤中。
8. diskSpoolBufferSizeMB:這個參數設置DiskStore(磁盤緩存)的緩存區大小。默認是30MB。每個Cache都應該有自己的一個緩衝區。
9. maxElementsOnDisk:硬盤最大緩存個數。
10. diskPersistent:是否緩存虛擬機重啓期數據 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
11. diskExpiryThreadIntervalSeconds:磁盤失效線程運行時間間隔,默認是120秒。
12. memoryStoreEvictionPolicy:當達到maxElementsInMemory限制時,Ehcache將會根據指定的策略去清理內存。默認策略是LRU(最近最少使用)。你可以設置爲FIFO(先進先出)或是LFU(較少使用)。
13. clearOnFlush:內存數量最大時是否清除。
14. -->
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
updateCheck="false">
<diskStore path="java.io.tmpdir/Tmp_EhCache" />
<!-- 默認配置 -->
<defaultCache maxElementsInMemory="5000" eternal="false"
timeToIdleSeconds="120" timeToLiveSeconds="120"
memoryStoreEvictionPolicy="LRU" overflowToDisk="false" />
<cache name="baseCache" maxElementsInMemory="10000"
maxElementsOnDisk="100000" />
</ehcache>
測試代碼:
使用cacheable註解即可 清除緩存調用cacheManager之中的clear()即可
@CacheConfig(cacheNames = "baseCache")
public interface UserMapper {
@Select("select * from users where name=#{name}")
@Cacheable
UserEntity findName(@Param("name") String name);
}
//緩存清除 具體執行環節在Controller之中進行調用cacheManager之中的clear()即可;
@Autowired
private CacheManager cacheManager;
@RequestMapping("/remoKey")
public void remoKey() {
cacheManager.getCache("baseCache").clear();
}
待思考問題 如如何進行確保DB數據與緩存的數據一致性問題?
在這裏插入代碼片
SpringBoot定時任務處理
使用註解開發 @Scheduled(fixedRate = 5000)
@Component
public class ScheduledTasks {
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
@Scheduled(fixedRate = 5000)
public void reportCurrentTime() {
System.out.println("現在時間:" + dateFormat.format(new Date()));
}
}
自定義參數配置
properties文件配置信息:
name=xiaojun
@Value("${name}")
private String name;
@ResponseBody
@RequestMapping("/getValue")
public String getValue() {
return name;
}
後續待更新。。。敬請期待