ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

@Autowired注入null空指针和解决

2021-11-21 17:02:12  阅读:137  来源: 互联网

标签:Autowired beanFactory private class bean ErrorOrderResultEnum null public 指针


一、问题背景

在自定义的component中,通常需要注入一些其他的bean来完成业务操作,比如需要注入service,但可能会出现@Autowired注入失败的情况。

业务背景

客户下了一个送货的订单,经过平台的派单系统 之后,司机接收到了订单,开始进行送货。但是在送货的过程中,可能会出现一些意外情况无法完成订单,因此司机需要对该订单上报异常,上报异常之后,平台根据上报的异常做出不同的处理。

POJO

这个实体类是平台受理异常订单时,做出的受理方式的请求参数,后台会根据,后台会根据不同的处理方式做出不同的操作。

@Data
public class ErrorOrderInfo implements Serializable {
    private static final long serialVersionUID = 2614758007534512965L;
    /** 记录异常订单信息的记录号 */
    private String recordNo;
    /** 上报异常的订单号 */
    private String orderNo;
    /** 异常类型 */
    private String type;
    /** 平台受理方式 */
    private String result;
}
ErrorOrderResultEnum

异常订单的处理方式枚举类

@Getter
@SuppressWarnings("all")
public enum  ErrorOrderResultEnum {
    CANCEL_ORDER("1","取消订单"),
    CHANGE_DRIVER("2","更换司机");
    // 更多类型。。。
    private final String result;
    private final String desc;
    private  ErrorOrderResultEnum(String result, String desc) {
        this.result = result;
        this.desc = desc;
    }
}
service
@Service
@Transactional(rollbackFor = Exception.class)
public class OrderErrorServiceImpl implements OrderErrorService{
    /**
     * 异常订单处理
     */
    @Override
    public void handleErrorOrder(ErrorOrderInfo info) {
        // 省略一些业务逻辑处理。。。
        
        // 开始处理平台对上报异常之后不同处理方式的功能实现
        if (ErrorOrderResultEnum.CANCEL_ORDER.getResult().equals(info.getResult())) {
            // 平台对异常订单做出"取消订单"操作
        } else if (ErrorOrderResultEnum.CHANGE_DRIVER.getResult().equals(info.getResult())) {
            // 平台对异常订单做出"更换司机"操作
        }
        // 更多处理方式
    }
}
代码实现方式改造

后来采用了策略模式改造代码,具体如下
1.1 增加一个处理异常订单的抽象处理器

public abstract class ErrorOrderHandler {
    /**
     * 根据不同的处理结果做出不同的处理
     * @param info 平台处理结果信息
     */
    public abstract Object errorOrderHandler(ErrorOrderInfo info);
}

1.2 每种处理方式使用单独的bean来处理
@ErrorOrderResultType标记这个bean用来处理那个操作类型的

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface ErrorOrderResultType {
    ErrorOrderResultEnum value();
}

CancelOrderHandler取消订单的handler

/**
 * 处理取消订单的handler
 */
@Component
@ErrorOrderResultType(ErrorOrderResultEnum.CANCEL_ORDER) // 标记为取消订单的处理器
public class CancelOrderHandler extends ErrorOrderHandler{
    /**  注入订单service */
    @Autowired
    private OrderService orderService;
    
    /** 继承抽象处理器 ErrorOrderHandler 实现具体的操作逻辑*/
    @Override
    public Object errorOrderHandler(ErrorOrderInfo info) {
        // 省去一些业务逻辑
        
        // cancelOrder方法是取消订单的具体实现
        return orderService.cancelOrder(info);
    }
}

ChangeDriverHandler更换司机的handler

/**
 * 处理更换司机的handler
 */
@Component
@ErrorOrderResultType(ErrorOrderResultEnum.CHANGE_DRIVER) // 标记为更换司机的处理器
public class ChangeDriverHandler extends ErrorOrderHandler{
    /**  注入司机service */
    @Autowired
    private DriverService driverService;
    
    /** 继承抽象处理器 ErrorOrderHandler 实现具体的操作逻辑*/
    @Override
    public Object errorOrderHandler(ErrorOrderInfo info) {
        // 省去一些业务逻辑
        
        // changeDriver方法是更换司机的具体实现
        return driverService.changeDriver(info);
    }
}

1.3 初始化CancelOrderHandler和ChangeDriverHandler
将其初始化到HandlerContext中

/**
 * 异常订单处理器上下文对象
 */
public class HandlerContext {
    
    private final Map<ErrorOrderResultEnum, ErrorOrderHandler> handlerMap;
    
    public HandlerContext(Map<ErrorOrderResultEnum, ErrorOrderHandler> handlerMap) {
        this.handlerMap = handlerMap;
    }
    
    /**
     * 获得实例
     */
    public ErrorOrderHandler getInstance(ErrorOrderResultEnum type) {
        return handlerMap.get(type);
    }
}

1.4 对HandlerContext初始化

/**
 * 初始化数据
 */
@Component
public class HandlerProcessor implements BeanFactoryPostProcessor {
    /** 保存初始化后的handler */
    private final Map<ErrorOrderResultEnum, ErrorOrderHandler> handlerMap = new ConcurrentHashMap(ErrorOrderResultEnum.values().length);
    /**
     * 将HandlerContext单例注册到bean工厂,构造注入handlerMap
     * @param beanFactory bean工厂
     */
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        for (ErrorOrderResultEnum temp : ErrorOrderResultEnum.values()) {
            ErrorOrderHandler handler = this.getBeansWithAnnotation(beanFactory,
                    ErrorOrderHandler.class,ErrorOrderResultType.class,temp);
            if (handler != null) {
                handlerMap.put(temp, handler);
            }
        }
        // 将HandlerContext以单例模式注册到beanFactory中
        HandlerContext context = new HandlerContext(handlerMap);
        beanFactory.registerSingleton(HandlerContext.class.getName(),context);
    }
    
    /**
     * 获取带有@ErrorOrderResultType注解的bean
     * @param beanFactory bean工厂
     * @param parentClass 带有@ErrorOrderResultType的bean的父类
     * @param anno @ErrorOrderResultType注解
     * @param type 枚举类型
     */
    private <T> T getBeansWithAnnotation(ConfigurableListableBeanFactory beanFactory,
                                                     Class<T> parentClass,
                                                     Class<? extends ErrorOrderResultType> anno,
                                                     ErrorOrderResultEnum type) {
        Collection<T> tCollection = beanFactory.getBeansOfType(parentClass).values();
        for (T t : tCollection) {
            // 是否有@ErrorOrderResultType注解
            ErrorOrderResultType annotation = t.getClass().getAnnotation(anno);
            if (annotation != null) {
                // 枚举bean上的枚举类型是否对应
                ErrorOrderResultEnum e = annotation.value();
                // 返回枚举类型匹配的bean
                if (e != null && type.getResult().equals(e.getResult())) {
                    return t;
                }
            }
        }
        return null;
    }
}

1.5 改造OrderErrorService

@Service
@Transactional(rollbackFor = Exception.class)
public class OrderErrorServiceImpl implements OrderErrorService{
    @Autowired
    private HandlerContext context;
    /**
     * 异常订单处理
     */
    @Override
    public void handleErrorOrder(ErrorOrderInfo info) {
        // 省略一些业务逻辑处理。。。
        
        // 开始处理平台对上报异常之后不同处理方式的功能实现
        // if (ErrorOrderResultEnum.CANCEL_ORDER.getResult().equals(info.getResult())) {
        //     // 平台对异常订单做出"取消订单"操作
        // } else if (ErrorOrderResultEnum.CHANGE_DRIVER.getResult().equals(info.getResult())) {
        //     // 平台对异常订单做出"更换司机"操作
        // }
        // 更多处理方式
    
        
        // 通过info获取到对应的枚举类(此处省略具体的实现),通过枚举类获取对应的处理器
        ErrorOrderHandler instance = context.getInstance(type);
        instance.errorOrderHandler(info);
    }
}

改造后的结果

在CancleOrderHandelr中@Autowire注入的OrderService变成了null
在这里插入图片描述

二、探索之路

2.1 @autowire注入null
2.2 尝试了set方法注入 依旧是null
2.3 构造注入,还是null
2.4 于是又通过@postConstruct初始化,还是null

@Autowired
    private Orderservice orderservice;
    
    private static CancelOrderHandler cancelOrderHandler;
    @PostConstruct
    public void init() {
        cancelOrderHandler = this;
        cancelOrderHandler.orderservice = this.orderservice;
    }

2.5 通过spring上下文工具类获取,还是null
SpringUtils

@Component
public final class SpringUtils implements BeanFactoryPostProcessor {
    /**
     * Spring应用上下文环境
     */
    private static ConfigurableListableBeanFactory beanFactory;

    @Override
    public void postProcessBeanFactory(@NotNull ConfigurableListableBeanFactory beanFactory) throws BeansException {
        SpringUtils.beanFactory = beanFactory;
    }

    /**
     * 获取对象
     *
     * @param name
     * @return Object 一个以所给名字注册的bean的实例
     * @throws BeansException
     */
    @SuppressWarnings("unchecked")
    public static <T> T getBean(String name) throws BeansException {
        return (T) beanFactory.getBean(name);
    }

    /**
     * 获取类型为requiredType的对象
     *
     * @param clz 类型
     * @return T
     * @throws BeansException
     */
    public static <T> T getBean(Class<T> clz) throws BeansException {
        return beanFactory.getBean(clz);
    }
}
private final OrderService orderService = SpringUtils.getBean(OrderService.class);

2.6于是开始怀疑应该是初始化CancleOrderHandler的时候出了问题
通过debug发现,确实是bean生命周期的问题,初始化的时候handlerMap中的存储的bean并没有进行属性注入,就被取出来放到了handlerMap中
在这里插入图片描述

三、解决方案

于是改造HandlerProcessor,同时实现BeanPostProcessor, BeanFactoryPostProcessor两个接口,并重写以下两个方法

/**
 * 初始化数据
 */
@Component
public class HandlerProcessor implements BeanPostProcessor, BeanFactoryPostProcessor {
    private final Map<ErrorOrderResultEnum, ErrorOrderHandler> handlerMap = new ConcurrentHashMap(ErrorOrderResultEnum.values().length);
    /**
     * 将HandlerContext单例注册到bean工厂,构造注入handlerMap
     * @param beanFactory bean工厂
     */
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 将HandlerContext以单例模式注册到beanFactory中
        HandlerContext context = new HandlerContext(handlerMap);
        beanFactory.registerSingleton(HandlerContext.class.getName(),context);
    }
    /**
     * 初始化handlerMap,每当初始完一个bean调用一次该方法
     * @param bean bean对象
     * @param beanName bean名字
     * @return 不能返回null,因为后置处理器从ioc取出后不会主动还回去,否则后续不能从ioc容器获得该bean,所以需要return回去而不是return null
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    // 该方法是等bean完全初始化完之后再取出来放到handlerMap中,以供自己后期使用
    // 此处省略具体的实现
	}
}    

再次测试,发现OrderService不再为 null,成功注入
在这里插入图片描述

标签:Autowired,beanFactory,private,class,bean,ErrorOrderResultEnum,null,public,指针
来源: https://blog.csdn.net/qq_16229395/article/details/121453306

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有