今天在工作中碰到这样一个, 其实之前也遇到过, 但是并没有具体的去了解详情, 今天由于疏忽再次碰到了这个问题, 所以这里和大家分享一下。
起初是这样的:
Listener<P> 接口, 负责处理事件,
ListenerRegistry 负责dispatcher 事件处理接口,也就是Listener, Listener 在实力化时通过 spring的InitializingBean 回调接口向ListenerRegistry注册自己.
下面是代码:
Listener接口:
public interface Listener<P> extends InitializingBean {
/**
* 是否支持此事件
* @param event 事件类型
* @return boolean
*/
boolean isSupport(Event event);
/**
* 处理事件
* @param param 参数
*/
LogisticsResult<Boolean> handle(P param);
}
ListenerRegistry:
@Service
@Slf4j
public class ListenerRegistry implements BeanFactoryPostProcessor {
private List<Listener> listeners = new ArrayList<>();
private ConfigurableListableBeanFactory beanFactory;
public void register(Listener listener) {
if(listener != null) {
listeners.add(listener);
}
}
public <P> LogisticsResult<Boolean> call(Event event,P param) {
try {
for (Listener listener : listeners) {
if(listener.isSupport(event)) {
return listener.handle(param);
}
}
return LogisticsResult.success(Boolean.TRUE);
} catch (Exception e) {
return LogisticsResult.fail("回调处理异常,"+e.getMessage());
}
}
}
AbstractListener: 所有事件处理器继承这个抽象类
public abstract class AbstractListener<P> implements Listener<P> {
@Autowired
protected ListenerRegistry listenerRegistry;
@Override
public void afterPropertiesSet() throws Exception {
listenerRegistry.register(this);
}
}
现在有这样一个类,接收事件, 然后调用ListenerRegistry:
@Service
@Slf4j
public class ReceiverServiceImpl implements ReceiverService {
@Autowired
private ListenerRegistry listenerRegistry;
@Override
public LogisticsResult<Boolean> pushQuotationInfo(InquireBidDTO inquireBidDTO){
return listenerRegistry.call(Event.Inquire_Callback,inquireBidDTO);
}
}
整个应用的配置,spring bean 默认都是懒加载的,
如上面所写, 应用可以正常启动, 但是当ReceiverService 接收到事件并传给 ListenerRegistry时, 事件并不会得到处理.
经过debug, 发现 ListenerRegistry 中并没有事件处理器注册, 这个问题不难理解,因为懒加载的问题,
还有个前提, 就是应用中没有其他类引用事件处理器,也就是Listener, 这样,Listener 实现类并被没有被spring 创建, 自然而然
InitializingBean接口也不被调用, 就不会像ListenerRegistry注册.
然后经过改造ListenerRegistry如下:
@Service
@Slf4j
public class ListenerRegistry implements BeanFactoryPostProcessor {
private List<Listener> listeners = new ArrayList<>();
private ConfigurableListableBeanFactory beanFactory;
public void register(Listener listener) {
if(listener != null) {
listeners.add(listener);
}
}
public <P> LogisticsResult<Boolean> call(Event event,P param) {
try {
for (Listener listener : listeners) {
if(listener.isSupport(event)) {
return listener.handle(param);
}
}
return LogisticsResult.success(Boolean.TRUE);
} catch (Exception e) {
return LogisticsResult.fail("回调处理异常,"+e.getMessage());
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
beanFactory.getBeansOfType(Listener.class);
}
}
上述改造实现了
BeanFactoryPostProcessor, 通过此postProcessBeanFactory(), 调用beanFactory.getBeansOfType(Listener.class),以触发Listener实现类的实例化
但是如上所写,依然存在问题, 就是 Listener 实现类中的依赖(通过@Autowire)的属性无法注入, 导致 导致调用ListenerRegistry.register接口时,抛空指针异常.
经过断点调试, 发现在BeanFactoryPostProcessor 执行时,
InstantiationAwareBeanPostProcessor(实现了BeanPostProcessor接口)还未被实例化
这个接口有什么用呢?
其实@Autowire 注解处理是由
AutowiredAnnotationBeanPostProcessor来完成, 它继承了InstantiationAwareBeanPostProcessor,最终的处理是由InstantiationAwareBeanPostProcessor.postProcessPropertyValues这个方法来完成, AutowiredAnnotationBeanPostProcessor重写了这个方法,其代码如下:
@Override
public PropertyValues postProcessPropertyValues(
PropertyValues pvs,
PropertyDescriptor[] pds,
Object bean, String beanName) throws BeansException {
InjectionMetadata metadata = findAutowiringMetadata(beanName,
bean.getClass(), pvs);
try {
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
具体的代码有兴趣者可以去看看.
找到了原因,就好处理了, 最终的代码如下,其实之前有这样写过,但是没有很详细的了解为什么要非要这么写:
改造后的ListenerRegistry:
@Service
@Slf4j
public class ListenerRegistry implements BeanFactoryPostProcessor {
private List<Listener> listeners = new ArrayList<>();
private ConfigurableListableBeanFactory beanFactory;
public void init() {
beanFactory.getBeansOfType(Listener.class);
}
public void register(Listener listener) {
if(listener != null) {
listeners.add(listener);
}
}
public <P> LogisticsResult<Boolean> call(Event event,P param) {
try {
log.info("[[ListenerRegistry.call]>>>>回调处理,事件:{},参数:{}",event.getName(), JsonUtils.toJson(param));
for (Listener listener : listeners) {
if(listener.isSupport(event)) {
return listener.handle(param);
}
}
return LogisticsResult.success(Boolean.TRUE);
} catch (Exception e) {
log.error("[ListenerRegistry.call]>>>>调用异常,事件:{},参数:{},ERROR:{}",event.getName(), JsonUtils.toJson(param),e.getMessage(),e);
return LogisticsResult.fail("回调处理异常,"+e.getMessage());
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
}
改造后postProcessBeanFactory不做具体事宜, 新增init方法去触发Listener实现类的实例化,
还需要添加一个类,来调用ListenerRegistry的init方法,代码如下:
@Service
@Lazy(false)
public class ListenerRegistryHelper {
@Autowired
private ListenerRegistry listenerRegistry;
@PostConstruct
public void init() {
listenerRegistry.init();
}
}
前提是要关闭此类的延迟初始化,为什么这样就可以了呢, 对于spring 来说,非懒加载的单例实例化时那些BeanPostProcessor接口已实例化, 就能处理Autowire注解了.
好了,到这里就结束