Spring注解的(List&Map)特殊注入功能


一、先看一個示例演示:spring注解的一個特殊的注入功能。

首先,是定義一個接口,3個實現類。

public interface GreetService {

    public String sayHello(String name);
    
}
@Service("china")
public class ChinaGreetServiceImpl implements GreetService {

    @Override
    public String sayHello(String name) {
        return "你好";
    }

}
@Service("japan")
public class JapanGreetServiceImpl implements GreetService {

    @Override
    public String sayHello(String name) {
        return "亞麻得";
    }

}
@Service("usa")
public class UsaGreetServiceImpl2 implements GreetService {

    @Override
    public String sayHello(String name) {
        return "hello";
    }

}

下面看到代碼中有直接注入一個List和一個Map的。示例代碼如下:

GreetController代碼:

@RestController
@RequestMapping("/greet")
public class GreetController {

    @Autowired
    private List<GreetService> greetServiceList;

    @Autowired
    private Map<String, GreetService> greetServiceMap;

    @RequestMapping(value = "/test/{id}", method = RequestMethod.GET)
    public String getbook5(@ApiParam("id編號") @PathVariable("id") Long id) {
        for (Map.Entry<String, GreetService> entry : greetServiceMap.entrySet()) {
            System.out.println(entry.getValue().sayHello("" + id));
        }
        System.out.println("==list====");
        for (GreetService greetService : greetServiceList) {
            System.out.println(greetService.sayHello("" + id));
        }

        return "" + id;
    }

}

最后在調試List的時候突然靈感一閃,如果只有一個對象那么List里面的值不就只有一個嗎。於是開始測試驗證,結果發現的確如此。當實例化一個GreetController之后,另外一個類采用泛型注入List,Spring竟然成功的將實例化的對象放入List之中。思路打開之后,針對Map的就更好說了。Spring會將service的名字作為key,對象作為value封裝進入Map。

運行之后,訪問http://127.0.0.1:8091/greet/test/1執行結果如下:

原來,在不知不覺中Spring已經幫我們做了很多事情,只是我們不知道而已。

 二、@Autowired 注入集合類型

從spring-beans-4.3.14.RELEASE.jar的源碼可以看看到如下:

在org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DependencyDescriptor, String, Set<String>, TypeConverter) 方法中發現了原因。

對於@Autowired聲明的數組、集合類型,spring並不是根據beanName去找容器中對應的bean,而是把容器中所有類型與集合(數組)中元素類型相同的bean構造出一個對應集合,注入到目標bean中。對應到上問配置文件中,就是把容器中所有類型為java.lang.String的bean放到新建的Set中,然后注入到Manager bean中。也就是把resourcePackage和resourceLoaction這兩個String注入了,導致上面的輸出結果。

在spring reference中也發現相關說明。

@Autowired

If you intend to express annotation-driven injection by name, do not primarily use @Autowired, even if is technically capable of referring to a bean name through @Qualifier values. Instead, use the JSR-250 @Resource annotation, which is semantically defined to identify a specific target component by its unique name, with the declared type being irrelevant for the matching process.
As a specific consequence of this semantic difference, beans that are themselves defined as a collection or map type cannot be injected through @Autowired, because type matching is not properly applicable to them. Use @Resource for such beans, referring to the specific collection or map bean by unique name.
@Autowired applies to fields, constructors, and multi-argument methods, allowing for narrowing through qualifier annotations at the parameter level. By contrast, @Resource is supported only for fields and bean property setter methods with a single argument. As a consequence, stick with qualifiers if your injection target is a constructor or a multi-argument method.

從上面的說明中找到解決辦法就是注入集合類型不要使用@Autowired,而使用@Resource注解。同時Spring官方也是不推薦使用@Autowired的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM