實驗項目是想要使用多種數據庫訪問方式,好比 JPA 和 MyBatis。java
項目的 Service 層業務邏輯相同,只是具體實現代碼不一樣,天然是一組接口,兩組實現類的架構比較合理。spring
不過這種模式卻有一個問題,若是 Bean 是按實現類裝配,則在切換數據庫訪問方式時,就須要大量的代碼修改。若是按接口裝配,則會出現歧義(同一接口有兩個實現,沒法自動裝配)。數據庫
雖然能夠使用「首選Bean」或「限定」裝配,可是與直接使用實現類裝配同樣,切換數據庫訪問地,仍然要大量修改源碼。mybatis
通過實驗,使用「條件裝配」實現了利用配置切換數據庫訪問方式,不須要修改代碼了。架構
示例:ide
先定義 Service 接口:spa
public interface UserServiceInterface { ...... }
再定義 MyBatis 實現類:code
@Service @Conditional(MybatisCondition.class) public class UserServiceMybatisImpl implements UserServiceInterface { ...... }
注意其中的 @Conditional(MybatisCondition.class),MybatisCondition 類必須實現 org.springframework.context.annotation.Condition 接口,該接口僅有一個 matches 方法,當該方法返回真時,UserServiceMybatisImpl 被裝配。blog
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 在靜態語法檢查時,實在沒辦法搞定這個自動裝配的判斷。
不要緊,不影響運行!