java每日精进 3.21 【Springboot规范1】

1.Springboot、Springcloud、SpringCloudAlibaba

现在的Spring Cloud Alibaba由于没有纳入到Spring Cloud的主版本管理中,所以我们需要自己去引入其版本信息;

springboot:

主要特点
  • 自动配置:根据依赖自动配置 Spring 应用。

  • 内嵌服务器:支持内嵌 Tomcat、Jetty 等服务器,无需单独部署。

  • 简化依赖管理:通过 starter 依赖简化 Maven/Gradle 配置。

  • 监控和管理:提供 Actuator 模块,支持应用监控和管理。

作用

Spring Boot 主要用于快速开发单体应用或微服务应用中的单个服务。

SpringCloud:

Spring Cloud 是一个基于 Spring Boot 的 微服务架构解决方案,提供了一系列工具和框架,用于构建分布式系统中的常见模式(如配置管理、服务发现、熔断器、负载均衡等)。

主要组件
  • 服务发现:Eureka、Consul、Zookeeper。

  • 配置中心:Spring Cloud Config。

  • 负载均衡:Ribbon、LoadBalancer。

  • 熔断器:Hystrix、Resilience4j。

  • API 网关:Zuul、Spring Cloud Gateway。

  • 分布式追踪:Sleuth、Zipkin。

作用

Spring Cloud 主要用于解决微服务架构中的 分布式系统问题,例如服务之间的通信、配置管理、容错处理等。

SpringCloudAlibaba:

Spring Cloud Alibaba 是 Spring Cloud 的一个子项目,由阿里巴巴开源,提供了一系列基于阿里巴巴生态的微服务解决方案。它是 Spring Cloud 的扩展,集成了阿里巴巴的中间件和工具。

主要组件
  • 服务发现与配置管理:Nacos。

  • 熔断与限流:Sentinel。

  • 分布式事务:Seata。

  • 消息队列:RocketMQ。

  • 分布式任务调度:SchedulerX。

作用

Spring Cloud Alibaba 主要用于在 Spring Cloud 的基础上,提供 阿里巴巴生态的集成支持,特别适合国内企业和开发者使用。

1. Spring Boot 是基础
  • Spring Boot 是 Spring Cloud 和 Spring Cloud Alibaba 的基础。

  • Spring Boot 提供了快速开发单个微服务的能力,而 Spring Cloud 和 Spring Cloud Alibaba 则是在此基础上解决分布式系统的问题。

2. Spring Cloud 是扩展
  • Spring Cloud 基于 Spring Boot,提供了一套完整的微服务解决方案。

  • 它解决了分布式系统中的常见问题,如服务发现、配置管理、负载均衡等。

3. Spring Cloud Alibaba 是增强
  • Spring Cloud Alibaba 是 Spring Cloud 的扩展,集成了阿里巴巴的中间件和工具。

  • 它在 Spring Cloud 的基础上,提供了更适合国内开发者的解决方案(如 Nacos、Sentinel、Seata 等)。

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Finchley.SR1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>0.2.1.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

而不是像以往使用Spring Cloud的时候,直接引入Spring Cloud的主版本(Dalston、Edgware、Finchley、Greenwich这些)就可以的。我们需要像上面的例子那样,单独的引入spring-cloud-alibaba-dependencies来管理Spring Cloud Alibaba下的组件版本。

由于Spring Cloud基于Spring Boot构建,而Spring Cloud Alibaba又基于Spring Cloud Common的规范实现,所以当我们使用Spring Cloud Alibaba来构建微服务应用的时候,需要知道这三者之间的版本关系。

下表整理了目前Spring Cloud Alibaba的版本与Spring Boot、Spring Cloud版本的兼容关系:

Spring Boot Spring Cloud Spring Cloud Alibaba
2.1.x Greenwich 0.9.x
2.0.x Finchley 0.2.x
1.5.x Edgware 0.1.x
1.5.x Dalston 0.1.x

2.工程结构

