栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

@Autowired注入null空指针和解决

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

@Autowired注入null空指针和解决

一、问题背景

在自定义的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 {
    
    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

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

ChangeDriverHandler更换司机的handler

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

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

public class HandlerContext {
    
    private final Map handlerMap;
    
    public HandlerContext(Map handlerMap) {
        this.handlerMap = handlerMap;
    }
    
    
    public ErrorOrderHandler getInstance(ErrorOrderResultEnum type) {
        return handlerMap.get(type);
    }
}

1.4 对HandlerContext初始化

@Component
public class HandlerProcessor implements BeanFactoryPostProcessor {
    
    private final Map handlerMap = new ConcurrentHashMap(ErrorOrderResultEnum.values().length);
    
    @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);
    }
    
    
    private  T getBeansWithAnnotation(ConfigurableListableBeanFactory beanFactory,
                                                     Class parentClass,
                                                     Class anno,
                                                     ErrorOrderResultEnum type) {
        Collection 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 {
    
    private static ConfigurableListableBeanFactory beanFactory;

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

    
    @SuppressWarnings("unchecked")
    public static  T getBean(String name) throws BeansException {
        return (T) beanFactory.getBean(name);
    }

    
    public static  T getBean(Class 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 handlerMap = new ConcurrentHashMap(ErrorOrderResultEnum.values().length);
    
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 将HandlerContext以单例模式注册到beanFactory中
        HandlerContext context = new HandlerContext(handlerMap);
        beanFactory.registerSingleton(HandlerContext.class.getName(),context);
    }
    
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    // 该方法是等bean完全初始化完之后再取出来放到handlerMap中,以供自己后期使用
    // 此处省略具体的实现
	}
}    

再次测试,发现OrderService不再为 null,成功注入

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/582103.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号