关于在自定义分片代码中使用springBean注入的问题

方便更快捷的说明问题,可以按需填写(可删除)

环境说明

<java.version>17</java.version>
<spring-boot.version>3.0.2</spring-boot.version>
<mybatis.plus.version>3.5.3</mybatis.plus.version>
<mysql.version>8.0.27</mysql.version>

shardingsphere-jdbc:
<dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>shardingsphere-jdbc</artifactId>
            <version>5.5.0</version>
            <exclusions>
                <exclusion>
                    <groupId>org.apache.shardingsphere</groupId>
                    <artifactId>shardingsphere-test-util</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

场景、问题:

一些配置

sharding.yaml部分内容
rules:
- !SINGLE
  tables:
    - ds_0.*
  defaultDataSource: ds_0
- !SHARDING
  tables:
    saas_file:
      actualDataNodes: ds_0.saas_files_10001_202404,ds_0.saas_files_10001_202405,ds_0.saas_files_10002_202404,ds_0.saas_files_10002_202405
      tableStrategy:
        complex: # 用于多分片键的复合分片场景
          shardingColumns: file_id,tenant_id,file_upload_time # 分片列名称,多个列以逗号分隔
          shardingAlgorithmName: sharding-altorithm # 分片算法名称
  shardingAlgorithms:
    sharding-altorithm:
      type: CLASS_BASED # 分片算法类型
      props:
        strategy: COMPLEX
        algorithmClassName: com.micolor.saas.storage.sharding.ComplexModTableShardAlgorithm
props:
  sql-show: true