my-spring-boot-app/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/
│   │   │       └── example/
│   │   │           ├── MySpringBootApplication.java  # 启动类
│   │   │           ├── config/                       # 配置类
│   │   │           ├── controller/                  # 控制器层
│   │   │           ├── service/                     # 服务层
│   │   │           ├── repository/                  # 数据访问层
│   │   │           ├── model/                       # 实体类
│   │   │           ├── dto/                         # 数据传输对象
│   │   │           ├── exception/                   # 自定义异常
│   │   │           └── util/                        # 工具类
│   │   ├── resources/
│   │   │   ├── static/                              # 静态资源(CSS、JS、图片等)
│   │   │   ├── templates/                           # 模板文件(如 Thymeleaf)
│   │   │   ├── application.yml                      # 主配置文件
│   │   │   ├── application-dev.yml                  # 开发环境配置文件
│   │   │   ├── application-prod.yml                 # 生产环境配置文件
│   │   │   └── logback-spring.xml                   # 日志配置文件
│   │   └── webapp/                                  # Web 资源(可选)
│   └── test/
│       ├── java/
│       │   └── com/
│       │       └── example/
│       │           ├── MySpringBootApplicationTests.java  # 测试类
│       │           ├── controller/                        # 控制器测试
│       │           ├── service/                           # 服务层测试
│       │           └── repository/                        # 数据访问层测试
│       └── resources/
│           └── application-test.yml                      # 测试环境配置文件
├── target/                                               # 构建输出目录
├── pom.xml                                               # Maven 配置文件
├── Dockerfile                                            # Docker 镜像构建文件
├── .gitignore                                            # Git 忽略文件
└── README.md                                             # 项目说明文档

3.配置文件

3.1自定义参数:

book.name=SpringCloudInAction
book.author=nihao

@Component
public class Book {

    @Value("${book.name}")
    private String name;
    @Value("${book.author}")
    private String author;

    // 省略getter和setter
}

3.2命令行参数

java -jar xxx.jar --server.port=8888

3.3 多环境配置

开发、测试、生产环境中,其中每个环境的数据库地址、服务器端口等等配置都会不同,如果在为不同环境打包时都要频繁修改配置文件的话,那必将是个非常繁琐且容易发生错误的事。

在Spring Boot中多环境配置文件名需要满足application-{profile}.properties的格式,其中{profile}对应你的环境标识,比如:

  • application-dev.properties:开发环境
  • application-test.properties:测试环境
  • application-prod.properties:生产环境

至于哪个具体的配置文件会被加载,需要在application.properties文件中通过spring.profiles.active属性来设置,其值对应配置文件中的{profile}值。如:spring.profiles.active=test就会加载application-test.properties配置文件内容。

List类型

在properties文件中使用[]来定位列表类型,比如:

spring.my-example.url[0]=http://example.com
spring.my-example.url[1]=http://spring.io

也支持使用逗号分割的配置方式,上面与下面的配置是等价的:

spring.my-example.url=http://example.com,http://spring.io

而在yaml文件中使用可以使用如下配置:

spring:
  my-example:
    url:
      - http://example.com
      - http://spring.io

也支持逗号分割的方式:

spring:
  my-example:
    url: http://example.com, http://spring.io
Map类型

Map类型在properties和yaml中的标准配置方式如下:

  • properties格式:
spring.my-example.foo=bar
spring.my-example.hello=world
  • yaml格式:
spring:
  my-example:
    foo: bar
    hello: world

注意:如果Map类型的key包含非字母数字和-的字符,需要用[]括起来,比如:

spring:
  my-example:
    '[foo.baz]': bar
指定环境启动

java -jar myapp.jar -Dspring.profiles.active=dev
 

4. API

Swagger2

 <!-- SpringDoc OpenAPI -->
        <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
            <version>2.0.2</version>
        </dependency>
# 启用 Swagger UI
springdoc.swagger-ui.enabled=true

