Spring Boot Auto-Configuration

news2024/11/17 11:31:34

Spring 自定义Auto-Configuration

Spring Boot 可以根据classpath中依赖关系自动装配应用程序。通过自动装配机制,可以使开发更快、更简单。今天,学习下如何在Spring Boot 中创建自定义 auto-configuration。

代码运行环境

  • JDK17
  • MYSQL8
  • 源码地址

Maven 依赖

首先添加以下依赖

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
  <version>2.7.5</version>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-jpa</artifactId>
  <version>2.7.5</version>
</dependency>
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>8.0.19</version>
</dependency>

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-test</artifactId>
  <version>2.7.5</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.13.1</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>javax.xml.bind</groupId>
  <artifactId>jaxb-api</artifactId>
  <version>2.3.1</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-test</artifactId>
  <version>5.3.23</version>
  <scope>test</scope>
</dependency>

创建自动装配

为了创建自动装配机制,首先创建一个类,并使用 @Configuration注解标记。以创建一个Mysql数据源为例

@Configuration
public class MySQLAutoconfiguration {
    //...
}

接下来,需要将类注册到Spring Boot 容器中。创建 resources/META-INF/spring.factories文件, 内容如下:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.spring.boot.autoconfig.MySQLAutoconfiguration
  • 如果想要自定义的装配有更高的优先级,需要添加 @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) 注解即可。
  • 开发者可以使用 @Conditional 注解标记 auto-configuration的类,以便在条件满足时激活自动装配.
  • bean的默认作用于为单例,如果开发者自定义的bean 装配跟框架内定义的bean一致,则会覆盖默认的bean定义

Class Conditions

Conditions 系列注解允许开发者定义 当指定条件满足时才会加载 auto-configuration.

  • @ConditionalOnClass 当指定类存在时 条件满足
  • @ConditionalOnMissingClass 当指定类不存在时 条件满足
@Configuration
@ConditionalOnClass(DataSource.class)
public class MySQLAutoconfiguration {
    //...
}

上述代码指定当 DataSource.class 存在时,@Configuration 装配的逻辑才生效。

Bean Conditions

指定的bean是否存在,由此来确定是否加载 @Configuration

  • @ConditionalOnBean - bean存在时 条件满足
  • @ConditionalOnMissingBean - bean不存在时 条件满足

接下来,在 configuration class中增加 数据源定义. 开发者期望同时满足以下两个条件,才会创建bean

  1. 当容器中存在以 datasource 命名的bean
  2. 当容器中不存在entityManagerFactory类型的bean
@Bean
@ConditionalOnBean(name = "dataSource")
@ConditionalOnMissingBean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
    LocalContainerEntityManagerFactoryBean em
      = new LocalContainerEntityManagerFactoryBean();
    em.setDataSource(dataSource());
    em.setPackagesToScan("com.spring.boot");
    em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
    if (additionalProperties() != null) {
        em.setJpaProperties(additionalProperties());
    }
    return em;
}

以同样的方式创建事务管理的bean

@Bean
@ConditionalOnMissingBean(type = "JpaTransactionManager")
JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
    JpaTransactionManager transactionManager = new JpaTransactionManager();
    transactionManager.setEntityManagerFactory(entityManagerFactory);
    return transactionManager;
}

Property Conditions

开发者可以使用@ConditionalOnProperty注解通过判断Spring 环境中是否存在相关属性来确定是否进行自动装配。

首先,在 resource 目录下创建 mysql.perperties

usemysql=local

mysql-hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
mysql-hibernate.show_sql=true
mysql-hibernate.hbm2ddl.auto=update

其次,使用@PropertySource注解以mysql.perperties是否存在为条件,决定是否加载配置

@PropertySource("classpath:mysql.properties")
public class MySQLAutoconfiguration {
    //...
}

接下来,我们使用两种方式创建建数据库连接

  • 硬编码方式
@Bean
@ConditionalOnProperty(name = "usemysql", havingValue = "local")
@ConditionalOnMissingBean
public DataSource dataSource() {
    DriverManagerDataSource dataSource = new DriverManagerDataSource();
 
    dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
    //此处需要根据实际情况进行修改
    dataSource.setUrl("jdbc:mysql://localhost:3306/myDb?createDatabaseIfNotExist=true");
    dataSource.setUsername("root");
    dataSource.setPassword("123456");

    return dataSource;
}
  • 配置文件的方式
