翻代码的时候,发现一段@Autowired
注解写在Map上,遂点过去又翻了下@Autowired
注解的源码,有如下这么一段说明
<h3>Autowiring Arrays, Collections, and Maps</h3> <p>In case of an array, {@link java.util.Collection}, or {@link java.util.Map} dependency type, the container autowires all beans matching the declared value type. For such purposes, the map keys must be declared as type {@code String} which will be resolved to the corresponding bean names. Such a container-provided collection will be ordered, taking into account {@link org.springframework.core.Ordered Ordered} and {@link org.springframework.core.annotation.Order @Order} values of the target components, otherwise following their registration order in the container. Alternatively, a single matching target bean may also be a generally typed {@code Collection} or {@code Map} itself, getting injected as such.
简单翻一下,大意是 @Autowired
注解可以用来注入 Array、Collection和 Map这三种类型的变量,选择类型对应的type来注入的。
其中Map的key必须被定义为String类型,Map的key会被用来保存Bean的name。
Collection类型的在注入的时候会根据@Order注解来对内容进行排序,如果没有@Order注解,则会根据注册顺序决定。
即使只有一个匹配的类型的bean,也可以这么操作。
根据上面说明的内容,简单写一段代码尝试下,代码如下
定义接口
package com.cheungq.demo.service.autowiredTest.simpleServices;
/**
* SimpleInterface<br>
* @author CheungQ
*/
public interface SimpleInterface {
/**
* 实现类自行做点什么
*/
void doSomeThing();
}
写3个实现类
package com.cheungq.demo.service.autowiredTest.simpleServices;
import org.springframework.stereotype.Component;
/**
* FirstSimpleServiceImpl<br>
* @author CheungQ
*/
@Component
public class FirstSimpleServiceImpl implements SimpleInterface{
@Override
public void doSomeThing() {
System.out.println("This is the FIRST implement class");
}
}
package com.cheungq.demo.service.autowiredTest.simpleServices;
import org.springframework.stereotype.Component;
/**
* SecondSimpleServiceImpl<br>
* @author CheungQ
*/
@Component
public class SecondSimpleServiceImpl implements SimpleInterface{
@Override
public void doSomeThing() {
System.out.println("This is the SECOND implement class");
}
}
package com.cheungq.demo.service.autowiredTest.simpleServices;
import org.springframework.stereotype.Component;
/**
* ThirdSimpleServiceImpl<br>
* @author CheungQ
*/
@Component
public class ThirdSimpleServiceImpl implements SimpleInterface{
@Override
public void doSomeThing() {
System.out.println("This is the THIRD implement class");
}
}
写一个Service类,并用@Autowired分别修饰Array、Collection和Map类型
package com.cheungq.demo.service.autowiredTest; import com.cheungq.demo.service.autowiredTest.simpleServices.SimpleInterface; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.Arrays; import java.util.List; import java.util.Map; /** * AutowiredTestService<br> * @author CheungQ */ @Service public class AutowiredTestService { @Autowired private List<SimpleInterface> simpleServiceList; @Autowired private SimpleInterface[] simpleServiceArray; @Autowired private Map<String,SimpleInterface> simpleServiceMap; public SimpleInterface getByName(String name){ System.out.println(Arrays.toString(simpleServiceArray)); System.out.println(simpleServiceList); System.out.println(simpleServiceMap); return simpleServiceMap.getOrDefault(name,null); } }
最后写个Controller调用下看下
package com.cheungq.demo.controller; import com.cheungq.demo.service.autowiredTest.AutowiredTestService; import com.cheungq.demo.service.autowiredTest.simpleServices.SimpleInterface; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.validation.constraints.NotEmpty; /** * SimpleController<br> * @author CheungQ */ @RestController @RequestMapping(value = "simple/") public class SimpleController { @Autowired private AutowiredTestService autowiredTestService; @RequestMapping(value = "test") public void test(@RequestParam @NotEmpty String name) { SimpleInterface service = autowiredTestService.getByName(name); if (null != service){ service.doSomeThing(); } } }
执行代码,并在Service中打个断点,我们看下情况,如下图
可以看到,Spring对Array、Collection和Map类型进行了注入,下一步修改代码,给ThirdSimpleServiceImpl实现类添加@Order注解
package com.cheungq.demo.service.autowiredTest.simpleServices;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* ThirdSimpleServiceImpl<br>
* @author CheungQ
*/
@Component
@Order(1)
public class ThirdSimpleServiceImpl implements SimpleInterface{
@Override
public void doSomeThing() {
System.out.println("This is the THIRD implement class");
}
}
重启应用,并测试下
Array和Collection类型中的顺序都发生了改变,ThirdSimpleServiceImpl实现类正确的排到了第一位。
简单说下之前做业务开发的时候曾经的一些应用场景。
一个是在批量拉取订单数据系统中,有一个拉取任务配置模块,可以配置任务执行时间片划分参数、分页数、执行线程数、执行的BeanName。
在主要的业务流程中,根据执行的BeanName获取需要执行的bean实例、这些bean实例都要按照约定实现之前约定的接口。接口约定了两个主要的方法,一个是根据给定的参数获取总数据条数,另一个是根据给定的参数按页码拉取同步远端的订单数据。
那么再开发过程中,开发人员需要做的是根据业务需求,实现这个接口,而整个拉取的任务调度则由系统配置,根据指定的bean实例执行。
另一个曾经使用过的场景,在平台活动商户报名系统中。这个系统做得比较灵活点,根据我在这个系统上的开发和使用感受来看,这个系统最初的设计构想可能是想打造成一个低代码平台的模式。为什么会这么说呢?从已经实现的基础框架上来看,各个模块都做成了灵活配置的形式。活动类型可配置,创建活动的时候需要填写的字段可配置,商户报名填写字段可配置,可报名商户资质和商户类型可配置,报名商户、商品相关校验逻辑可配置,报名数据下发下游系统相关逻辑也是可配置的。一整个流程几乎都可以通过配置信息来调整,唯一的问题是,统统都是JSON对象配置,以及部分可在线编辑的代码配置,在可视化方面做的很少,这也导致这一整个的配置工作还是只能是开发人员来操作。稍微有点偏题了。
在这个系统中有一个模块是专门做报名信息校验的,通过配置对应的校验的BeanName,以及对应validate实例的执行顺序、相关校验参数(如字段最大最小值、字符串校验正则等等)这些。这样在执行的时候获取对应bean实例也是这么处理的。
发表评论