# 配置 API 文档信息
springdoc.info.title=AI大模型调用接口文档
springdoc.info.description=AI大模型调用的相关接口文档
springdoc.info.version=1.0

各参数配置含义如下:

  • swagger.title:标题
  • swagger.description:描述
  • swagger.version:版本
@RestController
@RequestMapping("/api/ai")
@Tag(name = "AI大模型调用接口", description = "AI大模型调用的相关接口文档")

@Operation(summary = "获取文章摘要", description = "根据输入的文本生成文章摘要")
    @PostMapping("/abstract")
    public Result getAbstract(
            @Parameter(description = "输入的文本", required = true) @RequestBody String text) {
        try {
            CompletableFuture<String> future = aiProofAbstractService.proofabstractBigStr(text);
            String abstractResult = future.join();
            return new Result(AppConstants.SUCCESS_CODE, abstractResult);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

JSR-303

JSR是Java Specification Requests的缩写,意思是Java 规范提案。是指向JCP(Java Community Process)提出新增一个标准化技术规范的正式请求。任何人都可以提交JSR,以向Java平台增添新的API和服务。JSR已成为Java界的一个重要标准。

第一步:在要校验的字段上添加上@NotNull注解,具体如下:

@Data
@ApiModel(description="用户实体")
public class User {

    @ApiModelProperty("用户编号")
    private Long id;

    @NotNull
    @ApiModelProperty("用户姓名")
    private String name;

    @NotNull
    @ApiModelProperty("用户年龄")
    private Integer age;

}

第二步:在需要校验的参数实体前添加@Valid注解,具体如下:

@PostMapping("/")
@ApiOperation(value = "创建用户", notes = "根据User对象创建用户")
public String postUser(@Valid @RequestBody User user) {
    users.put(user.getId(), user);
    return "success";
}

尝试一些其他校验

在完成了上面的例子之后,我们还可以增加一些校验规则,比如:校验字符串的长度、校验数字的大小、校验字符串格式是否为邮箱等。下面我们就来定义一些复杂的校验定义,比如:

@Data
@ApiModel(description="用户实体")
public class User {

    @ApiModelProperty("用户编号")
    private Long id;

    @NotNull
    @Size(min = 2, max = 5)
    @ApiModelProperty("用户姓名")
    private String name;

    @NotNull
    @Max(100)
    @Min(10)
    @ApiModelProperty("用户年龄")
    private Integer age;

    @NotNull
    @Email
    @ApiModelProperty("用户邮箱")
    private String email;

}

JSON Schema

JSON Schema 是一种用于定义 JSON 数据格式、内容和语义的规范,可用于校验 JSON 数据是否符合特定的结构和约束要求。以下是关于 JSON Schema 校验的一些基本信息:

<dependency>
    <groupId>com.github.java-json-tools</groupId>
    <artifactId>json-schema-validator</artifactId>
    <version>2.2.10</version>
</dependency>
<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.6</version>
</dependency>
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "username": {
      "type": "string",
      "minLength": 3,
      "maxLength": 20
    },
    "email": {
      "type": "string",
      "format": "email"
    },
    "password": {
      "type": "string",
      "minLength": 8
    }
  },
  "required": ["username", "email", "password"],
  "additionalProperties": false
}
import org.everit.json.schema.Schema;
import org.everit.json.schema.ValidationException;
import org.everit.json.schema.loader.SchemaLoader;
import org.json.JSONObject;
import org.json.JSONTokener;

public class JsonSchemaValidator {

    // 加载 JSON Schema
    private static Schema loadSchema(String schemaPath) {
        JSONObject rawSchema = new JSONObject(new JSONTokener(JsonSchemaValidator.class.getResourceAsStream(schemaPath)));
        return SchemaLoader.load(rawSchema);
    }

