第二章 Springboot进阶部分笔记

拼搏现实的明天。 2023-06-16 02:25 80阅读 0赞

一、集成Redis

1、修改pom文件,增加依赖


<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2、在properties增加redis配置

# REDIS (RedisProperties)
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=192.168.30.156
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=12345678
# 连接超时时间(毫秒)
spring.redis.timeout=5000

3、新建单元测试

/\**

  • * 测试连接redis(连接地址为虚拟机redis服务,需要手动开启)*
  • */
    @SpringBootTest(classes = {App.class})
    @RunWith(SpringRunner.class)
    public class SpringRedisTest {
    @Resource
    private RedisTemplate redisTemplate;
    @Test
    public void testRedis() *throws
    Exception {
    1. ValueOperations<String, String> ops = **redisTemplate**.opsForValue();
    2. ops.set(**"name"**, **"hankin1117"**);
    3. String value = ops.get(**"name"**);
    4. System.***out***.println(value);
    }
    }

二、集成RabbitMQ

RabbitMQ在后面SpringCloud的章节还会用到,在这会简单的安装使用下RabbitMq,至于RabbitMQ的详细使用请参考分布式消息队列课题。

1、Windows安装RabbitMQ

先安装Erlang,下载地址:http://erlang.org/download/otp_win64_20.3.exe

RabbitMQ Server 3.7.4下载地址:

https://bintray.com/rabbitmq/all/download_file?file_path=rabbitmq-server%2F3.7.4%2Frabbitmq-server-3.7.4.exe

安装好后,启动服务:

开启web插件,进入rabbitmq安装目录的sbin目录,在命令行界面开启web插件:

./rabbitmq-plugins enable rabbitmq_management

重新启动reabbitmq服务,在地址栏输入http://localhost:15672/

使用默认用户 guest/guest登陆界面

2、新增用户,并设置权限

用新创建的admin用户登陆,发现新用户已经新增成功,设置权限:

点击这用户,设置虚拟主机的权限(全部可读,可写,可配置)

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3NjYxNDU4_size_16_color_FFFFFF_t_70

这个时候一个admin新用户设置完毕

3、SpringBoot中使用RabbitMQ

1)修改pom文件,增加rabbitmq依赖:


<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

2)修改配置properties文件,增加rabbitmq的连接信息

## rabbitmq config
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=admin

3)创建Rabbit配置类,用来配置队列,交换器,路由等高级信息

@Configuration
public class RabbitConfig {
@Bean
public Queue firstQueue() {
// 创建一个队列,名称为:hankin

  • *return new Queue(“hankin”);
    }
    }

4)创建消息的生产者:

@Component
public class Sender {
@Resource
private AmqpTemplate rabbitTemplate;
public void send() {
rabbitTemplate.convertAndSend(“hankin”,“this is a message!”);
}
}

5)创建消息的消费者

@Component
@RabbitListener(queues = “hankin”) //**TODO 定义该类需要监听的队列
public class Receiver {
// 指定对消息的处理

  • @RabbitHandler
    public void process(String msg) {
    System.**
    out*.println(“receive msg : “** + msg);
    }
    }

6)新增单元测试

@RunWith(SpringRunner.class)
@SpringBootTest(classes = App.class)
public class RabbitmqTest {
@Resource
private Sender sender;
@Test
public void testRabbitmq() throws Exception {
sender.send();
}
}

20191123221255282.png

三、Actuator监控管理

Actuator是spring boot的一个附加功能,可帮助你在应用程序生产环境时监视和管理应用程序;可以使用HTTP的各种请求来监管、审计、收集应用的运行情况,特别对于微服务管理十分有意义。

缺点:没有可视化界面(Spring cloud还会用到这功能,就可以看到界面了)

1、修改pom文件,添加依赖:


<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

2、修改application.properties文件,启动监控端点

# 加载所有的端点/默认只加载了 info / health
management.endpoints.web.exposure.include=*
# 描述信息
info.blog-url=https://blog.csdn.net/m0\_37661458
info.author=hankin
info.version=@project.version@

