关于标题—>只是想看看标题党的效果如何
一、场景(简化)
要实现一个用户数据中心的系统架构,其中要用到两个数据库,一个database名为sso,主要存放用户的信息。另一个database名为configuration,存放一些配置信息。当A系统通过接口过来请求用户信息时,需要在配置库查询A系统的权限,然后将对应权限的用户信息返回给A系统。所以就需要使用两个不同的库,要在同一个项目中配置两套EntityManager(或者Hibernate的session)和事物管理。
连接池使用阿里巴巴的Druid,持久框架使用的Hibernate,需要引入spring-boot-starter-data-jpa
二、实体的包结构
- com.kingboy.configuration.domain(配置中心的实体)
- com.kingboy.ssoservice.domain(用户信息的实体)
三、配置文件(application.properties)
分别编写两套数据源的配置,我主要用不同的模块名称来区分不同的数据源。
- spring.datasource.configuration.*
- spring.datasource.sso.*
#-----------------------------------通用数据源配置-----------------------------
spring.jpa.hibernate.ddl-auto=update
spring.jpa.open-in-view=false
spring.jpa.show-sql=true
#---------------------------------------------------------
#configuration数据源
spring.datasource.configuration.url=jdbc:mysql://localhost:3306/configration?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false
spring.datasource.configuration.username=root
spring.datasource.configuration.password=123456
spring.datasource.configuration.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.configuration.maxActive=20
spring.datasource.configuration.initialSize=5
spring.datasource.configuration.minIdle=5
spring.datasource.configuration.maxWait=60000
spring.datasource.configuration.maxPoolPreparedStatementPerConnectionSize=20
spring.datasource.configuration.timeBetweenEvictionRunsMillis=60000
spring.datasource.configuration.minEvictableIdleTimeMillis=300000
spring.datasource.configuration.poolPreparedStatements=true
#---------------------------------------------------------
#sso数据源
spring.datasource.sso.url=jdbc:mysql://localhost:3306/sso?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false
spring.datasource.sso.username=root
spring.datasource.sso.password=123456
spring.datasource.sso.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.sso.maxActive=20
spring.datasource.sso.initialSize=5
spring.datasource.sso.minIdle=5
spring.datasource.sso.maxWait=60000
spring.datasource.sso.maxPoolPreparedStatementPerConnectionSize=20
spring.datasource.sso.timeBetweenEvictionRunsMillis=60000
spring.datasource.sso.minEvictableIdleTimeMillis=300000
spring.datasource.sso.poolPreparedStatements=true
这么多属性一看就很萌逼了,我们先把它加载到一个信息载体类中,方便以后使用。
configuration数据源的信息载体类:
package com.kingboy.configuration.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @Author kingboy
* @Date 2017/6/19 下午5:15
* @Description ConfigurationProperties is used to configuration的数据池属性
*/
@ConfigurationProperties(prefix = "spring.datasource.configuration")
@Component
public class ConfigurationDataSourceProperties {
public String url;
public String username;
public String password;
public String driverClassName;
public Integer maxActive;
public Integer initialSize;
public Integer minIdle;
public Integer maxWait;
public Integer maxPoolPreparedStatementPerConnectionSize;
public Integer timeBetweenEvictionRunsMillis;
public Integer minEvictableIdleTimeMillis;
public Boolean poolPreparedStatements;
}
sso数据源的信息载体类:
package com.kingboy.ssoservice.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @Author kingboy
* @Date 2017/6/19 下午5:15
* @Description ConfigurationProperties is used to configuration的数据池属性
*/
@ConfigurationProperties(prefix = "spring.datasource.sso")
@Component
public class SSODataSourceProperties {
public String url;
public String username;
public String password;
public String driverClassName;
public Integer maxActive;
public Integer initialSize;
public Integer minIdle;
public Integer maxWait;
public Integer maxPoolPreparedStatementPerConnectionSize;
public Integer timeBetweenEvictionRunsMillis;
public Integer minEvictableIdleTimeMillis;
public Boolean poolPreparedStatements;
}
四、配置configuration和sso的实体管理Bean和事物管理Bean
具体的配置说明都写在代码注释里面了。
configuration的配置
package com.kingboy.configuration.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.util.Map;
/**
* @Author kingboy
* @Date 2017/6/18 下午11:13
* @Description ConfigurationDataSource is used to 数据源配置
*/
@Configuration
@EnableTransactionManagement//开启事物管理
@EnableJpaRepositories(//自定义数据管理的配置
//指定EntityManager的创建工厂Bean
entityManagerFactoryRef="configurationEntityManagerFactory",
//指定事物管理的Bean
transactionManagerRef="configurationTransactionManager",
//指定管理的实体位置
basePackages= {"com.kingboy.configuration.domain"})
public class ConfigurationJPAConfig {
/*
* 配置数据源
*/
@Bean
public DataSource configurationDataSource() {
DruidDataSource dataSource = new DruidDataSource();
//设置数据源的属性
setDruidProperties(dataSource);
return dataSource;
}
@Autowired
ConfigurationDataSourceProperties config;//注入数据源配置信息
//设置数据源的属性的方法
private void setDruidProperties(DruidDataSource dataSource) {
dataSource.setUrl(config.url);
dataSource.setUsername(config.username);
dataSource.setPassword(config.password);
dataSource.setDriverClassName(config.driverClassName);
dataSource.setMaxActive(config.maxActive);
dataSource.setInitialSize(config.initialSize);
dataSource.setMinIdle(config.minIdle);
dataSource.setMaxWait(config.maxWait);
dataSource.setMaxPoolPreparedStatementPerConnectionSize(config.maxPoolPreparedStatementPerConnectionSize);
dataSource.setTimeBetweenEvictionRunsMillis(config.timeBetweenEvictionRunsMillis);
dataSource.setMinEvictableIdleTimeMillis(config.minEvictableIdleTimeMillis);
dataSource.setPoolPreparedStatements(config.poolPreparedStatements);
}
/*
* 配置实体管理工厂Bean
*/
@Bean
public LocalContainerEntityManagerFactoryBean configurationEntityManagerFactory (EntityManagerFactoryBuilder builder) {
return builder
.dataSource(configurationDataSource())
.packages("com.kingboy.configuration.domain")//设置实体类所在位置
.persistenceUnit("configuration")
.properties(getProperties(configurationDataSource()))//设置hibernate通用配置
.build();
}
@Autowired
private JpaProperties jpaProperties;//注入spring自带的jpa属性类
/*
*拿到hibernate的通用配置
*/
private Map<String, String> getProperties(DataSource dataSource) {
return jpaProperties.getHibernateProperties(dataSource);
}
/*
*配置事物管理的Bean
*/
@Bean
public PlatformTransactionManager configurationTransactionManager(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(configurationEntityManagerFactory(builder).getObject());
}
}
sso的配置
package com.kingboy.ssoservice.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.util.Map;
/**
* @Author kingboy
* @Date 2017/6/18 下午11:13
* @Description ConfigurationDataSource is used to 数据源配置
*/
@Configuration
@EnableTransactionManagement//开启事物管理
@EnableJpaRepositories(//自定义数据管理的配置
//指定EntityManager的创建工厂Bean
entityManagerFactoryRef="ssoEntityManagerFactory",
//指定事物管理的Bean
transactionManagerRef="ssoTransactionManager",
//指定管理的实体位置
basePackages= {"com.kingboy.ssoservice.domain"}) //设置Repository所在位置
public class SSOJPAConfig {
/*
* 配置数据源
*/
@Bean
@Primary//主数据源,或者叫默认数据源,下面的@Primary同理
public DataSource ssoDataSource() {
DruidDataSource dataSource = new DruidDataSource();
setDruidProperties(dataSource);
return dataSource;
}
//注入数据源配置信息
@Autowired
SSODataSourceProperties config;
private void setDruidProperties(DruidDataSource dataSource) {
dataSource.setUrl(config.url);
dataSource.setUsername(config.username);
dataSource.setPassword(config.password);
dataSource.setDriverClassName(config.driverClassName);
dataSource.setMaxActive(config.maxActive);
dataSource.setInitialSize(config.initialSize);
dataSource.setMinIdle(config.minIdle);
dataSource.setMaxWait(config.maxWait);
dataSource.setMaxPoolPreparedStatementPerConnectionSize(config.maxPoolPreparedStatementPerConnectionSize);
dataSource.setTimeBetweenEvictionRunsMillis(config.timeBetweenEvictionRunsMillis);
dataSource.setMinEvictableIdleTimeMillis(config.minEvictableIdleTimeMillis);
dataSource.setPoolPreparedStatements(config.poolPreparedStatements);
}
/*
* 配置实体管理工厂Bean
*/
@Bean
@Primary
public LocalContainerEntityManagerFactoryBean ssoEntityManagerFactory (EntityManagerFactoryBuilder builder) {
return builder
.dataSource(ssoDataSource())
.packages("com.kingboy.ssoservice.domain") //设置实体类所在位置
.persistenceUnit("sso")
.properties(getProperties(ssoDataSource()))//设置hibernate通用配置
.build();
}
@Autowired
private JpaProperties jpaProperties;//注入spring自带的jpa属性类
/*
*拿到hibernate的通用配置
*/
private Map<String, String> getProperties(DataSource dataSource) {
return jpaProperties.getHibernateProperties(dataSource);
}
/*
*配置事物管理的Bean
*/
@Bean
public PlatformTransactionManager ssoTransactionManager(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(ssoEntityManagerFactory(builder).getObject());
}
}
五、关于第四节的说明
@Bean注解如果没有指定bean的名字,那么会以方法名作为bean的名字。所以就有了@EnableJpaRepositories注解中的
entityManagerFactoryRef="ssoEntityManagerFactory"
和transactionManagerRef="ssoTransactionManager"
。private JpaProperties jpaProperties;
是spring自动注入的,可以获取到配置文件中『通用数据源配置』的信息,如show-sql等属性。只所以将sso与configuration分开配置,一是为了整洁。二是为了模块解耦,如果是多模块项目,会很好拆分。
六、使用
为了方便阅读,随便写个栗子,就从controller开始写了。也不使用接口编程了,这样看起来更顺畅。
实体类(注解就不加了)
public class User {
private Integer id;
private String telephone;
private String password;
//setter getter
}
public class Configuration {
private Integer id;
private String formatId;
private String secret;
//setter getter
}
Controller
@RestController
@RequestMapping(produces = "application/json")
public class UserController {
@Resource
UserService userService;
@Resource
ConfigurationService configurationService;
/**
* 添加User
* @return
*/
//为了方便用了restfule的形式,正常要用post,https
@GetMapping(value = "/AddUser/{telephone}/{password}")
public ApiResult add(@PathVariable String telephone, @PathVariable String password) {
userService.addUser(telephone, password);
return ApiResult.success("add user success!");
}
/**
* 添加配置
* @return
*/
//为了方便用了restfule的形式,正常要用post,https
@GetMapping(value = "/AddConfig/{formatId}/{secret}")
public ApiResult add(@PathVariable String formatId, @PathVariable String secret) {
configurationService.addConfig(formatId, secret);
return ApiResult.success("add config success!");
}
}
Service
@Service
public class UserServiceImpl{
@Resource
UserRepository userRepository;
@Override
@Transactional(rollbackFor = Exception.class, value = "ssoTransactionManager")//对应的事物管理Bean的名字
public void addUser(String telephone,String password) {
userRepository.addUser(telephone, password);
}
}
@Service
public class ConfigurationServiceImpl{
@Resource
ConfigurationRepository configurationRepository;
@Override
@Transactional(rollbackFor = Exception.class, value = "configurationTransactionManager")//对应的事物管理Bean的名字
public void addConfig(String formatId,String secret) {
configurationRepository.addConfig(formatId, secret);
}
}
Repository
@Repository
public class UserRepositoryImpl {
@Autowired
@Qualifier("ssoEntityManagerFactory")//实体管理工厂Bean的名字
EntityManager ssoEntityManager;
@Override
public void addUser(String telephone, String password) {
User user = new User(null, telephone, password);
ssoEntityManager.persist(user);
}
}
@Repository
public class ConfigurationRepositoryImpl {
@Autowired
@Qualifier("configurationEntityManagerFactory")//实体管理工厂Bean的名字
EntityManager configurationEntityManager;
@Override
public void addConfig(String formatId, String secret) {
Configuration config = new Configuration(null, formatId, secret);
configurationEntityManager.persist(config);
}
}
上面代码手写,可能个别地方会有个小纰漏。
至此,全部搞定……m……m……p