    // 验证 JSON 数据
    public static void validateJson(Schema schema, String jsonData) {
        try {
            JSONObject jsonObject = new JSONObject(jsonData);
            schema.validate(jsonObject);
            System.out.println("JSON 数据验证通过!");
        } catch (ValidationException e) {
            System.err.println("JSON 数据验证失败:" + e.getMessage());
            e.getCausingExceptions().stream()
                .map(ValidationException::getMessage)
                .forEach(System.err::println);
        }
    }

    public static void main(String[] args) {
        // 加载 Schema
        Schema schema = loadSchema("/schema/user-registration-schema.json");

        // 测试 JSON 数据
        String validJson = "{ \"username\": \"john_doe\", \"email\": \"[email protected]\", \"password\": \"password123\" }";
        String invalidJson = "{ \"username\": \"jd\", \"email\": \"invalid-email\", \"password\": \"123\" }";

        // 验证 JSON 数据
        validateJson(schema, validJson);   // 验证通过
        validateJson(schema, invalidJson); // 验证失败
    }
}

5.数据访问

数据源配置

在我们访问数据库的时候,需要先配置一个数据源,下面分别介绍一下几种不同的数据库配置方式。

首先,为了连接数据库需要引入jdbc支持,在pom.xml中引入如下配置:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
#嵌入式数据库支持

嵌入式数据库通常用于开发和测试环境,不推荐用于生产环境。Spring Boot提供自动配置的嵌入式数据库有H2、HSQL、Derby,你不需要提供任何连接配置就能使用。

比如,我们可以在pom.xml中引入如下配置使用HSQL

<dependency>
    <groupId>org.hsqldb</groupId>
    <artifactId>hsqldb</artifactId>
    <scope>runtime</scope>
</dependency>
#连接生产数据源

以MySQL数据库为例,先引入MySQL连接的依赖包,在pom.xml中加入:

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

src/main/resources/application.properties中配置数据源信息

spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=dbuser
spring.datasource.password=dbpass
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

注意:因为Spring Boot 2.1.x默认使用了MySQL 8.0的驱动,所以这里采用com.mysql.cj.jdbc.Driver,而不是老的com.mysql.jdbc.Driver

#JPA
#依赖
<dependencies>
    <!-- Spring Boot Starter Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- Spring Data JPA -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <!-- MySQL Driver -->
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
    </dependency>

    <!-- Lombok (可选) -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <scope>provided</scope>
    </dependency>

    <!-- Spring Boot Starter Test -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
properity配置文件
# 数据库连接配置
spring.datasource.url=jdbc:mysql://localhost:3306/mydatabase?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=yourpassword

# JPA 配置
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
#定义实体
package com.example.demo.entity;

import jakarta.persistence.*;
import lombok.Data;

@Data
@Entity
@Table(name = "users")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String name;

    @Column(nullable = false, unique = true)
    private String email;

    @Column(nullable = false)
    private String password;
}
#数据操作层
package com.example.demo.repository;

import com.example.demo.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {
    // 自定义查询方法
    User findByEmail(String email);
}
#controller和service层
@RestController
@RequestMapping("/users")
public class UserController {

    @Autowired
    private UserService userService;

    // 创建用户
    @PostMapping
    public User createUser(@RequestBody User user) {
        return userService.saveUser(user);
    }

    // 获取所有用户
    @GetMapping
    public List<User> getAllUsers() {
        return userService.getAllUsers();
    }

    // 根据邮箱获取用户
    @GetMapping("/{email}")
    public User getUserByEmail(@PathVariable String email) {
        return userService.getUserByEmail(email);
    }
}

===============================================================
@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    // 保存用户
    public User saveUser(User user) {
        return userRepository.save(user);
    }

    // 查询所有用户
    public List<User> getAllUsers() {
        return userRepository.findAll();
    }

    // 根据邮箱查询用户
    public User getUserByEmail(String email) {
        return userRepository.findByEmail(email);
    }
}

多数据源的配置

jdbc多数据源
spring.datasource.primary.jdbc-url=jdbc:mysql://localhost:3306/test1
spring.datasource.primary.username=root
spring.datasource.primary.password=123456
spring.datasource.primary.driver-class-name=com.mysql.cj.jdbc.Driver