重新启动,在地址栏输入:http://localhost:8080/actuator/info,在界面看到这说明监控成功

A**ctuator访问路径**:通过actuator/+端点名就可以获取相应的信息。
































路径

作用

/actuator/beans

显示应用程序中所有Spring bean的完整列表。

/actuator/configprops

显示所有配置信息。

/actuator/env

陈列所有的环境变量。

/actuator/mappings

显示所有@RequestMapping的url整理列表。

/actuator/health

显示应用程序运行状况信息 up表示成功 down失败

/actuator/info

查看自定义应用信息

四、自定义Starter

在学习SpringBoot的过程中,不管是集成redis还是RabbitMQ,甚至是前面集成mybatis已经学习了很多starter,这些starter都是springboot为我们提供的一些封装;这些starter能非常方便快捷的增加功能,并不需要很多配置,即使需要配置也就在application.properties稍微配置下就可以了,那么接下来就学习下怎么创建属于自己的starter。

1、redis-starter插件

前面已经使用过spring-boot-starter-data-redis,这个starter是用来集成redis的,那么接下来完成一个starter,这个starter也就集成下redis。新建一个项目,这个项目不需要web功能。

1.1、环境搭建

1)pom文件内容如下:


<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.0.1</version>
</dependency>

2)创建一个RedisProperties用于加载Redis需要的配置,这里为简单起见,并没有设置密码

@ConfigurationProperties(prefix = “redis”)
public class RedisProperties {
private String host;
private int port;
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
}

3)创建一个配置类,这个配置类用于加载配置,并实例化Jedis客户端

@Configuration //开启配置
@ConditionalOnClass(Jedis.class)
@EnableConfigurationProperties(RedisProperties.class) // TODO 开启使用映射实体对象
@ConditionalOnProperty//**TODO 存在对应配置信息时初始化该配置类
(
prefix = “redis”,//存在配置前缀redis

  • value = “enabled”,//开启*
  • matchIfMissing = true//缺失检查*
  • )
    public class RedisAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean
    public Jedis jedis(RedisProperties redisProperties){
    *return new
    Jedis(redisProperties.getHost(), redisProperties.getPort());
    }
    }

4)自动化配置代码中有很多我们之前没有用到的注解配置,我们从上开始讲解

@Configuration:这个配置就不用多做解释了,我们一直在使用。

@EnableConfigurationProperties:这是一个开启使用配置参数的注解,value值就是我们配置实体参数映射的ClassType,将配置实体作为配置来源。

1.2、SpringBoot内置条件注解

有关@ConditionalOnXxx相关的注解这里要系统的说下,因为这个是我们配置的关键,根据名称我们可以理解为具有Xxx条件,当然它实际的意义也是如此,条件注解是一个系列,下面我们详细做出解释:

@ConditionalOnBean:当SpringIoc容器内存在指定Bean的条件。

@ConditionalOnClass:当SpringIoc容器内存在指定Class的条件。

@ConditionalOnExpression:基于SpEL表达式作为判断条件。

@ConditionalOnJava:基于JVM版本作为判断条件。

@ConditionalOnMissingBean:当SpringIoc容器内不存在指定Bean的条件。

@ConditionalOnMissingClass:当SpringIoc容器内不存在指定Class的条件。

@ConditionalOnNotWebApplication:当前项目不是Web项目的条件。

@ConditionalOnProperty:指定的属性是否有指定的值。

@ConditionalOnResource:类路径是否有指定的值。

@ConditionalOnSingleCandidate:当指定Bean在SpringIoc容器内只有一个,或者虽然有多个但是指定首选的Bean。

@ConditionalOnWebApplication:当前项目是Web项目的条件。

以上注解都是元注解@Conditional演变而来的,根据不用的条件对应创建以上的具体条件注解。到目前为止我们还没有完成自动化配置starter,我们需要了解SpringBoot运作原理后才可以完成后续编码。

1.3、Starter自动化运作原理

在注解@SpringBootApplication上存在一个开启自动化配置的注解@EnableAutoConfiguration来完成自动化配置,注解源码如下所示:

