• Spring in action读书笔记(四) Spring 处理自动装配的歧义性


    1、 有歧义的bean

            自动装配中仅有一个bean匹配所需要的结果时,自动装配才是有效的。如果有多个bean能够匹配结果的话,

    这种奇异性会阻碍Spring自动装配属性,构造器参数或方法参数。

            假设定义了一个接口。

    package test;
    
    public interface Interface {
    }

    有两个实现类:

    package test;
    
    import org.springframework.stereotype.Component;
    
    @Component
    public class Impl1 implements Interface {
    }
    package test;
    
    import org.springframework.stereotype.Component;
    
    @Component
    public class Impl2 implements Interface {
    }

    创建配置类InterfaceConfig

    package test;
    
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    @ComponentScan(basePackageClasses = Interface.class)
    public class InterfaceConfig {
    
    
    }

    这个时候如果注入Interface属性,程序将报错。

    package test;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = {InterfaceConfig.class})
    public class TestAutowired {
    
        @Autowired
        private Interface imp;
    
        @Test
        public void test() {
            System.out.println(imp);
        }
    
    }

    错误信息:

    org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'test.TestAutowired': Unsatisfied dependency expressed through field 'imp'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'test.Interface' available: expected single matching bean but found 2: impl1,impl2

    大致是说产生了歧义性,无法确定装配哪一个bean

    2、 使用@Primary注解,标记首选的bean

    package test;
    
    import org.springframework.context.annotation.Primary;
    import org.springframework.stereotype.Component;
    
    @Component
    @Primary
    public class Impl1 implements Interface {
    }

     缺点: 如果标记了两个或更多的首选bean,仍然会产生歧义性。

    3、在需要注入参数的地方,使用限定符@Qualifier注解,指定装配bean 的ID

    package test;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = {InterfaceConfig.class})
    public class TestAutowired {
    
        @Autowired
        @Qualifier("impl2")
        private Interface imp;
    
        @Test
        public void test() {
            System.out.println(imp);
        }
    
    }

    缺点: 有类型强耦合,对类名的改动会导致限定符失效

    4、在bean上使用@Qualifier设定限定符,在注入的地方使用相同的限定符。

    package test;
    
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.context.annotation.Primary;
    import org.springframework.stereotype.Component;
    
    @Component
    @Qualifier("1")
    public class Impl1 implements Interface {
    }

    注入:

    package test;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = {InterfaceConfig.class})
    public class TestAutowired {
    
        @Autowired
        @Qualifier("1")
        private Interface imp;
    
        @Test
        public void test() {
            System.out.println(imp);
        }
    
    }

     不足: 如果多个bean都具备相同特性,会再次遇到歧义性的问题。

    例如:对Impl2增加同样的注解,这时会产生和步骤1中同样的问题;

    package test;
    
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.stereotype.Component;
    
    @Component
    @Qualifier("1")
    public class Impl2 implements Interface {
    }

    由于@Qualifier注解不可重复, 这时没有直接的方法将自动装配的bean缩小范围到仅有一个可选的bean

    5、自定义限定符注解

    package test;
    
    import org.springframework.beans.factory.annotation.Qualifier;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Qualifier
    public @interface Interface1 {
    }

    在bean类及需要注入的地方添加该注解:

    package test;
    
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.context.annotation.Primary;
    import org.springframework.stereotype.Component;
    
    @Component
    @Interface1
    public class Impl1 implements Interface {
    }
    package test;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = {InterfaceConfig.class})
    public class TestAutowired {
    
        @Autowired
        @Interface1
        private Interface imp;
    
        @Test
        public void test() {
            System.out.println(imp);
        }
    
    }

    可以通过多个自定义注解,缩减满足bean装配的范围。

  • 相关阅读:
    idea spring boot 1.x junit单元测试
    linux oracle/jdk启用大页面
    jdk8之CompletableFuture与CompletionService
    gc日志深入解析-覆盖CMS、并行GC、G1、ZGC、openj9
    h2 web console使用
    LockSupport工具类详解
    反射、Unsafe、直接调用性能大比拼
    spring boot druid动态多数据源监控集成
    Linux网络
    org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection总结
  • 原文地址:https://www.cnblogs.com/wushengwuxi/p/11933046.html
Copyright © 2020-2023  润新知