spring.datasource.secondary.jdbc-url=jdbc:mysql://localhost:3306/test2
spring.datasource.secondary.username=root
spring.datasource.secondary.password=123456
spring.datasource.secondary.driver-class-name=com.mysql.cj.jdbc.Driver
  1. 多数据源配置的时候,与单数据源不同点在于spring.datasource之后多设置一个数据源名称primarysecondary来区分不同的数据源配置,这个前缀将在后续初始化数据源的时候用到。

完成多数据源的配置信息之后,就来创建个配置类来加载这些配置信息,初始化数据源,以及初始化每个数据源要用的JdbcTemplate。你只需要在你的Spring Boot应用下添加下面的这个配置类即可完成!

@Configuration
public class DataSourceConfiguration {

    @Primary
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.secondary")
    public DataSource secondaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    public JdbcTemplate primaryJdbcTemplate(@Qualifier("primaryDataSource") DataSource primaryDataSource) {
        return new JdbcTemplate(primaryDataSource);
    }

    @Bean
    public JdbcTemplate secondaryJdbcTemplate(@Qualifier("secondaryDataSource") DataSource secondaryDataSource) {
        return new JdbcTemplate(secondaryDataSource);
    }

}
@RunWith(SpringRunner.class)
@SpringBootTest
public class Chapter37ApplicationTests {

    @Autowired
    protected JdbcTemplate primaryJdbcTemplate;

    @Autowired
    protected JdbcTemplate secondaryJdbcTemplate;

    @Before
    public void setUp() {
        primaryJdbcTemplate.update("DELETE  FROM  USER ");
        secondaryJdbcTemplate.update("DELETE  FROM  USER ");
    }

    @Test
    public void test() throws Exception {
        // 往第一个数据源中插入 2 条数据
        primaryJdbcTemplate.update("insert into user(name,age) values(?, ?)", "aaa", 20);
        primaryJdbcTemplate.update("insert into user(name,age) values(?, ?)", "bbb", 30);

        // 往第二个数据源中插入 1 条数据,若插入的是第一个数据源,则会主键冲突报错
        secondaryJdbcTemplate.update("insert into user(name,age) values(?, ?)", "ccc", 20);

        // 查一下第一个数据源中是否有 2 条数据,验证插入是否成功
        Assert.assertEquals("2", primaryJdbcTemplate.queryForObject("select count(1) from user", String.class));

        // 查一下第一个数据源中是否有 1 条数据,验证插入是否成功
        Assert.assertEquals("1", secondaryJdbcTemplate.queryForObject("select count(1) from user", String.class));
    }

}
Spring Data JPA的多数据源配置
spring.datasource.primary.jdbc-url=jdbc:mysql://localhost:3306/test1
spring.datasource.primary.username=root
spring.datasource.primary.password=123456
spring.datasource.primary.driver-class-name=com.mysql.cj.jdbc.Driver

spring.datasource.secondary.jdbc-url=jdbc:mysql://localhost:3306/test2
spring.datasource.secondary.username=root
spring.datasource.secondary.password=123456
spring.datasource.secondary.driver-class-name=com.mysql.cj.jdbc.Driver

# 日志打印执行的SQL
spring.jpa.show-sql=true
# Hibernate的DDL策略
spring.jpa.hibernate.ddl-auto=create-drop
@Configuration
public class DataSourceConfiguration {

    @Primary
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.secondary")
    public DataSource secondaryDataSource() {
        return DataSourceBuilder.create().build();
    }

}

通过@ConfigurationProperties可以知道这两个数据源分别加载了spring.datasource.primary.*spring.datasource.secondary.*的配置。@Primary注解指定了主数据源,就是当我们不特别指定哪个数据源的时候,就会使用这个Bean真正差异部分在下面的JPA配置上。

