博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
解决xxl-job与springsecurity异常问题Scope ‘request‘ is not active
阅读量:2216 次
发布时间:2019-05-07

本文共 7766 字,大约阅读时间需要 25 分钟。

开发碰到了一个奇怪的异常如下

Error creating bean with name 'scopedTarget.oauth2ClientContext': Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
错误原因是引入了xxl-job和springsecurity。翻了下xxl-job官方issue如下
自己跟了下代码
XxlJobSpringExecutor#initJobHandlerMethodRepository

private void initJobHandlerMethodRepository(ApplicationContext applicationContext) {
//省略。。。。 String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames(); for (String beanDefinitionName : beanDefinitionNames) {
// 代码在此处抛了异常 Object bean = applicationContext.getBean(beanDefinitionName); //省略代码

AbstractBeanFactory#doGetBean跟到代码块如下

//异常抛出位置Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName); try {
return createBean(beanName, mbd, args); } finally {
afterPrototypeCreation(beanName); } }); bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);

进入Scope.get发现其实现如下。

在这里插入图片描述
根据异常可知scopedTarget.oauth2ClientContext这个beanScoperequest,所以它走到了AbstractRequestAttributesScope这个实现中
AbstractRequestAttributesScope#get代码如下在第一行时就抛出了异常

@Override	public Object get(String name, ObjectFactory
objectFactory) {
RequestAttributes attributes = RequestContextHolder.currentRequestAttributes(); Object scopedObject = attributes.getAttribute(name, getScope()); if (scopedObject == null) {
scopedObject = objectFactory.getObject(); attributes.setAttribute(name, scopedObject, getScope()); // Retrieve object again, registering it for implicit session attribute updates. // As a bonus, we also allow for potential decoration at the getAttribute level. Object retrievedObject = attributes.getAttribute(name, getScope()); if (retrievedObject != null) {
// Only proceed with retrieved object if still present (the expected case). // If it disappeared concurrently, we return our locally created instance. scopedObject = retrievedObject; } } return scopedObject; }

然而我们xxl-job并不需要拿这个bean,xxl-job需要的bean都是单例的。但是我们又不想去修改xxl-job代码怎么办呢?

那就新写个类XxlJobSpringExecutorProxy继承XxlJobSpringExecutor

public class XxlJobSpringExecutor extends XxlJobSpringExecutor {
@Override public void afterPropertiesSet() throws Exception {
// init JobHandler Repository initJobHandlerRepository(XxlJobSpringExecutor .getApplicationContext); // init JobHandler Repository (for method) initJobHandlerMethodRepository(XxlJobSpringExecutor .getApplicationContext); // refresh GlueFactory GlueFactory.refreshInstance(1); // super start super.start(); } // destroy @Override public void destroy() {
super.destroy(); } private void initJobHandlerRepository(ApplicationContext applicationContext) {
if (applicationContext == null) {
return; } // init job handler action Map
serviceBeanMap = applicationContext.getBeansWithAnnotation(JobHandler.class); if (serviceBeanMap != null && serviceBeanMap.size() > 0) {
for (Object serviceBean : serviceBeanMap.values()) {
if (serviceBean instanceof IJobHandler) {
String name = serviceBean.getClass().getAnnotation(JobHandler.class).value(); IJobHandler handler = (IJobHandler) serviceBean; if (loadJobHandler(name) != null) {
throw new RuntimeException("xxl-job jobhandler[" + name + "] naming conflicts."); } registJobHandler(name, handler); } } } } private void initJobHandlerMethodRepository(ApplicationContext applicationContext) {
if (applicationContext == null) {
return; } // 修改掉这一行,然后初始化的时候使用我们自己这个类即可,意味只获取单例的beanDefinitionNames这样就不会取到Scope为其它的bean。 String[] beanDefinitionNames = applicationContext.getBeanNamesForType(Object.class, false, true); for (String beanDefinitionName : beanDefinitionNames) {
Object bean = applicationContext.getBean(beanDefinitionName); Method[] methods = bean.getClass().getDeclaredMethods(); for (Method method: methods) {
XxlJob xxlJob = AnnotationUtils.findAnnotation(method, XxlJob.class); if (xxlJob != null) {
// name String name = xxlJob.value(); if (name.trim().length() == 0) {
throw new RuntimeException("xxl-job method-jobhandler name invalid, for[" + bean.getClass() + "#"+ method.getName() +"] ."); } if (loadJobHandler(name) != null) {
throw new RuntimeException("xxl-job jobhandler[" + name + "] naming conflicts."); } // execute method if (!(method.getParameterTypes()!=null && method.getParameterTypes().length==1 && method.getParameterTypes()[0].isAssignableFrom(String.class))) {
throw new RuntimeException("xxl-job method-jobhandler param-classtype invalid, for[" + bean.getClass() + "#"+ method.getName() +"] , " + "The correct method format like \" public ReturnT
execute(String param) \" ."); } if (!method.getReturnType().isAssignableFrom(ReturnT.class)) {
throw new RuntimeException("xxl-job method-jobhandler return-classtype invalid, for[" + bean.getClass() + "#"+ method.getName() +"] , " + "The correct method format like \" public ReturnT
execute(String param) \" ."); } method.setAccessible(true); // init and destory Method initMethod = null; Method destroyMethod = null; if(xxlJob.init().trim().length() > 0) {
try {
initMethod = bean.getClass().getDeclaredMethod(xxlJob.init()); initMethod.setAccessible(true); } catch (NoSuchMethodException e) {
throw new RuntimeException("xxl-job method-jobhandler initMethod invalid, for[" + bean.getClass() + "#"+ method.getName() +"] ."); } } if(xxlJob.destroy().trim().length() > 0) {
try {
destroyMethod = bean.getClass().getDeclaredMethod(xxlJob.destroy()); destroyMethod.setAccessible(true); } catch (NoSuchMethodException e) {
throw new RuntimeException("xxl-job method-jobhandler destroyMethod invalid, for[" + bean.getClass() + "#"+ method.getName() +"] ."); } } // registry jobhandler registJobHandler(name, new MethodJobHandler(bean, method, initMethod, destroyMethod)); } } } }

大功告成。

转载地址:http://atkfb.baihongyu.com/

你可能感兴趣的文章
阿里云《云原生》公开课笔记 第九章 应用存储和持久化数据卷:核心知识
查看>>
linux系统 阿里云源
查看>>
国内外helm源记录
查看>>
牛客网题目1:最大数
查看>>
散落人间知识点记录one
查看>>
Leetcode C++ 随手刷 547.朋友圈
查看>>
手抄笔记:深入理解linux内核-1
查看>>
内存堆与栈
查看>>
Leetcode C++《每日一题》20200621 124.二叉树的最大路径和
查看>>
Leetcode C++《每日一题》20200622 面试题 16.18. 模式匹配
查看>>
Leetcode C++《每日一题》20200625 139. 单词拆分
查看>>
Leetcode C++《每日一题》20200626 338. 比特位计数
查看>>
Leetcode C++ 《拓扑排序-1》20200626 207.课程表
查看>>
Go语言学习Part1:包、变量和函数
查看>>
Go语言学习Part2:流程控制语句:for、if、else、switch 和 defer
查看>>
Go语言学习Part3:struct、slice和映射
查看>>
Go语言学习Part4-1:方法和接口
查看>>
Leetcode Go 《精选TOP面试题》20200628 69.x的平方根
查看>>
leetcode 130. Surrounded Regions
查看>>
【Python】详解Python多线程Selenium跨浏览器测试
查看>>