ComplexModTableShardAlgorithm一些内容
@Slf4j
@Component
public class ComplexModTableShardAlgorithm implements ComplexKeysShardingAlgorithm {
    @Override
    public Collection<String> doSharding(Collection collection, ComplexKeysShardingValue complexKeysShardingValue) {
        //处理精确查询
        Map<String, List<Object>> mapSharding = complexKeysShardingValue.getColumnNameAndShardingValuesMap();
        //精确查询
        List<Integer> tenantIds = new ArrayList<>();
        List<String> fileIds = new ArrayList<>();
        if (!mapSharding.isEmpty()) {
            for (Map.Entry<String, List<Object>> entry : mapSharding.entrySet()) {
                String key = entry.getKey();
                List<Object> value = entry.getValue();
                if (key.equals("tenant_id")) {
                    tenantIds = value.stream().map(o -> Integer.parseInt(o.toString())).collect(Collectors.toList());
                }
                if (key.equals("file_id")) {
                    fileIds = value.stream().map(Object::toString).collect(Collectors.toList());
                }
            }
        }
        log.info("tenantIds=>{}",tenantIds);
        log.info("fileIds=>{}",fileIds);
        List<String> list = getTableName(tenantIds,fileIds);
        if(list.isEmpty()){
            return collection;
        }else{
            return list;
        }

    }
    @Autowired
    private FileShardingIndexService fileShardingIndexService;
    private List<String> getTableName(List<Integer> tenantIds,List<String> fileIds){
        List<String> tables = new ArrayList<>();
        try{
            List list = fileShardingIndexService.queryFileShardingIndex(tenantIds,fileIds);
            log.info("list==>{}",list);
            for(int i=0;i<list.size();i++){
                //TODO 搞事情....
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return tables;
    }
}

作业描述

场景

有个文件表(saas_file),对这个表按照tenant_id,file_upload_time2个字段进行了分表。
同时也有个索引表(saas_file_index)表,保存着fileId(文件编号),tenant_id(商户编号),file_upload_year_month(文件上传年月)3个字段。

实现逻辑:

  • 1当用tenant_id查询,就自动拼,没问题。
  • 2 当用fileuploadtime(范围)查询,也自动拼,没问题。
  • 3**(重点)** 当用 =fileid 或者 in(fileids) 的时候,就想根据这些fileid先去索引表中查询(使用fileShardingIndexService查询)出对应的tenant_id和file_upload_year_month,然后把结果拼装起来返回去。
问题

如实现逻辑3中描述,势必需要在ComplexModTableShardAlgorithm类中注入fileShardingIndexService,然后查询数据库。但是通过@Autowired注解无法注入。
请教如何在ComplexModTableShardAlgorithm或者类似的类中注入Spring的Bean.

已进行操作:

  • 已经对fileShardingIndexService单独测试(使用spring controller调用),均能正常运行。
  • 也写了个SpringUtils,尝试,依旧无用,代码如下:

@Component
public class SpringUtils implements ApplicationContextAware  {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringUtils.applicationContext = applicationContext;
    }

    public static <T> T getBean(String beanName) {
        if(applicationContext.containsBean(beanName)){
            return (T) applicationContext.getBean(beanName);
        }else{
            return null;
        }
    }

    public static <T> Map<String, T> getBeansOfType(Class<T> baseType) {
        return applicationContext.getBeansOfType(baseType);
    }
}

现状:

ComplexModTableShardAlgorithm中需要使用fileShardingIndexService类时,报null,报错信息如下:

java.lang.NullPointerException: Cannot invoke "com.micolor.saas.storage.serivce.FileShardingIndexService.queryFileShardingIndex(java.util.List, java.util.List)" because "this.fileShardingIndexService" is null
	at com.micolor.saas.storage.sharding.ComplexModTableShardAlgorithm.getTableName(ComplexModTableShardAlgorithm.java:58)
	at com.micolor.saas.storage.sharding.ComplexModTableShardAlgorithm.doSharding(ComplexModTableShardAlgorithm.java:45)
	at org.apache.shardingsphere.sharding.algorithm.sharding.classbased.ClassBasedShardingAlgorithm.doSharding(ClassBasedShardingAlgorithm.java:110)
	at org.apache.shardingsphere.sharding.route.strategy.type.complex.ComplexShardingStrategy.doSharding(ComplexShardingStrategy.java:72)
	at org.apache.shardingsphere.sharding.route.engine.type.standard.ShardingStandardRoutingEngine.routeTables(ShardingStandardRoutingEngine.java:274)
	at org.apache.shardingsphere.sharding.route.engine.type.standard.ShardingStandardRoutingEngine.route0(ShardingStandardRoutingEngine.java:253)
	at org.apache.shardingsphere.sharding.route.engine.type.standard.ShardingStandardRoutingEngine.routeByShardingConditionsWithCondition(ShardingStandardRoutingEngine.java:143)
	at org.apache.shardingsphere.sharding.route.engine.type.standard.ShardingStandardRoutingEngine.routeByShardingConditions(ShardingStandardRoutingEngine.java:136)
	at org.apache.shardingsphere.sharding.route.engine.type.standard.ShardingStandardRoutingEngine.getDataNodes(ShardingStandardRoutingEngine.java:103)
	at org.apache.shardingsphere.sharding.route.engine.type.standard.ShardingStandardRoutingEngine.route(ShardingStandardRoutingEngine.java:85)
	at org.apache.shardingsphere.sharding.route.engine.ShardingSQLRouter.createRouteContext0(ShardingSQLRouter.java:73)
	at org.apache.shardingsphere.sharding.route.engine.ShardingSQLRouter.createRouteContext(ShardingSQLRouter.java:61)
	at org.apache.shardingsphere.sharding.route.engine.ShardingSQLRouter.createRouteContext(ShardingSQLRouter.java:48)
	at org.apache.shardingsphere.infra.route.engine.impl.PartialSQLRouteExecutor.route(PartialSQLRouteExecutor.java:71)
	at org.apache.shardingsphere.infra.route.engine.SQLRouteEngine.route(SQLRouteEngine.java:59)
	at org.apache.shardingsphere.infra.connection.kernel.KernelProcessor.route(KernelProcessor.java:60)
	at org.apache.shardingsphere.infra.connection.kernel.KernelProcessor.generateExecutionContext(KernelProcessor.java:51)
	at org.apache.shardingsphere.driver.jdbc.core.statement.ShardingSpherePreparedStatement.createExecutionContext(ShardingSpherePreparedStatement.java:580)
	at org.apache.shardingsphere.driver.jdbc.core.statement.ShardingSpherePreparedStatement.execute(ShardingSpherePreparedStatement.java:426)
	at com.zaxxer.hikari.pool.ProxyPreparedStatement.execute(ProxyPreparedStatement.java:44)
	at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.execute(HikariProxyPreparedStatement.java)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.apache.ibatis.logging.jdbc.PreparedStatementLogger.invoke(PreparedStatementLogger.java:58)
	at jdk.proxy4/jdk.proxy4.$Proxy112.execute(Unknown Source)
	at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:65)
	at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:80)
	at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:65)
	at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:336)
	at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:158)
	at com.github.pagehelper.PageInterceptor.intercept(PageInterceptor.java:169)
	at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:59)
	at jdk.proxy2/jdk.proxy2.$Proxy100.query(Unknown Source)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:154)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:147)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:142)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:425)
	at jdk.proxy2/jdk.proxy2.$Proxy84.selectList(Unknown Source)
	at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:224)
	at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.executeForMany(MybatisMapperMethod.java:166)
	at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:77)
	at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:148)
	at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89)
	at jdk.proxy3/jdk.proxy3.$Proxy85.selectList(Unknown Source)
	at com.baomidou.mybatisplus.extension.service.IService.list(IService.java:370)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:699)
	at com.micolor.saas.storage.serivce.impl.FileServiceImpl$$SpringCGLIB$$0.list(<generated>)
	at com.micolor.saas.storage.contorller.FileController.getFile(FileController.java:49)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:207)
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:152)
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797)
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1080)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:973)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1011)
	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914)
	at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:731)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)
	at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:814)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:223)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158)
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158)
	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:177)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:119)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:400)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:859)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1734)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
	at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
	at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.base/java.lang.Thread.run(Thread.java:833)
京ICP备2021015875号