1.重构的时候遇到Spring按Type装载匹配的Bean的异常,当有两个具象类且是父子关系时(如下图, 父类SPParser4ItemAOImpl和子类SPParser4BrandAOImpl), 通过Spring容器ApplicationContext.getBean按type装载匹配父类时,会匹配到两个实例(自己SPParser4ItemAOImpl和子类SPParser4BrandAOImpl), 装载子类时,只会找到子类实例本身(SPParser4BrandAOImpl). 有兴趣可看下DefaultListableBeanFactory.doGetBeanNamesForType方法, 用了xxx.class.isInstance(beanInstance)去判断.

Spring自动装配匹配类名问题_ide

@Component
public class SPParser4BrandAOImpl extends SPParser4ItemAOImpl {

    @Override
    public void parseDataList() {
        System.out.println("This is in SPParser4BrandAOImpl");
    }
}

@Component
public class SPParser4ItemAOImpl extends SuperSPPageFloorParseAO {

    @Override
    public void parseDataList() {
        System.out.println("This is in SPParser4ItemAOImpl");
    }
}

public abstract class SuperSPPageFloorParseAO implements SPPageFloorParserAO {

    @Override
    public Map<String, String> parseAttrMap() {
        return new HashMap<>();
    }
}

public interface SPPageFloorParserAO {

    void parseDataList();

    /**
     * 获取 SPPageFloorVO attrMap数据
     * @return
     */
    Map<String, String> parseAttrMap();
}

@Component
public class SPParser4BannerAOImpl extends SuperSPPageFloorParseAO {

    public void parseDataList() {
        //是banner的话就进行url组装
        System.out.println("This is in SPParser4BannerAOImpl");
    }
}




[b][color=darkred]注意,调用的地方是找各自具象类[/color][/b]


SPParser4ItemAOImpl sPParser4ItemAOImpl = (SPParser4ItemAOImpl) context.getBean(SPParser4ItemAOImpl.class);
SPParser4BrandAOImpl sPParser4BrandAOImpl = (SPParser4BrandAOImpl) context.getBean(SPParser4BrandAOImpl.class);




2.Spring自动装配匹配类跟使用的地方是有关联的,如果使用的地方按接口类型或父类去查找, 会匹配到所有实现了接口类型和父类的具象类(SPParser4BannerAOImpl,SPParser4BrandAOImpl,SPParser4ItemAOImpl),程序会报错.


@Component
public class TestApp {
    @Autowired
    private SPPageFloorParserAO sPPageFloorParserAO;

    public void test(){
        sPPageFloorParserAO.parseDataList();
    }
}



@Autowired
    private SuperSPPageFloorParseAO superSPPageFloorParseAO;

    public void testSuperClass(){
        superSPPageFloorParseAO.parseDataList();
    }



解决TestApp的依赖注入时,还是用xxx.class.isInstance(beanInstance)去判断.



3. 在使用Spring注解如 @Component 注册为组件时,如果没有指定名字 @Component("指定的名字"), 而是默认的话,如果class名称为 ABxxx 时会直接返回,而不会将 A 转为小写,因为Spring的判断是:如果第二位是大写,则直接返回.有兴趣可看类AnnotationBeanNameGenerator的generateBeanName和buildDefaultBeanName方法.

Spring自动装配匹配类名问题_java_02



4. Qualifier如果在父子具象类中使用,如果Qualifier仅标在父具象类中,通过@Autowired和@Qualifier找父类也会找到两个,还需要把@Qualifier标注在子类上,这样Autowired父类只会找到一个.


@Component
//@Primary
@Qualifier("cold")
public class SPParser4ItemAOImpl extends SuperSPPageFloorParseAO {

    @Override
    public void parseDataList() {
        System.out.println("This is in SPParser4ItemAOImpl");
    }
}



@Component
//@Qualifier("需要增加一个新标识跟父类标识区分")
public class SPParser4BrandAOImpl extends SPParser4ItemAOImpl {

    @Override
    public void parseDataList() {
        System.out.println("This is in SPParser4BrandAOImpl");
    }
}



@Component
public class TestApp {

    @Autowired
    //@Qualifier("SPParser4ItemAOImpl")
    @Qualifier("cold")
    private SPPageFloorParserAO sPPageFloorParserAO;

    public void test(){
        sPPageFloorParserAO.parseDataList();
    }
}



@Test
    public void testGetBeanByClazz() {
        TestApp testApp = context.getBean(TestApp.class);
        testApp.test();
    }