javascript
Spring的@Primary注释在起作用
Spring是一個(gè)永不止息的框架。 這是因?yàn)樗峁┝嗽S多不同的解決方案,使我們(開(kāi)發(fā)人員)無(wú)需編寫(xiě)數(shù)百萬(wàn)行代碼即可完成我們的任務(wù)。 取而代之的是,我們能夠以更具可讀性,更標(biāo)準(zhǔn)化的方式進(jìn)行操作。 在這篇文章中,我將嘗試描述最有可能為大家所熟知的功能之一,但我認(rèn)為其重要性被低估了。 我將要討論的功能是@Primary批注。
問(wèn)題
在我從事的幾個(gè)項(xiàng)目中,我們遇到了一個(gè)常見(jiàn)的業(yè)務(wù)問(wèn)題–我們有一個(gè)進(jìn)入更復(fù)雜邏輯的入口–一些容器,該容器會(huì)將其他幾個(gè)處理器的結(jié)果收集到一個(gè)輸出中(例如map-filter-reduce函數(shù)編程中的函數(shù))。 在某種程度上,它類(lèi)似于Composite模式。 綜上所述,我們的方法如下:
有很多方法可以解決此問(wèn)題-我將介紹一種使用Spring和@Primary批注的方法。
解決方案
讓我們從定義用例如何適應(yīng)上述前提開(kāi)始。 我們的數(shù)據(jù)集是一個(gè)Person類(lèi),如下所示:
人.java
package com.blogspot.toomuchcoding.person.domain;public final class Person {private final String name;private final int age;private final boolean stupid;public Person(String name, int age, boolean stupid) {this.name = name;this.age = age;this.stupid = stupid;}public String getName() {return name;}public int getAge() {return age;}public boolean isStupid() {return stupid;} }沒(méi)有什么不尋常的。 現(xiàn)在讓我們定義合同:
PersonProcessingService.java
package com.blogspot.toomuchcoding.person.service;import com.blogspot.toomuchcoding.person.domain.Person;public interface PersonProcessingService {boolean isApplicableFor(Person person);String process(Person person); }如前提條件所述,PersonProcessingService的每個(gè)實(shí)現(xiàn)都必須定義合同的兩點(diǎn):
現(xiàn)在,讓我們看一下我們擁有的一些處理器-由于它毫無(wú)意義,所以我不會(huì)在此處發(fā)布代碼-您可以稍后在Github或Bitbucket上查看代碼。 我們有以下@Component注釋的PersonProcessingService實(shí)現(xiàn):
- AgePersonProcessingService
- 如果某人的年齡大于或等于18,則適用
- IntelligencePersonProcessingService
- 適用于某人是愚蠢的人
- NamePersonProcessingService
- 如果某人有名字,則適用
邏輯很簡(jiǎn)單。 現(xiàn)在,我們的PersonProcessingServices容器將要針對(duì)處理器上的給定Person進(jìn)行迭代,檢查當(dāng)前處理器是否適用(過(guò)濾器),如果是這種情況,則將響應(yīng)處理Person的結(jié)果字符串添加到響應(yīng)列表中(映射-將Person轉(zhuǎn)換為String的函數(shù)),并最終以逗號(hào)將這些響應(yīng)合并(減少)。 讓我們檢查一下它是如何完成的:
PersonProcessingServiceContainer.java
package com.blogspot.toomuchcoding.person.service;import java.util.ArrayList; import java.util.List;import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Component;import com.blogspot.toomuchcoding.person.domain.Person;@Component @Primary class PersonProcessingServiceContainer implements PersonProcessingService {private static final Logger LOGGER = LoggerFactory.getLogger(PersonProcessingServiceContainer.class);@Autowiredprivate List<PersonProcessingService> personProcessingServices = new ArrayList<PersonProcessingService>();@Overridepublic boolean isApplicableFor(Person person) {return person != null;}@Overridepublic String process(Person person) {List<String> output = new ArrayList<String>();for(PersonProcessingService personProcessingService : personProcessingServices){if(personProcessingService.isApplicableFor(person)){output.add(personProcessingService.process(person));}}String result = StringUtils.join(output, ",");LOGGER.info(result);return result;}public List<PersonProcessingService> getPersonProcessingServices() {return personProcessingServices;} }如您所見(jiàn),我們有一個(gè)用@Primary注釋的容器,這意味著如果必須注入PersonProcessingService的實(shí)現(xiàn),則Spring將選擇要注入的PersonProcessingServiceContainer。 很棒的事情是,我們有一個(gè)自動(dòng)連接的PersonProcessingServices列表,這意味著該接口的所有其他實(shí)現(xiàn)都將在那里自動(dòng)連接(容器不會(huì)自動(dòng)將其自身連接到該列表!)。
現(xiàn)在,讓我們檢查一下Spock測(cè)試 ,這些測(cè)試證明我沒(méi)有在說(shuō)謊。 如果您尚未在項(xiàng)目中使用Spock,則應(yīng)立即將其移動(dòng)。
PersonProcessingServiceContainerIntegrationSpec.groovy
package com.blogspot.toomuchcoding.person.service import com.blogspot.toomuchcoding.configuration.SpringConfiguration import com.blogspot.toomuchcoding.person.domain.Person import org.springframework.beans.factory.annotation.Autowired import org.springframework.test.context.ContextConfiguration import spock.lang.Specification import spock.lang.Unrollimport static org.hamcrest.CoreMatchers.notNullValue@ContextConfiguration(classes = [SpringConfiguration]) class PersonProcessingServiceContainerIntegrationSpec extends Specification {@AutowiredPersonProcessingService personProcessingServicedef "should autowire container even though there are many implementations of service"(){ expect: personProcessingService instanceof PersonProcessingServiceContainer}def "the autowired container should not have itself in the list of autowired services"(){ expect: personProcessingService instanceof PersonProcessingServiceContainerand:!(personProcessingService as PersonProcessingServiceContainer).personProcessingServices.findResult {it instanceof PersonProcessingServiceContainer}}def "should not be applicable for processing if a person doesn't exist"(){given:Person person = nullexpect:!personProcessingService.isApplicableFor(person)}def "should return an empty result for a person not applicable for anything"(){given:Person person = new Person("", 17, false)when:def result = personProcessingService.process(person)then:result notNullValue()result.isEmpty()}@Unroll("For name [#name], age [#age] and being stupid [#stupid] the result should contain keywords #keywords")def "should perform different processing depending on input"(){given:Person person = new Person(name, age, stupid)when:def result = personProcessingService.process(person) then:keywords.every {result.contains(it) }where:name | age | stupid || keywords"jan" | 20 | true || ['NAME', 'AGE', 'STUPID']"" | 20 | true || ['AGE', 'STUPID']"" | 20 | false || ['AGE']null | 17 | true || ['STUPID']"jan" | 17 | true || ['NAME']} }測(cè)試非常簡(jiǎn)單:
每個(gè)模塊的功能
想象一下您在核心模塊中定義了接口的實(shí)現(xiàn)的情況。
@Component class CoreModuleClass implements SomeInterface { ... }如果您在與核心模塊有依賴(lài)性的其他模塊中決定不想使用此CoreModuleClass并希望在SomeInterface自動(dòng)連線(xiàn)的任何地方都具有一些自定義邏輯該怎么辦? 好吧–使用@Primary!
@Component @Primary class CountryModuleClass implements SomeInterface { ... }通過(guò)這種方式,您可以確保必須自動(dòng)裝配SomeInterface的位置將是您的CountryModuleClass,將其插入到該字段中。
結(jié)論
在這篇文章中,您可以看到如何
- 使用@Primary批注創(chuàng)建類(lèi)似接口實(shí)現(xiàn)的復(fù)合容器
- 使用@Primary批注提供接口的每個(gè)模塊實(shí)現(xiàn),在自動(dòng)裝配方面,該實(shí)現(xiàn)將優(yōu)先于其他@Components
- 編寫(xiě)出色的Spock測(cè)試:)
編碼
您可以在Too Much Coding的Github存儲(chǔ)庫(kù)或Too Much Coding的Bitbucket存儲(chǔ)庫(kù)中找到此處提供的代碼。
翻譯自: https://www.javacodegeeks.com/2013/12/springs-primary-annotation-in-action.html
總結(jié)
以上是生活随笔為你收集整理的Spring的@Primary注释在起作用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 安卓 微信(微信安卓协议)
- 下一篇: linux开发常用命令(linux开发