Spring事件
事件
标识
在业务场景中有可能当A方法执行过程中需要调用B方法,但是不需要等待B方法处理完成,可以继续执行A方法,降低响应时间。
在spring中内置了这种事件机制来处理上述业务。需要使用到的两个注解为@EnableAsync
,@Async
。
@EnableAsync:用于开启是否异步,不用该注解标识类则会默认事件为同步机制。
使用方式有两种:
第一种是直接标识到B方法的类。
第二种是使用配置方式:
@Configuration
@EnableAsync
public class SpringAsyncConfig { ... }
@Async:是标识哪个方法使用异步,没标识则视为同步处理。
发送事件
使用到的是@EventListener
和ApplicationEvent
类
@EventListener: 用于标注事件的方法。
ApplicationEvent:事件扩展内容。
使用方式:
// 事件方法
@Async
@EventListener
public void saveOntologyInstance(OntologyIdSaveEvent ontologyIdSaveEvent){
...
}
// 事件类
public class OntologyIdSaveEvent extends ApplicationEvent {
...
}
// 事件发送
applicationContext.publishEvent(new OntologyIdSaveEvent(this, ontologyInstanceIds));
问题
aop代理方式问题
先附上日志:
org.springframework.beans.factory.BeanInitializationException:
Failed to process @EventListener annotation on bean with name 'neo4jServiceImpl';
nested exception is java.lang.IllegalStateException:
Need to invoke method 'saveOntologyInstance' declared on target class 'Neo4jServiceImpl',
but not found in any interface(s) of the exposed proxy type. Either pull the method up
to an interface or switch to CGLIB proxies by enforcing proxy-target-class mode in your
configuration.
日志提示的很明显,代理模式不对。
简单介绍一下spring中的aop两种模式:
cglib和jdk动态代理,简单一点就是jdk动态代理只针对接口的类生成代理,cglib针对实现类代理。
当接口没定义方法而事件调用了该方法时就会报这个错。
解决方式有两种:
第一种在接口中定义该方法。
第二种在@EnableAsync
指定proxyTargetClass
为true
强制使用cglib代理。
循环依赖问题
这个问题是一个很典型的问题,spring自己也给出了自己的处理方式,在业务中也应该尽量避免循环注入。
该问题产生原因是A方法调用B类的方法,B类通过spring注入了A方法所在的类就产生循环注入问题。
规避方式把事件方法抽离出来,形成独立的类,业务尽量解耦。