@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = “spring.boot.enableautoconfiguration”;
Class<?>[] exclude() default {};
String[] excludeName() default {};
}

在@EnableAutoConfiguration注解内使用到了@import注解来完成导入配置的功能,而EnableAutoConfigurationImportSelector内部则是使用了SpringFactoriesLoader.loadFactoryNames方法进行扫描具有META-INF/spring.factories文件的jar包。我们可以先来看下spring-boot-autoconfigure包内的spring.factories文件内容,如下所示:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3NjYxNDU4_size_16_color_FFFFFF_t_70 1

可以看到配置的结构形式是Key=>Value形式,多个Value时使用‘,’隔开,那我们在自定义starter内也可以使用这种形式来完成,我们的目的是为了完成自动化配置,所以我们这里Key则是需要使用org.springframework.boot.autoconfigure.EnableAutoConfiguration

1.4、自定义spring.factories

我们在src/main/resource目录下创建META-INF目录,并在目录内添加文件spring.factories,具体内容如下所示:

#配置自定义Starter的自动化配置
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.chj.**redis**.RedisAutoConfiguration

目前为止自定义的starter已经开发完毕。

2、新建项目测试startser

这里我们新建项目springboot-redis-startertest做测试,这项目用来测试前面创建的redis-starter。

代码地址:https://gitee.com/hankin\_chj/springboot-platform.git

1)Pom文件配置如下:


<dependency>
<groupId>com.chj</groupId>
<artifactId>springboot-redis-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>

2)application.properties在里面配置redis连接相关信息:

redis.host=127.0.0.1
redis.port=6379

3)准备好这些后,启动redis,新建立一个测试类,运行测试方法

@SpringBootTest(classes = App.class)
@RunWith(SpringRunner.class)
public class RedisTest {
@Resource
private Jedis jedis;
@Test
public void test() {
jedis.set(“hankin”,“hankintest”);
String str = jedis.get(“hankin”);
System.out.println(str);
}
}

到这一步,自定义redis-stater搞定。

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3NjYxNDU4_size_16_color_FFFFFF_t_70 2

五、SpringBoot CLI

Spring Boot CLI是一个命令行工具,如果想使用Spring进行快速开发可以使用它。它允许你运行Groovy脚本,这意味着你可以使用熟悉的类Java语法,并且没有那么多的模板代码。你可以通过Spring Boot CLI启动新项目,或为它编写命令。

Groovy是个基于JVM(Java虚拟机)的敏捷开发语音,既然是基于jvm,那么在groovy里面使用任何java的组件他都是可以支持识别的,在大概5,6年前Groovy比较火,尤其微信公众刚开放的那段时间,很多微信的后端程序都是基于grails开发的。

1、解压安装SpringBoot CLI

下载地址:

https://repo.spring.io/release/org/springframework/boot/spring-boot-cli/2.1.2.RELEASE/spring-boot-cli-2.1.2.RELEASE-bin.zip

为了方便你可以配置环境变量,但由于这个cli使用得并不频繁,就不配置了。

使用命令: .\spring.bat —version可以查看Spring CLI的版本信息。

20191123220930334.png

1)新建一个groovy的文件 hello.groovy

@RestController

class WebApplication {

@RequestMapping(“/“)

String home() {

“Hello World!”

}

}

2)使用命令可以启动:.\spring.bat run .\hello.groovy

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3NjYxNDU4_size_16_color_FFFFFF_t_70 3

这个时候他会自动下载依赖,并运行项目,直接访问上面的接口,返回结果如下:

20191123220857520.png

2、构建项目

刚开始学习springboot的时候经常使用http://start.spring.io/ 构建项目,其实这个功能你完全也可以使用 SpringBoot CLI完成构建。

使用命令:

.\spring init —build=maven —java-version=1.8 —dependencies=web —packaging=jar —boot-version=2.1.3.RELEASE —groupId=chj —artifactId=demo

项目创建成功!

六、性能优化

1、扫描优化

