实现 MapAutowired

实现 MapAutowired

场景

有些时候,在spring注入map的时候,我们不仅仅满足于默认 key 值 为bean的名称,也有可能根据bean中的某个属性值进行注入。这样不得不在容器启动后进行再次处理

目的

实现 根据bean属性注入 map 的 MapAutowired

定义注解

@Target({ ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MapAutowired {

    /**
     * 属性字段
     * @return
     */
    String value() default "";
}

实现后置处理器

@Component
@Slf4j
public class MapAutowiredPostProcessor implements InstantiationAwareBeanPostProcessor {

    @Autowired
    private ApplicationContext applicationContext;

    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {

        Field[] declaredFields = bean.getClass().getDeclaredFields();
        if (declaredFields == null || declaredFields.length<1) {
            return InstantiationAwareBeanPostProcessor.super.postProcessProperties(pvs, bean, beanName);
        }
        for (Field field : declaredFields) {
            MapAutowired annotation = field.getAnnotation(MapAutowired.class);
            if (annotation != null) {
                if (Map.class.isAssignableFrom(field.getType())){
                    Type type = field.getGenericType();
                    if (type instanceof ParameterizedType){
                        ParameterizedType parameterizedType = (ParameterizedType)type;
                        Type[] actualTypes = parameterizedType.getActualTypeArguments();
                        Class<?> valueType = (Class<?>) actualTypes[1];
                        Map<String, ?> beans = applicationContext.getBeansOfType(valueType);
                        if (!CollectionUtils.isEmpty(beans)){
                            field.setAccessible(true);
                            Object result = null;
                            if (StringUtils.hasText(annotation.value())){
                                //如果没有指定key,则注入key为bean名称
                                //指定key
                                Map m = new ConcurrentHashMap();
                                for (Object value : beans.values()) {
                                    Method method = ReflectionUtils.findMethod(valueType, annotation.value());
                                    if (method == null) {
                                        throw new RuntimeException("Method not found: " + annotation.value());
                                    }
                                    Object key = ReflectionUtils.invokeMethod(method, value);
                                    m.put(key, value);
                                }
                                result = m;
                            }else {
                                // 如果没有指定key,则注入key为bean名称
                                result = beans;
                            }
                            try {
                                field.set(bean,result);
                            } catch (IllegalAccessException e) {
                                throw new RuntimeException("Failed to set field value", e);
                            }
                        }
                    }else{
                        throw new IllegalStateException("Expected a ParameterizedType for the field");
                    }
                }else {
                    log.error("@MapAutowired can not inject a non Map class, so ignore bean name: {} ", beanName);
                }
            }
        }
        return InstantiationAwareBeanPostProcessor.super.postProcessProperties(pvs, bean, beanName);
    }
}

测试

public interface Pay {

    Integer getPayType();

    void pay();
}

@Component
@Slf4j
public class AliPay implements Pay{
    @Override
    public Integer getPayType() {
        return 1;
    }

    @Override
    public void pay() {
        log.info("alipay...");
    }
}

@Component
@Slf4j
public class WechatPay implements Pay{
    @Override
    public Integer getPayType() {
        return 2;
    }

    @Override
    public void pay() {
        log.info("wechat pay...");
    }
}

@Component
@Slf4j
public class ContextPublisher {


    /**
     * 指定 key 值方法
     */
    @MapAutowired(value = "getPayType")
    private Map<Integer, Pay> payMap;

    @PostConstruct
    public void pay(){
        System.out.println("pay bean: "+ payMap);
        for (Map.Entry<Integer, Pay> entry : payMap.entrySet()) {
            log.info("key: {}", entry.getKey());
            entry.getValue().pay();
        }
    }

}

结果:

c.e.b.publisher.ContextPublisher         : key: 1
com.example.bootnacos.map.pay.AliPay     : alipay...
c.e.b.publisher.ContextPublisher         : key: 2
com.example.bootnacos.map.pay.WechatPay  : wechat pay...
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值