@Bean(name = "dataSource")
@ConditionalOnProperty(
  name = "usemysql", 
  havingValue = "custom")
@ConditionalOnMissingBean
public DataSource dataSource2() {
    DriverManagerDataSource dataSource = new DriverManagerDataSource();
        
    dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
    dataSource.setUrl(env.getProperty("mysql.url"));
    dataSource.setUsername(env.getProperty("mysql.user") != null 
      ? env.getProperty("mysql.user") : "");
    dataSource.setPassword(env.getProperty("mysql.pass") != null 
      ? env.getProperty("mysql.pass") : "");
        
    return dataSource;
}

上述两个方法将条件装配的特性展现的淋漓尽致,并且对开发者十分友好。可以在配置文件中指定相关属性,实现按需加载。 开发环境加载dataSource,测试环境加载datasource2.

Resource Conditions

@ConditionalOnResource注解表示当指定资源存在时,才会进行自动装配。定义一个additionalProperties() 方法,该方法返回entityManagerFactory bean需要使用的 Hibernate 相关属性。

@ConditionalOnResource(
  resources = "classpath:mysql.properties")
@Conditional(HibernateCondition.class)
Properties additionalProperties() {
    Properties hibernateProperties = new Properties();

    hibernateProperties.setProperty("hibernate.hbm2ddl.auto", 
      env.getProperty("mysql-hibernate.hbm2ddl.auto"));
    hibernateProperties.setProperty("hibernate.dialect", 
      env.getProperty("mysql-hibernate.dialect"));
    hibernateProperties.setProperty("hibernate.show_sql", 
      env.getProperty("mysql-hibernate.show_sql") != null 
      ? env.getProperty("mysql-hibernate.show_sql") : "false");
    return hibernateProperties;
}

自定义 Conditions

之前介绍的各种 条件装配注解,基本能满足绝大多数业务需求。此外,Spring Boot 也预留了接口让开发者实现自定义的条件注解。我们来实现一个自定义装配的类,作用是判断 HibernateEntityManager 类是否在classpath中

static class HibernateCondition extends SpringBootCondition {

    private static String[] CLASS_NAMES
      = { "org.hibernate.ejb.HibernateEntityManager", 
          "org.hibernate.jpa.HibernateEntityManager" };

    @Override
    public ConditionOutcome getMatchOutcome(ConditionContext context, 
      AnnotatedTypeMetadata metadata) {
 
        ConditionMessage.Builder message
          = ConditionMessage.forCondition("Hibernate");
        return Arrays.stream(CLASS_NAMES)
          .filter(className -> ClassUtils.isPresent(className, context.getClassLoader()))
          .map(className -> ConditionOutcome
            .match(message.found("class")
            .items(Style.NORMAL, className)))
          .findAny()
          .orElseGet(() -> ConditionOutcome
            .noMatch(message.didNotFind("class", "classes")
            .items(Style.NORMAL, Arrays.asList(CLASS_NAMES))));
    }
}

然后在 additionalProperties() 方法上增加注解

@Conditional(HibernateCondition.class)
Properties additionalProperties() {
  //...
}

应用级别 Conditions

此外,开发者可以使用以下注解指定 web 上下文中满足指定条件

  • @ConditionalOnWebApplication - web应用才会满足条件
  • @ConditionalOnNotWebApplication - 非web应用才会满足条件

验证测试

创建实体文件

package com.spring.boot.entity;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class User {
    @Id
    private Long id;
    private String email;
    public User() {
    }
    public User(String email,Long id) {
        super();
        this.email = email;
        this.id = id;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
}

创建Repository

public interface MyUserRepository 
  extends JpaRepository<MyUser, String> { }

开启自动装配

为了开启自动装配启动类上,增加*@SpringBootApplication* 或 @EnableAutoConfiguration注解。

@SpringBootApplication
public class AutoconfigurationApplication {
    public static void main(String[] args) {
        SpringApplication.run(AutoconfigurationApplication.class, args);
    }
}

测试类

import com.spring.boot.AutoConfigurationApplication;
import com.spring.boot.entity.User;
import com.spring.boot.repository.UserRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;


@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = AutoConfigurationApplication.class)
@EnableJpaRepositories(basePackages = { "com.spring.boot" })
public class AutoconfigurationTest {