在默认情况下,我们会使用@SpringBootApplication注解来自动获取应用的配置信息,但这样也会带来一些副作用。使用这个注解后,会触发自动配置(auto-configuration)和组件扫描(component scanning),这跟使用@Configuration、@EnableAutoConfiguration和@ComponentScan三个注解的作用是一样的。这样做给开发带来方便的同时,会有以下的一些影响:

  • 会导致项目启动时间变长(原因:加载了我们不需要使用的组件,浪费了cpu资源和内存资源)。当启动一个大的应用程序,或将做大量的集成测试启动应用程序时,影响会特别明显。
  • 会加载一些不需要的多余的实例(beans)。
  • 会增加CPU消耗和内存的占用。

本着有问题就要解决的心态,针对以上的问题,我们要怎么解决呢?很明显,既然@SpringBootApplication加载了一些不必要的配置,那么我们想是否可以就加载我们自己指定的配置呢?

我们的思路不使用@SpringBootApplication并且不使用@ComponentScan注解(此注解会自动扫描我们注解了@Controller,@Service的注解的类,加载到Spring IOC容器中),然后我们使用@Configuration和@EnableAutoConfiguration进行配置启动类。

新建立一个项目,pom文件仅仅引入web依赖,新建一个测试controller,新增启动类;这个代码非常简单,优化的效果也不会很明显,但重点需要理解的是这原理,前面已经说过直接用@SpringBootApplication有各种问题,那么现在改变启动类:

//@SpringBootApplication
@EnableAutoConfiguration
@Configuration
@ComponentScan(“com.chj.controller”)
public class SpringbootOptimizeApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootOptimizeApplication.class, args);
}
}

这样直接使用自己定义ComponentScan的扫描类,让他只扫描自己需要的组件能增加启动时间,并且介绍spring容器bean的数目。前面讲自定义starter的时候讲过,@EnableAutoConfiguration注解会导入META-INF/spring.factories里面配置的很多Configuration,这些Configuration他都会去扫描,在启动VM参数里(VM options)面加入 -Ddebug:

重新启动,发现在控制台:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3NjYxNDU4_size_16_color_FFFFFF_t_70 4

控制台输入的信息,大概分成四大类:

1)Positive matches:匹配(以及匹配的原因)

2)Negative matches:忽略匹配(以及忽略的原因)

3)Exclusions:排除的配置类

4)Unconditional classes:没有带任何条件,肯定要扫描的类

根据上面的理论知识,我们只需要在启动的时候,显式地引入这些组件,需要的组件=Positive matches+Unconditional classes,我们可以不使用@EnableAutoConfiguration,转而显示的使用@Import来导入需要的配置类:

//@SpringBootApplication
//@EnableAutoConfiguration
@Configuration
@Import({
CodecsAutoConfiguration.class,
DispatcherServletAutoConfiguration.class,
EmbeddedWebServerFactoryCustomizerAutoConfiguration.class,
ErrorMvcAutoConfiguration.class,
HttpEncodingAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class,
JacksonAutoConfiguration.class,
ServletWebServerFactoryAutoConfiguration.class,
WebMvcAutoConfiguration.class,
ValidationAutoConfiguration.class,
MultipartAutoConfiguration.class,
JmxAutoConfiguration.class,
RestTemplateAutoConfiguration.class,
WebSocketServletAutoConfiguration.class,
TaskExecutionAutoConfiguration.class,
TaskSchedulingAutoConfiguration.class,
ConfigurationPropertiesAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class,
ProjectInfoAutoConfiguration.class
})
@ComponentScan(“com.chj.controller”)
public class SpringbootOptimizeApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootOptimizeApplication.class, args);
}
}

另外也可以删除一些虽然匹配到了,但是在项目中目前并没有使用到的配置,比如:

任务调度:TaskExecutionAutoConfiguration,TaskSchedulingAutoConfiguration

WebSocket:WebSocketServletAutoConfiguration

附件上传:MultipartAutoConfiguration

JMX:JmxAutoConfiguration等等……

2、JVM参数调优

