@Autowired二三事

40 阅读2分钟

概要

关于 @Autowired, 实际上有一些内容可以聊一下。

首先是比较重要的一点, @Autowired一般来讲是用于单个bean的注入 不过他其实可以用于Array (数组),Collections(集合),甚至是 Map (散列表)的注入。

@Autowired
List<IService> serviceBeans;

@Autowired
Set<IService> serviceBeans;

@Autowired
Map<String,IService> serviceBeanMap;

第二点则是涉及相关的一个bug的查找,注入的bean是空的某种情形。

注入方式在设计中的用处

其中Map的key只能是String类型,用于放置对应bean的名字。

这些集合、数组或者map用法其实在做设计的时候很有用处。

比如我有一个服务,用于对订单的某个类型,进行不同的处理,这时,具体实现代码可以是:

//某个实现类
@Service
public class TypeAService implements IService {

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void execute(Order order) {
        //do something
    }

    @Override
    public boolean support(SomeTypeEnum type) {
        return SomeTypeEnum .typeA.equals(type);
    }

}
//另一个实现类
@Service
public class TypeBService implements IService {

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void execute(Order order) {
        //do something
    }

    @Override
    public boolean support(SomeTypeEnum type) {
        return SomeTypeEnum .typeB.equals(type);
    }

}

我们的主体代码则可以保持不变,在新增加类型时,进行增加对应的处理类即可。对了,依旧是之前的理念,对代码尽可能少的改动以实现功能的扩展。

主体代码:


@Autowired
private List<IService> services;

public void doAction(Order order){
    for (IService service: services) {
        if (service.support(order.getType())) {
             recordActionService.execute(order);
        }    
    }
}

注入bean为空的某种情形

在用到cola框架(一种领域模型的依赖框架)的时候,对多模块的处理,会出现这样一种场景,在A模块中定义了接口,但是未实现,之后再在B模块中进行实现,并注册为bean。(有点类似JNDI)

这个时候spring 实际上是会有2个bean在容器中,假设接口为IService,实现为ServiceA,如果用

@Autowired
IService service;

或者ApplicationContextAware组件的applicationContext获取service=applicationContext.getBean(IService .class),

之后调用IService 任何方法都会报错,原因就是注入了IService的空接口,而不是ServiceA这个具体实现类。解决的办法就是在实现ServiceA中加入@Primary的注解。

结尾

最后,spring不太推荐属性注入,所以在属性注入中会报warning,强迫症可以替换为set方法注入,或者构造器注入。

具体原因网上有很多,这里也就不再多赘述了。