    @Autowired
    private UserRepository userRepository;

    @Test
    public void whenSaveUser_thenOk() {
        User user = new User("user@email.com",1000L);
        userRepository.save(user);
    }
}

运行测试方法,并在mysql数据库中相关记录

在这里插入图片描述

禁止自动装配

开发者可以通过以下两种方式禁止指定的自动装配

  • 代码方式

    @Configuration
    @EnableAutoConfiguration(
      exclude={MySQLAutoconfiguration.class})
    public class AutoconfigurationApplication {
        //...
    }
    
  • 配置方式

    spring.autoconfigure.exclude=com.baeldung.autoconfiguration.MySQLAutoconfiguration
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/30208.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[附源码]Python计算机毕业设计大学生心理健康管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

VSCODE编译阿里云HaaS程序时遇到Win32file找不到错误怎么办?

摘要&#xff1a;本文介绍DLL load failed while importing win32file&#xff1a;找不到指定的程序&#xff0c;这个错误的解决方法。使用vscode拉取阿里云HaaS物联网开发案例代码时&#xff0c;可能会遇到编译出错的情况&#xff0c;可能会遇到一些意外的问题&#xff0c;并非…

通过Native Memory Tracking查JVM的线程内存使用(线上JVM排障之九)

很多时候会面对线上内存使用很多,特别是本地内存怎么用的说不太清,就是每一块内存总和和总的Java线程占用内存不匹配。 很多时候如果dump出来内存也没有太大的作用,因为本地内存是看不到。本地内存有很多是线程占用的空间。 以下图为例,这是一个线上的服务的JVM各块内存使…

YOLOV5在deepstream6.1.1上应用

目录 0.前言 1.Yolov5模型 1.1模型生成 1.2模型转换 1.2.1 yolov5模型转换为onnx 1.2.2 onnx模型转换为engine 2.deepstream介绍 2.1简介 2.2安装 2.2.1 dGpu 2.2.2 Jetson 2.3使用方法 3.Yolov5模型在deepstream6.1.1上应用 3.1Yolov5输出与deepstream对接 3.1…

[附源码]java毕业设计学生信息管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

论文阅读:Fast Color Segementation

Fast Color Segementation 发表于CVPR 2020&#xff0c;主要是对之前的一篇图像软分割的论文&#xff08;参见&#xff1a;论文回顾&#xff1a;Unmixing-Based Soft Color Segmentation for Image Manipulation&#xff0c;Aksoy 2017&#xff09;进行改进。 一、论文简介 […

【Mac】Mac与PlayCover、Mac关闭sip

文章目录Mac笔记本使用PlayCover游玩Ipad游戏1.1 Mac 安装 PlayCover1.2 Mac 安装 原神/明日方舟1.3 注意事项Mac笔记本关闭sip2.1 查看sip状态2.2 关闭sip为什么要关闭SIP&#xff0c;关闭SIP的利与弊&#xff0c;请看&#xff1a;3.1 什么时候要关闭sip3.2 sip是什么3.3 关闭…

[附源码]Python计算机毕业设计大学生项目众筹系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

webpack详解

webpack 是代码编译工具&#xff0c;有入口、出口、loader 和插件。webpack 是一个用于现代 JavaScript 应用程序的静态模块打包工具。当 webpack 处理应用程序时&#xff0c;它会在内部构建一个依赖图(dependency graph)&#xff0c;此依赖图对应映射到项目所需的每个模块&…

Django中的CSRF使用及ajax请求接口时问题总结

前言说明 在Django中提交数据到后端服务的时候&#xff0c;为了安全&#xff0c;要使用CSRF&#xff08;跨站请求伪造&#xff09;。跨站请求伪造的问题在于&#xff0c;服务器信任来自客户端的数据。 常规的做法是在template模板HTML文件中的form表单 中添加 {% csrf_token …

葡萄糖-聚乙二醇-巯基Glucose-PEG-Alkyne|葡萄糖-聚乙二醇-生物素Glucose-PEG-Biotin