启动App,使用jdk里面jvisualvm.exe可以吃查看应用的内存情况:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3NjYxNDU4_size_16_color_FFFFFF_t_70 5

这个时候内存分配了2G,可以根据需要,判断是否需要这么大,一般来说1G足够,尤其是微服务,另外还发现最大值和最小值两个设置的并不一样,来看下会有什么问题。

1)设置JVM参数:-XX:+PrintGCDetails -Xmx32M -Xms1M

这样设置后发现有大量的GC,更可怕的还有大量的FULL GC存在。

频繁的GC对性能影响是很大的,频繁调用http://localhost:8080/hi,发现垃圾回收特别频繁:

2)设置JVM参数,把最大的内存数设置成1024:-XX:+PrintGCDetails -Xmx1024M -Xms1M

GC次数明显减少,但既然还会出现几个full GC;频繁调用http://localhost:8080/hi,发现垃圾回收依然特别频繁,这不断的申请内存,释放内存对性能是有不小的影响。

3)置JVM参数,把最大的内存数设置成1024,最小内存也设置成1024

-XX:+PrintGCDetails -Xmx1024M -Xms1024M

这个时候再重启,发现不管是gc还是full gc 都明显的减少了次数。

这个时候再来频繁调用http://localhost:8080/hi,发现内存的使用比较均匀了:

3、Undertow容器

默认情况下,Spring Boot使用Tomcat来作为内嵌的Servlet容器,可以将Web服务器切换到Undertow来提高应用性能。Undertow是一个采用Java开发的灵活的高性能Web服务器,提供包括阻塞和基于NIO的非堵塞机制,Undertow是红帽公司的开源产品。

3.1、Tomcat测试

1)先测试下默认情况tomcat性能,启动Apache JMeter,选择添加—》线程组,弹出页面设置线程数以及循环次数(这里我们设置1个线程请求1000次)。

2)然后右键:添加==》Sampler==》HTTP请求,填写路径:http://localhost:8080/hello

3)添加一个“聚合报告”,右键:添加==》监听器—》聚合报告

重复测试3次,求一个平均值:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3NjYxNDU4_size_16_color_FFFFFF_t_70 6

结果为:1313、1761、1720,可见tomcat在1秒内处理请求数不到2000。

3.2、Undertow测试

修改pom文件,先删除掉Tomcat然后引入undertow:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>

重新启动后发现容器以及切换成undertow:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3NjYxNDU4_size_16_color_FFFFFF_t_70 7

继续使用JMeter测试:1494、972、226发现性能提升还是比较大的。

七、多数据源与jta+atomikos

本章节主要学习多数据源与jta+atomikos分布式事务,SpringBoot默认是集成事务的,只要在方法上加上@Transactional既可,但某些项目用到了多个数据库,也就代表有多个数据源。

1、多数据源

1.1、数据库准备

两个数据库:

数据库1:Databases:spring

数据库2:Databases:spring2

1.2、pom文件

