网站加首页,网站和服务器的关系,网站备案密码能改吗,卖域名做非法网站Spring是一个永不止息的框架。 这是因为它提供了许多不同的解决方案#xff0c;使我们#xff08;开发人员#xff09;无需编写数百万行代码即可完成我们的任务。 取而代之的是#xff0c;我们能够以更具可读性#xff0c;更标准化的方式进行操作。 在这篇文章中#xff… Spring是一个永不止息的框架。 这是因为它提供了许多不同的解决方案使我们开发人员无需编写数百万行代码即可完成我们的任务。 取而代之的是我们能够以更具可读性更标准化的方式进行操作。 在这篇文章中我将尝试描述最有可能为大家所熟知的功能之一但我认为其重要性被低估了。 我将要讨论的功能是Primary批注。 问题 在我从事的几个项目中我们遇到了一个常见的业务问题–我们有一个进入更复杂逻辑的入口–一些容器该容器会将其他几个处理器的结果收集到一个输出中例如map-filter-reduce函数编程中的函数。 在某种程度上它类似于Composite模式。 综上所述我们的方法如下 我们有一个容器其中包含自动实现共同接口的处理器列表 我们的容器实现了与自动装配列表元素相同的接口 我们希望使用该容器的客户端类使整个处理工作透明化-他只对结果感兴趣 处理器具有一些逻辑谓词处理器可将其应用于当前输入数据集 然后将处理结果合并到一个列表中然后缩减为单个输出 有很多方法可以解决此问题-我将介绍一种使用Spring和Primary批注的方法。 解决方案 让我们从定义用例如何适应上述前提开始。 我们的数据集是一个Person类如下所示 人.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;}
} 没有什么不寻常的。 现在让我们定义合同 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的每个实现都必须定义合同的两点 是否适用于当前人员 它如何处理一个人。 现在让我们看一下我们拥有的一些处理器-由于它毫无意义所以我不会在此处发布代码-您可以稍后在Github或Bitbucket上查看代码。 我们有以下Component注释的PersonProcessingService实现 AgePersonProcessingService 如果某人的年龄大于或等于18则适用 IntelligencePersonProcessingService 适用于某人是愚蠢的人 NamePersonProcessingService 如果某人有名字则适用 逻辑很简单。 现在我们的PersonProcessingServices容器将要针对处理器上的给定Person进行迭代检查当前处理器是否适用过滤器如果是这种情况则将响应处理Person的结果字符串添加到响应列表中映射-将Person转换为String的函数并最终以逗号将这些响应合并减少。 让我们检查一下它是如何完成的 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 ListPersonProcessingService personProcessingServices new ArrayListPersonProcessingService();Overridepublic boolean isApplicableFor(Person person) {return person ! null;}Overridepublic String process(Person person) {ListString output new ArrayListString();for(PersonProcessingService personProcessingService : personProcessingServices){if(personProcessingService.isApplicableFor(person)){output.add(personProcessingService.process(person));}}String result StringUtils.join(output, ,);LOGGER.info(result);return result;}public ListPersonProcessingService getPersonProcessingServices() {return personProcessingServices;}
} 如您所见我们有一个用Primary注释的容器这意味着如果必须注入PersonProcessingService的实现则Spring将选择要注入的PersonProcessingServiceContainer。 很棒的事情是我们有一个自动连接的PersonProcessingServices列表这意味着该接口的所有其他实现都将在那里自动连接容器不会自动将其自身连接到该列表。 现在让我们检查一下Spock测试 这些测试证明我没有在说谎。 如果您尚未在项目中使用Spock则应立即将其移动。 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.notNullValueContextConfiguration(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 doesnt 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 || keywordsjan | 20 | true || [NAME, AGE, STUPID] | 20 | true || [AGE, STUPID] | 20 | false || [AGE]null | 17 | true || [STUPID]jan | 17 | true || [NAME]}
} 测试非常简单 我们证明自动装配字段实际上是我们的容器– PersonProcessingServiceContainer。 然后我们证明在PersonProcessingService的自动装配实现的集合中找不到对象该对象属于PersonProcessingServiceContainer类型 在接下来的两个测试中我们证明处理器背后的逻辑正在运行 最后但并非最不重要的一点是Spock最出色的– where子句它使我们能够创建漂亮的参数化测试。 每个模块的功能 想象一下您在核心模块中定义了接口的实现的情况。 Component
class CoreModuleClass implements SomeInterface {
...
} 如果您在与核心模块有依赖性的其他模块中决定不想使用此CoreModuleClass并希望在SomeInterface自动连线的任何地方都具有一些自定义逻辑该怎么办 好吧–使用Primary Component
Primary
class CountryModuleClass implements SomeInterface {
...
} 通过这种方式您可以确保必须自动装配SomeInterface的位置将是您的CountryModuleClass将其插入到该字段中。 结论 在这篇文章中您可以看到如何 使用Primary批注创建类似接口实现的复合容器 使用Primary批注提供接口的每个模块实现在自动装配方面该实现将优先于其他Components 编写出色的Spock测试:) 编码 您可以在Too Much Coding的Github存储库或Too Much Coding的Bitbucket存储库中找到此处提供的代码。 参考来自我们的JCG合作伙伴 Marcin Grzejszczak位于Blog上的 Spring Primary注释 适用于编码成瘾者博客。 翻译自: https://www.javacodegeeks.com/2013/12/springs-primary-annotation-in-action.html