葡萄糖-聚乙二醇-巯基Glucose-PEG-Alkyne 巯基&#xff0c;又称氢硫基或硫醇基&#xff0c;是由一个硫原子和一个氢原子相连组成的负一价官能团&#xff0c;化学式为-SH。巯基端连接不同的基团&#xff0c;有机物所属的类别不同&#xff0c;如硫醇&#xff08;R-SH&#xff09…

固定VMware中Linux系统的ip地址

我们的虚拟机中的Linux的ip地址默认是随机的&#xff0c;那就导致了如果我们要配置例如finshell这类的远程连接&#xff0c;就需要常常修改ip地址&#xff0c;非常的麻烦啊&#xff0c;那有没有什么办法可以固定这个IP呢。 方法肯定是有的 首先我们打开VMware 点这个 之后修改…

LeGO-LOAM

LeGO-LOAM: Lightweight and Ground-Optimized Lidar Odometry and Mapping on Variable Terrain 在可变地形上的轻量级的利用地面点优化的Iidar 里程计和 建图 作者&#xff1a;Tixiao Shan and Brendan Englot Abstract— We propose a lightweight and ground-optimized …

Bi-CLKT: Bi-Graph Contrastive Learning based Knowledge Tracing

图对比学习 文章目录摘要1 引言2 相关工作2.2 自监督学习2.3 图上的对比学习摘要 知识追踪(KT)的目标是根据学生对相关练习的历史学习来估计他们对一个概念的掌握程度。知识追踪的好处是可以更好地组织和调整学生的学习计划&#xff0c;并在必要时进行干预。随着深度学习的兴起…

回顾10年发展,2022亚马逊云科技re:Invent全球大会即将来袭

每年的亚马逊云科技re:Invent全球大会&#xff0c;都是全球云计算领域每年创新发布的关键节点&#xff0c;亚马逊云科技的这些技术发布&#xff0c;无一例外地成为了云计算领域技术发展的风向标&#xff0c;而今年的re:Invent全球大会即将启幕&#xff01; 2012年&#xff0c;亚…

Java基础40 断点调试(Debug)

DebugDebug介绍一、debug的使用二、Debug的使用使用1使用2 数组越界异常使用3 追溯源码使用4 直接执行到下一个断点Debug介绍 在开发中&#xff0c;新手程序员在查找错误时&#xff0c;这时老程序员就会提示&#xff0c;可以使用断点调试&#xff0c;一步一步的看源码执行的过…

使用QT绘制一个多边形

目录 1. 概述2. 实现2.1. 代码2.2. 解析3. 结果 1. 概述 可以通过QT的重绘事件和鼠标事件来绘制多边形&#xff0c;最简单的办法就是在继承QWidget的窗体中重写paintEvent、mousePressEvent等事件处理函数。QT提供了图形绘制接口QPainter&#xff0c;通过该接口可以绘制多种图…

易基因|脂多糖诱导的仔猪肝脏损伤模型中m6A RNA甲基化介导了NOD1/NF-kB信号激活

大家好&#xff0c;这里是专注表观组学十余年&#xff0c;领跑多组学科研服务的易基因。 2022年9月30日&#xff0c;南京农业大学动物科技学院钟翔教授团队在《ANTIOXIDANTS-BASEL》杂志发表题为“m6A RNA Methylation Mediates NOD1/NF-kB Signaling Activation in the Liver…

AlmaLinux 9上安装Kubernetes 1.25集群

AlmaLinux 9上安装Kubernetes 1.25集群 0. 确认Linux版本 uname -a1. 禁用swap sudo swapoff -a2. 禁用防火墙 sudo systemctl stop firewalld sudo systemctl disable firewalld3. 将SELinux设置为permissive模式 sudo setenforce 0 sudo sed -i s/^SELINUXenforcing$/SE…

Postgres 史上最垃圾的高可用软件之 - CLup

1. Clup 简介 CLup最大的特色功能是高可用。目前已存在几个开源的高可用软件: keepalived: 是一个较简单的高可用软件&#xff0c;其最早是于用LVS负载均衡软件&#xff0c;现在也常常用于ngnix的高可用&#xff0c;也可以用于数据库领域&#xff0c;但需要自己定制切换脚本才…