新建一个项目,在pom文件里面增加mybatis等依赖信息

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>

  • </dependency>
    <dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.5</version>
    </dependency>
    *
  • <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    </*dependency
    >

1.3、新增model类、新增mapper接口

可通过mybatis的generatorConfig.xml生产,代码省略。

注意:由于这两mapper接口对应不同的数据库,为了配置与管理方便,不同的数据库的mapper接口单独放置在一个package中。

1.4、Mapper的XML配置

为了管理方便,xml的配置也根据数据库的不同放置到不同的文件夹中。

例如:mapper文件夹下面分别新建order、user文件夹,用来存放各自的映射文件。

1.5、新建业务测试类

新建service接口与实现类OrderService以及实现类OrderServiceImpl,上面只是准备工作,目前未知没有配置与数据源相关的任何配置。

1.6、application.properties

新增application.properties,里面配置数据源相关信息,分别配置了两个数据库:

spring.datasource.spring.driverClassName=com.mysql.jdbc.Driver
spring.datasource.spring.jdbcUrl=jdbc:mysql://127.0.0.1:3306/spring?serverTimezone=GMT%2B8
spring.datasource.spring.username=root
spring.datasource.spring.password=root

spring.datasource.spring2.driverClassName=com.mysql.jdbc.Driver
spring.datasource.spring2.jdbcUrl=jdbc:mysql://127.0.0.1:3306/spring2?serverTimezone=GMT%2B8
spring.datasource.spring2.username=root
spring.datasource.spring2.password=root

2、数据源配置类

@Configuration
@MapperScan(basePackages = “com.chj.dao**.**user”, sqlSessionFactoryRef = “test1SqlSessionFactory”)

public class DataSource1Config {
@Bean(name = “test1DataSource”)
@ConfigurationProperties(prefix = “spring.datasource.spring”)
@Primary
public DataSource testDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = “test1SqlSessionFactory”)
@Primary
public SqlSessionFactory testSqlSessionFactory(@Qualifier(“test1DataSource”) DataSource dataSource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(“classpath:mapping/users/*.xml”));
return bean.getObject();
}
@Bean(name = “test1TransactionManager”)
@Primary
public DataSourceTransactionManager testTransactionManager(@Qualifier(“test1DataSource”) DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean(name = “test1SqlSessionTemplate”)
@Primary
public SqlSessionTemplate testSqlSessionTemplate(
@Qualifier(“test1SqlSessionFactory”) SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}

数据源配置类2:

@Configuration
@MapperScan(basePackages = “com.chj.dao.order”, sqlSessionFactoryRef = “test2SqlSessionFactory”)
public class DataSource2Config {
@Bean(name = “test2DataSource”)
@ConfigurationProperties(prefix = “spring.datasource.spring2”)
public DataSource testDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = “test2SqlSessionFactory”)
public SqlSessionFactory testSqlSessionFactory(@Qualifier(“test2DataSource”) DataSource dataSource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(“classpath:mapping/order/*.xml”));
return bean.getObject();
}
@Bean(name = “test2TransactionManager”)
public DataSourceTransactionManager testTransactionManager(@Qualifier(“test2DataSource”) DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean(name = “test2SqlSessionTemplate”)
public SqlSessionTemplate testSqlSessionTemplate(
@Qualifier(“test2SqlSessionFactory”) SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}

这两个配置文件是重中之重,配置了数据源,连接工厂,Mapper扫描的包,mapper xml配置的位置等

3、单元测试

@SpringBootTest(classes = {App.class})
@RunWith(SpringRunner.class)
public class MoreDataBaseTest {
@Resource
private OrderService orderService;
@org.junit.Test
public void test1() {
User user = new User();
user.setUserName(“hankin”);
user.setPassword(“123”);
user.setId(1001);

  1. Order orders = **new** Order();
  2. orders.setAccount(**"123"**);
  3. orders.setName(**"zhangsan"**);
  4. orders.setUserId(**"1001"**);
  5. **orderService**.addOrder(orders,user);
  6. \}

}

这个时候以及集成了2套数据源,并且已经测试发现可以同时入库。

2、jta+atomikos分布式事务

2.1、修改pom文件

增加atomikos支持


<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>

2.2、新增配置类DBConfig1与DBConfig2

DBConfig1代码示例:

@ConfigurationProperties(prefix = “spring.datasource.spring”)
@Component
public class DBConfig2 {
private String driverClassName;
private String jdbcUrl;
private String username;
private String password;

Getter/setter…
}

DBConfig2代码示例:

@ConfigurationProperties(prefix = “spring.datasource.spring2”)
@Component
public class DBConfig2 {
private String driverClassName;
private String jdbcUrl;
private String username;
private String password;

Getter/setter…
}

2.3、修改数据源配置类

数据源配置类1,添加事务修改:

/\**

  • * 数据源配置类1 添加事务修改*
  • */*

