java 编程解决Bean注入

zdwk9cvp  于 2023-05-12  发布在  Java
关注(0)|答案(2)|浏览(167)

我想找到一种方法,在Spring容器级别上,以编程方式在bean工厂上的不同实现之间选择候选人。
有了Profiles,我就可以像这样简单地实现它
我有以下配置文件“CH”和“IT”,我希望如果一个Bean配置了IT,那么将回退到默认值。
给定这些类:
默认实现

@Component
public class DefaultMapper {
     public void doSomething() {
        System.out.println("Map Default");
    }
}

瑞士实施

@Component
@Profile("CH")
public class SwissMapper extends DefaultMapper {

    @Override

    public void doSomething() {

        System.out.println("do something swiss");

    }

}

意大利实施:

@Component
@Profile("IT")
public class ItalianMapper extends DefaultMapper {
@Override
    public void doSomething() {
        System.out.println("do pasta");
    }
}

现在,如果我用@ActiveProfiles("IT")运行它,它会抛出一个NoUniqueBeanDefinitionException,这是很公平的,因为Default没有被分析,它将被注册,而不会被容器进一步关注。
一些考虑:
如果我将@Profile("default")添加到DefaultMapper,这将工作,直到我有另一个默认bean具有仅用CH分析的子类。
另一个Bean的默认实现:

@Component
@Profile("default")
public class DefaultParser {
    public void doSomething() {
        System.out.println("Parse Default");
    }
}

然后是Swiss实现(没有可用的意大利语,或者更好地说,默认值适合意大利语):

@Component
@Profile("CH")
public class SwissParser extends DefaultParser {
    @Override
    public void doSomething() {
        System.out.println("Ässe Ässe");
    }
}

现在,如果我用@ActiveProfiles("IT")运行它,它会抛出一个No BeanDefinitionException,这是公平的,但不是那么公平,因为“默认”没有链接为ActiveProfiles,对于IT来说,我没有实现。这里CH配置文件将起作用,因为每个默认类都有一个配置文件实现。
说我想用一种更好的方式来涵盖这种情况,而不需要:

  • 必须在默认类上定义@Profile({"default","IT", "<all other profiles which have NOT a specialized implementation"}@Profile("!CH"),其中我排除了那些具有专门化的配置文件。
  • 我认为@Primary不是一个解决方案,因为在DefaultMapper上,我必须进行专业化认证,这将被标记为@Primary,而容器根本不喜欢它

然后我想解决这个问题,我可以决定所有注入的类,当Bean的分辨率不明确时,我想以编程方式决定(在容器中)我想选择哪个实现。我认为注解类似于@Profile,即@Candidate(“CH”)与www.example.com中设置的值相比将适合application.properties即国籍.cantidate= CH。类似于:

public class MyExtension extends UnknowSpringType {
    @Override
    Object resolveAmbigousDependency(final Context ctx, final Resolution resolution) {
        final List<Class> clazzes = resolution.getResolvedClasses();
        for (final Class clazz : clazzes) {
            if (clazz.isAnnotationPresent(Candidate.class) && clazz.getAnnotation(Candidate.class).getVaue().equals(candidateApplicationPropertyValue)) {
            return clazz;
        }
        return getDefaultImplementation(clazzes);
    }
}

我过去用CDI SPI扩展做过类似的事情,这很优雅,我也可以用CDI的@Specializes以另一种方式覆盖这一点,但我在Spring上找不到同样简单的方法(我没有太多的经验),BeanFactory?BeanFactoryPostProcessor?
帮忙?

n6lpvg4x

n6lpvg4x1#

您可以将所有特定的解析器标记为@Primary,这将确保Spring自动连接此解析器,而不是未标记为@Primary的默认解析器。当所选配置文件不存在特定的解析器时,它将返回到非@Primary默认组件。
参见:https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/Primary.html

@Component
public class DefaultParser {
    public void doSomething() {
        System.out.println("Parse Default");
    }
}
@Component
@Primary
@Profile("CH")
public class SwissParser extends DefaultParser {
@Override
public void doSomething() {
    System.out.println("Ässe Ässe");
}
piztneat

piztneat2#

您可以激活多个配置文件,CH和IT,您的实施将失败。
这是一个国际化问题。

相关问题