分别创建两个数据源的JPA配置

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef="entityManagerFactoryPrimary",
        transactionManagerRef="transactionManagerPrimary",
        basePackages= { "com.didispace.chapter38.p" }) //设置Repository所在位置
public class PrimaryConfig {

    @Autowired
    @Qualifier("primaryDataSource")
    private DataSource primaryDataSource;

    @Autowired
    private JpaProperties jpaProperties;
    @Autowired
    private HibernateProperties hibernateProperties;

    private Map<String, Object> getVendorProperties() {
        return hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());
    }

    @Primary
    @Bean(name = "entityManagerPrimary")
    public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
        return entityManagerFactoryPrimary(builder).getObject().createEntityManager();
    }

    @Primary
    @Bean(name = "entityManagerFactoryPrimary")
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryPrimary (EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(primaryDataSource)
                .packages("com.didispace.chapter38.p") //设置实体类所在位置
                .persistenceUnit("primaryPersistenceUnit")
                .properties(getVendorProperties())
                .build();
    }

    @Primary
    @Bean(name = "transactionManagerPrimary")
    public PlatformTransactionManager transactionManagerPrimary(EntityManagerFactoryBuilder builder) {
        return new JpaTransactionManager(entityManagerFactoryPrimary(builder).getObject());
    }

}
==================================================================================================================================================================================
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef="entityManagerFactorySecondary",
        transactionManagerRef="transactionManagerSecondary",
        basePackages= { "com.didispace.chapter38.s" }) //设置Repository所在位置
public class SecondaryConfig {

    @Autowired
    @Qualifier("secondaryDataSource")
    private DataSource secondaryDataSource;

    @Autowired
    private JpaProperties jpaProperties;
    @Autowired
    private HibernateProperties hibernateProperties;

    private Map<String, Object> getVendorProperties() {
        return hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());
    }

    @Bean(name = "entityManagerSecondary")
    public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
        return entityManagerFactorySecondary(builder).getObject().createEntityManager();
    }

    @Bean(name = "entityManagerFactorySecondary")
    public LocalContainerEntityManagerFactoryBean entityManagerFactorySecondary (EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(secondaryDataSource)
                .packages("com.didispace.chapter38.s") //设置实体类所在位置
                .persistenceUnit("secondaryPersistenceUnit")
                .properties(getVendorProperties())
                .build();
    }

    @Bean(name = "transactionManagerSecondary")
    PlatformTransactionManager transactionManagerSecondary(EntityManagerFactoryBuilder builder) {
        return new JpaTransactionManager(entityManagerFactorySecondary(builder).getObject());
    }

}
MyBatis的多数据源配置
spring:
  # datasource 数据源配置内容
  datasource:
    # 订单数据源配置
    orders:
      url: jdbc:mysql://127.0.0.1:3306/test_orders?useSSL=false&useUnicode=true&characterEncoding=UTF-8
      driver-class-name: com.mysql.jdbc.Driver
      username: root
      password:
      type: com.alibaba.druid.pool.DruidDataSource # 设置类型为 DruidDataSource
      # Druid 自定义配置,对应 DruidDataSource 中的 setting 方法的属性
      min-idle: 0 # 池中维护的最小空闲连接数,默认为 0 个。
      max-active: 20 # 池中最大连接数,包括闲置和使用中的连接,默认为 8 个。
    # 用户数据源配置
    users:
      url: jdbc:mysql://127.0.0.1:3306/test_users?useSSL=false&useUnicode=true&characterEncoding=UTF-8
      driver-class-name: com.mysql.jdbc.Driver
      username: root
      password:
      type: com.alibaba.druid.pool.DruidDataSource # 设置类型为 DruidDataSource
      # Druid 自定义配置,对应 DruidDataSource 中的 setting 方法的属性
      min-idle: 0 # 池中维护的最小空闲连接数,默认为 0 个。
      max-active: 20 # 池中最大连接数,包括闲置和使用中的连接,默认为 8 个。
    # Druid 自定已配置
    druid:
      # 过滤器配置
      filter:
        stat: # 配置 StatFilter ,对应文档 https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_StatFilter
          log-slow-sql: true # 开启慢查询记录
          slow-sql-millis: 5000 # 慢 SQL 的标准,单位:毫秒
      # StatViewServlet 配置
      stat-view-servlet: # 配置 StatViewServlet ,对应文档 https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_StatViewServlet%E9%85%8D%E7%BD%AE
        enabled: true # 是否开启 StatViewServlet
        login-username: admin # 账号
        login-password: 123456 # 密码
