SpringBoot自动装配-Import
1. 简介
@Import导入的类会被Spring加载到IOC容器中。而@Import提供4中用法:
导入Bean
导入配置类
导入 ImportSelector 实现类。一般用于加载配置文件中的类
导入 ImportBeanDefinitionRegistrar 实现类。
2. 定义
@Import
注解定义如下,其内部只有一个参数为Class对象数组
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
Class<?>[] value();
}
3. 使用说明
通过一个简单的小例子测试一下@Import
是不是真的能实现Bean的注入
3.1 创建项目
3.1.1 导入依赖
这里我们除了springboot依赖,再添加个lombok依赖
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.ldx</groupId>
<artifactId>import-annotation</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>import-annotation</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
3.1.2 创建User类
package com.ldx.importannotation;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* 用户信息实体
* @author ludangxin
* @date 2021/8/1
*/
@Data
@AllArgsConstructor
public class User {
public User() {
this.name = "李四";
this.age = 13;
}
private String name;
private Integer age;
}
3.2 测试导入Bean
3.2.1 修改启动类
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Import;
@Slf4j
// 注入UserBean
@Import(value = User.class)
@SpringBootApplication
public class ImportAnnotationApplication {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(ImportAnnotationApplication.class, args);
User user = applicationContext.getBean(User.class);
log.info("user info ==={}",user);
}
}
3.2.2 启动测试
UserBean注入成功。
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.5.3)
2021-08-01 19:36:55.243 INFO 49498 --- [ main] c.l.i.ImportAnnotationApplication : Starting ImportAnnotationApplication using Java 1.8.0_261 on ludangxindeMacBook-Pro.local with PID 49498 (/Users/ludangxin/workspace/idea/import-annotation/target/classes started by ludangxin in /Users/ludangxin/workspace/idea/import-annotation)
2021-08-01 19:36:55.245 INFO 49498 --- [ main] c.l.i.ImportAnnotationApplication : No active profile set, falling back to default profiles: default
2021-08-01 19:36:55.731 INFO 49498 --- [ main] c.l.i.ImportAnnotationApplication : Started ImportAnnotationApplication in 0.893 seconds (JVM running for 1.417)
2021-08-01 19:36:55.735 INFO 49498 --- [ main] c.l.i.ImportAnnotationApplication : user info ===User(name=李四, age=13)
3.3 测试导入配置类
3.3.1 创建UserConfig类
import org.springframework.context.annotation.Bean;
/**
* 用户配置类
* @author ludangxin
* @date 2021/8/1
*/
public class UserConfig {
@Bean
public User getUser(){
return new User();
}
}
3.3.2 修改启动类
将启动类上的@Import
的value指向UserConfig
类
@Import(value = UserConfig.class)
3.3.3 启动测试
UserBean注入成功。
3.4 测试导入ImportSelector
3.4.1 创建UseImportSelector类
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
/**
* 用户Bean选择器配置类
* @author ludangxin
* @date 2021/8/1
*/
public class UseImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
// 指定User类的全限类名
return new String[]{"com.ldx.importannotation.User"};
}
}
3.4.2 修改启动类
将启动类上的@Import
的value指向UseImportSelector
类
@Import(value = UseImportSelector.class)
3.4.3 启动测试
UserBean注入成功。
3.5 测试导入ImportBeanDefinitionRegistrar类
3.5.1 创建UserImportBeanDefinitionRegistrar
package com.ldx.importannotation;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
/**
* 用户Bean定义注册配置类
* @author ludangxin
* @date 2021/8/1
*/
public class UserImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 创建User类型的Bean的定义
BeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition();
// 将创建的UserBean定义注册到SpringRegistry中,其名称为user
registry.registerBeanDefinition("user", beanDefinition);
}
}
3.5.2 修改启动类
将启动类上的@Import
的value指向UserImportBeanDefinitionRegistrar
类
@Import(value = UserImportBeanDefinitionRegistrar.class)
3.5.3 启动测试
UserBean注入成功。
3.6 小结
简介中介绍的四种方式都可以注入UserBean。
好处:
- 导入指定的Bean或配置类。例如:由于业务需要将包路径或者需要加载的Bean类不在
@ComponentScan
的扫描范围内,这时候我们就可以通过@Import
来实现Bean的注入。 - ImportSelector方式是制定需要加载类的全限类名。这时候我们就可以将我们的需要装载的类写到配置文件中,比如某个txt中,然后项目启动的时候读取txt中的全限类名,实现Bean的装载。SpringBoot就是使用这种方式实现的自动装配。
4. 改进
上面的例子通过使用@Import
注解实现了spring bean的自动注入。但是装载Bean每次都得指定Bean的类或者配置类,在生产环境中我们在使用第三方Jar的时候根本不知道应该使用哪个配置文件或者压根就不知道配置文件的名称。这时我们其实可以扩展一个注解来优化这个问题。
4.1 创建注解
package com.ldx.importannotation;
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
/**
* 启用User配置信息注解
* @author ludangxin
* @date 2021/8/1
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
// 指定需要导入的UserBean的配置类
@Import(UseImportSelector.class)
public @interface EnableUser {}
4.2 修改启动类
注掉之前的@Import
,使用刚创建的@EnableUser
注解
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Import;
@Slf4j
//@Import(value = UserImportBeanDefinitionRegistrar.class)
@EnableUser
@SpringBootApplication
public class ImportAnnotationApplication {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(ImportAnnotationApplication.class, args);
User user = applicationContext.getBean(User.class);
log.info("user info ==={}",user);
}
}
4.3 启动测试
UserBean注入成功。
思考
SpringBoot项目中能不能直接获取或者使用Jar包中的Bean呢?
5. 验证
5.1 创建项目
user模块为Bean的提供者,book-manage通过引入user模块Jar,来验证项目中能不能直接使用Jar中的Bean
5.2 创建user模块
5.2.1 导入依赖
没啥特别的依赖
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.ldx</groupId>
<artifactId>user</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>user</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
5.2.2 创建User类
package com.ldx.user;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.List;
/**
* 用户信息类
* @author ludangxin
* @date 2021/8/1
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Integer id;
private String name;
/**
* 角色状态吗 1.管理员 2.老师 3.学生
*/
private Character role;
private Integer age;
public User getUserInfo() {
return new User(66, "张三", '3', 21);
}
/**
* 获取其任课老师信息
*/
public List<User> getTeachers() {
List<User> users = new ArrayList<>();
User user = new User();
user.setId(2);
user.setName("王麻子");
user.setAge(45);
user.setRole('2');
User user1 = new User();
user1.setId(3);
user1.setName("李四");
user1.setAge(35);
user1.setRole('2');
users.add(user);
users.add(user1);
return users;
}
}
5.2.3 修改启动类
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
@Slf4j
@SpringBootApplication
public class UserApplication {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(UserApplication.class, args);
User user = applicationContext.getBean(User.class);
user.getTeachers().forEach(obj ->
log.info("user teacher info ==={} ", obj)
);
}
@Bean
public User getUser() {
return new User();
}
}
5.2.4 启动测试
在user模块中先验证下User Bean注册的正确性,log如下:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.5.3)
2021-08-01 21:09:54.666 INFO 51037 --- [ main] com.ldx.user.UserApplication : Starting UserApplication using Java 1.8.0_261 on ludangxindeMacBook-Pro.local with PID 51037 (/Users/ludangxin/workspace/idea/verifyusejarbean/user/target/classes started by ludangxin in /Users/ludangxin/workspace/idea/verifyusejarbean)
2021-08-01 21:09:54.669 INFO 51037 --- [ main] com.ldx.user.UserApplication : No active profile set, falling back to default profiles: default
2021-08-01 21:09:55.151 INFO 51037 --- [ main] com.ldx.user.UserApplication : Started UserApplication in 0.818 seconds (JVM running for 1.317)
2021-08-01 21:09:55.155 INFO 51037 --- [ main] com.ldx.user.UserApplication : user teacher info ===User(id=2, name=王麻子, role=2, age=45)
2021-08-01 21:09:55.156 INFO 51037 --- [ main] com.ldx.user.UserApplication : user teacher info ===User(id=3, name=李四, role=2, age=35)
user bean 注册成功。
5.2.5 装载Jar
点击idea maven插件的install将jar装载到本地仓库
5.3 创建book-manage模块
5.3.1 导入依赖
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.ldx</groupId>
<artifactId>book-manage</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>book-manage</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- user模块依赖 -->
<dependency>
<groupId>com.ldx</groupId>
<artifactId>user</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
5.3.2 修改启动类
直接获取User Bean 并调用getUserInfo
方法
import com.ldx.user.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@Slf4j
@SpringBootApplication
public class BookManageApplication {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(BookManageApplication.class, args);
User user = applicationContext.getBean(User.class);
log.info("user info === {}", user.getUserInfo());
}
}
5.3.3 启动测试
启动报错,没有可用的User Bean
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.5.3)
2021-08-01 21:15:09.219 INFO 51124 --- [ main] c.ldx.bookmanage.BookManageApplication : Starting BookManageApplication using Java 1.8.0_261 on ludangxindeMacBook-Pro.local with PID 51124 (/Users/ludangxin/workspace/idea/verifyusejarbean/book-manage/target/classes started by ludangxin in /Users/ludangxin/workspace/idea/verifyusejarbean)
2021-08-01 21:15:09.221 INFO 51124 --- [ main] c.ldx.bookmanage.BookManageApplication : No active profile set, falling back to default profiles: default
2021-08-01 21:15:09.623 INFO 51124 --- [ main] c.ldx.bookmanage.BookManageApplication : Started BookManageApplication in 0.707 seconds (JVM running for 1.133)
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.ldx.user.User' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:351)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:342)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1172)
at com.ldx.bookmanage.BookManageApplication.main(BookManageApplication.java:15)
6. 改进
在5.0章节中我们验证了直接使用jar包中的bean时不可取的,那有什么办法能解决么?
这时候我们就可以使用4.0中的Enable注解来解决这个问题。
6.1 在user模块中添加Enable注解
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
/**
* 启用User配置信息注解
* @author ludangxin
* @date 2021/8/1
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(User.class)
public @interface EnableUser {}
6.2 修改book-manage模块中的启动类
在book-manage
模块的启动类上加上@EnableUser
注解
6.3 启动验证
user bean 注入成功。
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.5.3)
2021-08-01 21:18:55.686 INFO 51193 --- [ main] c.ldx.bookmanage.BookManageApplication : Starting BookManageApplication using Java 1.8.0_261 on ludangxindeMacBook-Pro.local with PID 51193 (/Users/ludangxin/workspace/idea/verifyusejarbean/book-manage/target/classes started by ludangxin in /Users/ludangxin/workspace/idea/verifyusejarbean)
2021-08-01 21:18:55.688 INFO 51193 --- [ main] c.ldx.bookmanage.BookManageApplication : No active profile set, falling back to default profiles: default
2021-08-01 21:18:56.145 INFO 51193 --- [ main] c.ldx.bookmanage.BookManageApplication : Started BookManageApplication in 0.762 seconds (JVM running for 1.223)
2021-08-01 21:18:56.148 INFO 51193 --- [ main] c.ldx.bookmanage.BookManageApplication : user info === User(id=66, name=张三, role=3, age=21)
7. 小结
- 不能直接在当前项目中使用Jar中的Bean(SpringBoot默认使用
ImportSelector
的方式加载META-INF/spring.factories
中指定的配置类,会导致只需要导入相应的第三方Jar就可以使用其环境中的Bean) - 可以在当前项目中使用Jar包中提供的Enable注解来导入Jar的Bean配置
SpringBoot自动装配-Import的更多相关文章
- springboot自动装配
Spring Boot自动配置原理 springboot自动装配 springboot配置文件 Spring Boot的出现,得益于“习惯优于配置”的理念,没有繁琐的配置.难以集成的内容(大多数流行第 ...
- 一步步从Spring Framework装配掌握SpringBoot自动装配
目录 Spring Framework模式注解 Spring Framework@Enable模块装配 Spring Framework条件装配 SpringBoot 自动装配 本章总结 Spring ...
- SpringBoot启动流程分析(五):SpringBoot自动装配原理实现
SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...
- SpringBoot自动装配原理解析
本文包含:SpringBoot的自动配置原理及如何自定义SpringBootStar等 我们知道,在使用SpringBoot的时候,我们只需要如下方式即可直接启动一个Web程序: @SpringBoo ...
- Spring Boot之从Spring Framework装配掌握SpringBoot自动装配
Spring Framework模式注解 模式注解是一种用于声明在应用中扮演“组件”角色的注解.如 Spring Framework 中的 @Repository 标注在任何类上 ,用于扮演仓储角色的 ...
- springboot自动装配原理
最近开始学习spring源码,看各种文章的时候看到了springboot自动装配实现原理.用自己的话简单概括下. 首先打开一个基本的springboot项目,点进去@SpringBootApplica ...
- springboot自动装配原理,写一个自己的start
springboot自动装配原理 第一次使用springboot的时候,都感觉很神奇.只要加入一个maven的依赖,写几行配置,就能注入redisTemple,rabbitmqTemple等对象. 这 ...
- 【Springboot】Springboot自动装配原理
1.核心注解就是 EnableAutoConfiguration 该注解会激活SpringBoot的自动装配功能: 代码如下: @Target(ElementType.TYPE) @Retentio ...
- SpringBoot自动装配-自定义Start
SpringBoot自动装配 在没有使用SpringBoot之前,使用ssm时配置redis需要在XML中配置端口号,地址,账号密码,连接池等等,而使用了SpringBoot后只需要在applicat ...
随机推荐
- docker 自定义部署Springboot——依赖与代码分离部署
第一步:执行mvn package 命令打出jar包,然后解压jar包,把lib放到服务器合适的目录下面 第二步:打出不带jar包的SpringBoot工程 首先配置pom.xml文件 <bui ...
- Linux 常用命令 随口说
ls cd pwd du disk usage -h -s. 文件大小 df disk free -h 磁盘占用 fdisk mount top/htop + ps + grep + wc + pki ...
- spring中BeanPostProcessor之四:AutowiredAnnotationBeanPostProcessor(01)
在<spring中BeanPostProcessor之二:CommonAnnotationBeanPostProcessor(01)>中分析了CommonAnnotationBeanPos ...
- Local dimming algorithm in matlab
LED局部背光算法的matlab仿真 最近公司接了华星光电(TCL)的一个项目LCD-BackLight-Local-Diming-Algorithm-IP ,由于没有实际的硬件,只能根据客户给的论文 ...
- 《手把手教你》系列技巧篇(六)-java+ selenium自动化测试-阅读selenium源码(详细教程)
1.简介 前面几篇基础系列文章,足够你迈进了Selenium门槛,再不济你也至少知道如何写你第一个基于Java的Selenium自动化测试脚本.接下来宏哥介绍Selenium技巧篇,主要是介绍一些常用 ...
- css 设置小知识点记录
1.消除控件与控件之间的边界 /* 公共样式 用于消除控件与控件之间的边界 */ *{ margin:0; padding:0} 2.设置背景图片大小与控件大小一致 #frame_top{ min-h ...
- webpack(1)安装环境与解决环境问题
前言 如果我们需要使用webpack,就需要依赖node环境 nvm node npm webpack@cli webpack nvm安装 nvm是一个用来管理node版本的工具.我们之所以需要使用n ...
- 在线CRM系统对企业的好处有哪些
随着信息技术的飞速发展,每个企业都希望通过互联网技术来让自身发展壮大.由于强大的管理能力和技术手段,在线CRM系统成为了企业用来管理自身获得发展的最佳选择.那么在线CRM系统对企业来说有哪些好处呢?本 ...
- 两台主机间docker容器网络互通
服务器1: 网络172.30.0.0/16 服务器2: 网络172.31.0.0/16 服务器1和服务器2上的docker容器网络之间是无法互通的,如果需要互通,需要做以下配置: 服务器1上执行: i ...
- 一小时搞懂Mysql锁机制
内容概述: 我们知道,数据也是一种供许多用户共享访问的资源.如何保证数据并发访问的一致性.有效性,是所有数据库必须解决的一个问题,锁的冲突也是影响数据库并发访问性能的一个重要因素.从这一角度来说,锁对 ...