Spring Boot 2 实践记录之 条件装配
实验项目是想要使用多种数据库访问方式,比如 JPA 和 MyBatis。
项目的 Service 层业务逻辑相同,只是具体实现代码不同,自然是一组接口,两组实现类的架构比较合理。
不过这种模式却有一个问题,如果 Bean 是按实现类装配,则在切换数据库访问方式时,就需要大量的代码修改。如果按接口装配,则会出现歧义(同一接口有两个实现,无法自动装配)。
虽然可以使用「首选Bean」或「限定」装配,但是与直接使用实现类装配一样,切换数据库访问地,仍然要大量修改源码。
经过实验,使用「条件装配」实现了利用配置切换数据库访问方式,不需要修改代码了。
示例:
先定义 Service 接口:
public interface UserServiceInterface {
......
}
再定义 MyBatis 实现类:
@Service
@Conditional(MybatisCondition.class)
public class UserServiceMybatisImpl implements UserServiceInterface {
......
}
注意其中的 @Conditional(MybatisCondition.class),MybatisCondition 类必须实现 org.springframework.context.annotation.Condition 接口,该接口仅有一个 matches 方法,当该方法返回真时,UserServiceMybatisImpl 被装配。
MybatisCondition 的 matches 方法的逻辑被实现为根据配置文件中的 use.data.access.method 属性是否为 mybatis,来决定是否装配 UserServiceMybatisImpl 类:
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata; public class MybatisCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment env = context.getEnvironment();
if (env.getProperty("use.data.access.method").equals("mybatis")) {
return true;
}
return false;
}
}
再定义 SPA 实现类及其 SpaCondition 类,实现方式与 Mybatis 相同,仅在配置项为 spa 时,装配 UserServiceSpaImpl 类:
@Service
@Conditional(SpaCondition.class)
public class UserServiceSpaImpl implements UserServiceInterface {
......
}
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata; public class SpaCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment env = context.getEnvironment();
if (env.getProperty("use.data.access.method").equals("spa")) {
return true;
}
return false;
}
}
定义一个类,自动装配 UserServiceInterface,并打印其类名:
public class Test {
@Autowired
private UserServiceInterface userServiceInterface;
public void testUserService() {
System.out.println(userServiceInterface.getClass();
}
}
现在还不能运行,需要添加配置项。
先将配置项配置为 mybatis:
use.data.access.method = mybatis
运行 Test 类的 testUserService 方法,结果为:
UserServiceMybatisImpl
将配置项修改为 spa:
use.data.access.method = spa
运行 Test 类的 testUserService 方法,结果为:
UserServiceSpaImpl
不过,有个小小的缺憾,就是在 Idea 中,如下代码行:
@Autowired
private UserServiceInterface userServiceInterface;
会有错误提示:
Could not autowire. There is more than one bean of 'UserServiceInterface' type.
Beans:
userServiceMybatisImpl (UserServiceMybatisImpl.java)
userServiceSpaImpl (UserServiceSpaImpl.java)
由于配置项是在运行时读取的,Idea 在静态语法检查时,实在没办法搞定这个自动装配的判断。
没关系,不影响运行!
Spring Boot 2 实践记录之 条件装配的更多相关文章
- Spring Boot 2 实践记录之 使用 ConfigurationProperties 注解将配置属性匹配至配置类的属性
在 Spring Boot 2 实践记录之 条件装配 一文中,曾经使用 Condition 类的 ConditionContext 参数获取了配置文件中的配置属性.但那是因为 Spring 提供了将上 ...
- Spring Boot 2 实践记录之 封装依赖及尽可能不创建静态方法以避免在 Service 和 Controller 的单元测试中使用 Powermock
在前面的文章中(Spring Boot 2 实践记录之 Powermock 和 SpringBootTest)提到了使用 Powermock 结合 SpringBootTest.WebMvcTest ...
- Spring Boot 2 实践记录之 MyBatis 集成的启动时警告信息问题
按笔者 Spring Boot 2 实践记录之 MySQL + MyBatis 配置 中的方式,如果想正确运行,需要在 Mapper 类上添加 @Mapper 注解. 但是加入此注解之后,启动时会出现 ...
- Spring Boot 2 实践记录之 Redis 及 Session Redis 配置
先说 Redis 的配置,在一些网上资料中,Spring Boot 的 Redis 除了添加依赖外,还要使用 XML 或 Java 配置文件做些配置,不过经过实践并不需要. 先在 pom 文件中添加 ...
- Spring Boot 2 实践记录之 Powermock 和 SpringBootTest
由于要代码中使用了 Date 类生成实时时间,单元测试中需要 Mock Date 的构造方法,以预设其行为,这就要使用到 PowerMock 在 Spring Boot 的测试套件中,需要添加 @Ru ...
- Spring Boot 2 实践记录之 使用 Powermock、Mockito 对 UUID 进行 mock 单元测试
由于注册时,需要对输入的密码进行加密,使用到了 UUID.sha1.md 等算法.在单元测试时,使用到了 Powermock,记录如下. 先看下加密算法: import org.apache.comm ...
- Spring Boot 2 实践记录之 组合注解原理
Spring 的组合注解功能,网上有很多文章介绍,不过都是介绍其使用方法,鲜有其原理解析. 组合注解并非 Java 的原生能力.就是说,想通过用「注解A」来注解「注解B」,再用「注解B」 来注解 C( ...
- Spring Boot 2 实践记录之 MySQL + MyBatis 配置
如果不需要连接池,那么只需要简单的在pom文件中,添加mysql依赖: <dependency> <groupId>mysql</groupId> <arti ...
- Spring Boot 报错记录
Spring Boot 报错记录 由于新建的项目没有配置数据库连接启动报错,可以通过取消自动数据源自动配置来解决 解决方案1: @SpringBootApplication(exclude = Dat ...
随机推荐
- springboot取得resources下的文件
参考http://blog.csdn.net/programmeryu/article/details/58002218 ResourceUtils.getFile("classpath:p ...
- SpringCloud 简单理解
0.SpringCloud,微服务架构.包括 服务发现(Eureka),断路器(Hystrix),服务网关(Zuul),客户端负载均衡(Ribbon).服务跟踪(Sleuth).消息总线(Bus).消 ...
- Dungeon Game (GRAPH - DP)
QUESTION The demons had captured the princess (P) and imprisoned her in the bottom-right corner of a ...
- 最小重组缓冲区和路径MTU发现
概括: 主要来源于unp,可参考:http://blog.csdn.net/ysu108/article/details/7764461 疑惑: 1. 最小重组缓冲区大小: ipv4为576,ipv6 ...
- C++重载、重写(覆盖)、隐藏
类成员函数中重载/重写(覆盖)/重定义(隐藏)的区别? 答:分别简单讲述一下函数重载,函数覆盖,函数隐藏的概念与特征: 函数重载:重载函数通常用来命名一组功能相似的函数 1.函数要在相同的类域 2.函 ...
- fragment 事务回滚 ---动态创建fragment
import java.util.Date; import java.util.LinkedList; import com.qianfeng.gp08_day23_fragment5.fragmen ...
- springboot与elasticsearch
1.安装elasticsearch 下载elasticsearch docker pull registry.docker-cn.com/library/elasticsearch 运行elastic ...
- PHP下ajax跨域的解决方案之jsonp
首先要说明一下json和jsonp的区别? json是一种基于文本的数据交换方式,或者叫做描述数据的一种格式. var person = { "name": "test& ...
- .NET获得上传图片宽高
代码: //图片大小限制--------------------------- System.Drawing.Image txtStoryimage = System.Drawing.Image.Fr ...
- Linux 配置文件管理
一.简介 参考:https://robots.thoughtbot.com/rcm-for-rc-files-in-dotfiles-repos http://dotfiles.github.io/ ...