// DataSourceConfig.java
 
@Configuration
public class DataSourceConfig {
 
    /**
     * 创建 orders 数据源
     */
    @Primary
    @Bean(name = "ordersDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.orders") // 读取 spring.datasource.orders 配置到 HikariDataSource 对象
    public DataSource ordersDataSource() {
        return DruidDataSourceBuilder.create().build();
    }
 
    /**
     * 创建 users 数据源
     */
    @Bean(name = "usersDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.users")
    public DataSource usersDataSource() {
        return DruidDataSourceBuilder.create().build();
    }
 
}

6 缓存

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

@SpringBootApplication
@EnableCaching
public class YourApplication {
    public static void main(String[] args) {
        SpringApplication.run(YourApplication.class, args);
    }
}
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Arrays;

@Configuration
@EnableCaching
public class CacheConfig {

    @Bean
    public CacheManager cacheManager() {
        // 创建一个基于 ConcurrentMap 的缓存管理器
        return new ConcurrentMapCacheManager(
                Arrays.asList("myCache") // 定义缓存名称
        );
    }
}
  1. 使用缓存:在需要缓存的方法上添加 @Cacheable 注解。
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

@Service
public class YourService {

    @Cacheable(value = "myCache", key = "#id") // 使用名为 myCache 的缓存,key 为方法参数 id
    public String getSomeData(int id) {
        // 模拟从数据库或其他数据源获取数据
        System.out.println("Fetching data from source for id: " + id);
        return "Data for id " + id;
    }
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class YourController {

    @Autowired
    private YourService yourService;

    @GetMapping("/data/{id}")
    public String getData(@PathVariable int id) {
        return yourService.getSomeData(id);
    }
}

redis注解

<?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>org.example</groupId>
    <artifactId>redisCache</artifactId>
    <version>1.0-SNAPSHOT</version>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.3</version>
    </parent>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>

    <dependencies>
        <!-- Spring Boot Starter Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- MyBatis-Plus -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.4</version>
        </dependency>
        <!-- Redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <version>3.1.3</version>
        </dependency>
        <!-- Spring Boot 缓存启动器 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
            <version>3.1.3</version>
        </dependency>
        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- MySQL 驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.33</version>
        </dependency>
    </dependencies>

</project>
@RestController
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/users/{id}")
    public User getUserById(@PathVariable Long id) {
        return userService.getUserById(id);
    }
}
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
@Data
@TableName("user")
public class User implements Serializable {
    @TableId
    private Long id;
    private String name;
    private Integer age;
}
@Service
@CacheConfig(cacheNames = "users") // 指定缓存名称为 users
public class UserService {

    @Autowired
    private UserMapper userMapper;

    @Cacheable(key = "#id") // 使用方法参数 id 作为缓存的 key
    public User getUserById(Long id) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", id);
        return userMapper.selectOne(queryWrapper);
    }
}
@SpringBootApplication
@EnableCaching // 启用缓存功能
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
# MySQL 配置
spring.datasource.url=jdbc:mysql://localhost:3306/user?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# Redis 配置
spring.data.redis.host=localhost
spring.data.redis.port=6379

# 缓存类型使用 Redis
spring.cache.type=redis

mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

logging.level.org.springframework.cache=DEBUG

第一次会有日志出现,之后都从缓存中取,没有日志出现

猜你喜欢

转载自blog.csdn.net/weixin_51721783/article/details/146387835
今日推荐