@Configuration
@MapperScan(basePackages = “com.chj.dao.user”, sqlSessionFactoryRef = “test1SqlSessionFactory”)
public class DataSource1Config1 {
@Bean(name = “test1DataSource”)
@Primary
public DataSource testDataSource(DBConfig1 config1) {
MysqlXADataSource mysqlXADataSource=new MysqlXADataSource();
mysqlXADataSource.setUrl(config1.getJdbcUrl());
mysqlXADataSource.setPassword(config1.getPassword());
mysqlXADataSource.setUser(config1.getUsername());
AtomikosDataSourceBean atomikosDataSourceBean=new AtomikosDataSourceBean();
atomikosDataSourceBean.setXaDataSource(mysqlXADataSource);
atomikosDataSourceBean.setUniqueResourceName(“test1Datasource”);
return atomikosDataSourceBean;
}
@Bean(name = “test1SqlSessionFactory”)
@Primary
public SqlSessionFactory testSqlSessionFactory(@Qualifier(“test1DataSource”) DataSource dataSource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(“classpath:**mapper*/user/\.xml”));
return bean.getObject();
}
// @Bean(name = “test1TransactionManager”)
// @Primary
// public DataSourceTransactionManager testTransactionManager(@Qualifier(“test1DataSource”) DataSource dataSource) {
// return new DataSourceTransactionManager(dataSource);
// }

  • @Bean(name = “test1SqlSessionTemplate”)
    @Primary
    *public
    SqlSessionTemplate testSqlSessionTemplate(
    1. @Qualifier(**"test1SqlSessionFactory"**) SqlSessionFactory sqlSessionFactory) **throws** Exception \{
    return new SqlSessionTemplate(sqlSessionFactory);
    }
    }

数据源配置类2,添加事务修改:

/\**

  • * 数据源配置类2,添加事务修改*
  • */
    @Configuration
    @MapperScan(basePackages = “com.chj.dao.order”, sqlSessionFactoryRef = “test2SqlSessionFactory”)
    public class DataSource2Config2 {
    @Bean(name = “test2DataSource”)
    *public
    DataSource testDataSource(DBConfig2 config2) {
    1. MysqlXADataSource mysqlXADataSource=**new** MysqlXADataSource();
    2. mysqlXADataSource.setUrl(config2.getJdbcUrl());
    3. mysqlXADataSource.setPassword(config2.getPassword());
    4. mysqlXADataSource.setUser(config2.getUsername());
    5. AtomikosDataSourceBean atomikosDataSourceBean=**new** AtomikosDataSourceBean();
    6. atomikosDataSourceBean.setXaDataSource(mysqlXADataSource);
    7. atomikosDataSourceBean.setUniqueResourceName(**"test2Datasource"**);
    8. **return** atomikosDataSourceBean;
    }
    @Bean(name = “test2SqlSessionFactory”)
    public SqlSessionFactory testSqlSessionFactory(@Qualifier(“test2DataSource”) DataSource dataSource)
    1. **throws** Exception \{
    2. SqlSessionFactoryBean bean = **new** SqlSessionFactoryBean();
    3. bean.setDataSource(dataSource);
    4. bean.setMapperLocations(**new** PathMatchingResourcePatternResolver().getResources(**"classpath:****mapper****/order/\*.xml"**));
    5. **return** bean.getObject();
    }
    // @Bean(name = “test2TransactionManager”)
    // public DataSourceTransactionManager testTransactionManager(@Qualifier(“test2DataSource”) DataSource dataSource) {
    // return new DataSourceTransactionManager(dataSource);
    // }
  • @Bean(name = “test2SqlSessionTemplate”)
    *public
    SqlSessionTemplate testSqlSessionTemplate(
    1. @Qualifier(**"test2SqlSessionFactory"**) SqlSessionFactory sqlSessionFactory) **throws** Exception \{
    return new SqlSessionTemplate(sqlSessionFactory);
    }
    }

2.4、修改Service方法

public class OrderServiceImpl implements OrderService {
@Resource
private UserMapper userMapper;
@Resource
private OrderMapper orderMapper;
@Transactional
@Override
public void addOrder(Order order, User user) {
userMapper.insertSelective(user);
int i=10/0;
orderMapper.insertSelective(order);
}
}

使用之前的单元测试。

发表评论

表情:
评论列表 (有 0 条评论,80人围观)

还没有评论,来说两句吧...

相关阅读