You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot工厂模式下RouteFactory Bean注入失败及空指针问题

Spring Boot结合工厂模式与JpaRepository实现Route创建的问题

我在Spring Boot应用中结合工厂设计模式与JpaRepository实现Route(道路)的创建,遇到了依赖注入和空指针相关问题,以下是详细代码与错误信息:


实体类Route

@Entity
@Table(name = "route", schema="location")
@Getter
@Setter
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Route implements Serializable {

private static final long serialVersionUID = 1L;

  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "route_generator")
  private long id;
  
  @Column(name = "route_type")
  private String routeType;
  
  @Column(name = "route_name")
  private String routeName;
  @Column(name = "route_width")
  private long routeWidth;

  @Column(name = "description")
  private String description;
}

RouteRepository仓库接口

public interface RouteRepository extends JpaRepository<Route, Long>{

    Iterable<Route> findByRouteType(String route_type);

    int createRouteByType(Route route);
    
    int deleteRouteByRouteType(String routeType);
    
    //List<Route> findRoutesByQuartierId(Long quartierId);
}

RouteFactory工厂接口

public interface RouteFactory {
    public <T> RouteRepository getRouteService(String routeType);
}

初始服务类实现(以nationalRoad为例)

@Service("nationaleRoad")
public class CountryRouteService implements RouteRepository{

@Override
 public int createRouteByType(Route route) {
        Route _route = new Route();
        _route.setRouteType("nationaleRoad");
        _route.setRouteName(route.getRouteName());
        _route.setRouteName(route.getRouteWidth()*4); // 注:此处重复调用setRouteName,应为setRouteWidth
        _route.setDescription(route.getDescription());          
        save(_route);
    
        return 1 ;
 };

@Override
public int deleteRouteByRouteType(String routeType) {
    // TODO Auto-generated method stub
    return 0;
}
    // 其他JpaRepository方法的实现...
}

regionalRoad类型的服务类结构类似,但存在类名重复(同样命名为CountryRouteService)的问题。

初始控制器代码

@Slf4j
@CrossOrigin(origins = "http://localhost:8080")
@RestController
@RequestMapping("/api")
public class RouteController {
  
  private static final Logger log = LoggerFactory.getLogger(RouteController.class);
  
  private final RouteFactory factory;
  
  public RouteController(RouteFactory factory) {
      this.factory = factory;
  }
  
  @PostMapping("/route/")
  public void createRoute(@RequestBody Route route) {
      log.info("Logging the Routefactory {}", factory);
      factory.getRouteService(route.getRouteType()).createRouteByType(route);
        System.out.println("Successfully Published the road = ' " + route + " ' to the RegistrationTopic");
        
  }
}

初始错误信息

No qualifying bean of type 'com.emura_group.country_geo_tracing.factory.RouteFactory' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

伴随日志:

Bean creation exception on singleton FactoryBean type check: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration': No bean named 'org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry' available.

已尝试的无效操作:

  • 将控制器构造注入改为@Autowired RouteFactory factory
  • 给RouteFactory添加@Service/@Component/@Repository注解

修改后的代码(编辑后)

修改后的服务类(不再实现RouteRepository)

@Service("nationaleRoad")
public class CountryRouteService{

@Autowired
RouteRepository routeRepository;
 public int createRouteByType(Route route) {
        Route _route = new Route();
        _route.setRouteType("nationaleRoad");
        _route.setRouteName(route.getRouteName());
        _route.setRouteName(route.getRouteWidth()*4); // 仍存在重复setRouteName的问题
        _route.setDescription(route.getDescription());          
        routeRepository.save(_route);

        return 1 ;
 };

public int deleteRouteByRouteType(String routeType) {
    // TODO Auto-generated method stub
    return 0;
}
    // 其他方法...
}

修改后的控制器

@Slf4j
@CrossOrigin(origins = "http://localhost:8080")
@RestController
@RequestMapping("/api")
public class RouteController {
  
private static final Logger log = 
  LoggerFactory.getLogger(RouteController.class);
  
  RouteFactory factory;
  
  @PostMapping("/route/")
  public void createRoute(@RequestBody Route route) {
      log.info("Logging the Routefactory {}", factory);
      factory.getRouteService(route.getRouteType()).createRouteByRouteType(route);
        System.out.println("Successfully created the road = ' " + route + " ' to the RegistrationTopic");
    
  }
}

修改后新错误

java.lang.NullPointerException: Cannot invoke "com.emura_group.country_geo_tracing.factory.RouteFactory.getRouteService(String)" because "this.factory" is null

再次尝试@Autowired注入RouteFactory,回到最初的找不到bean错误。


解决方案

1. 实现RouteFactory的具体类,让Spring能识别并创建Bean

RouteFactory是接口,Spring无法直接实例化,必须提供实现类并标记为Spring组件:

@Component
public class RouteFactoryImpl implements RouteFactory {

    private final Map<String, RouteService> routeServiceMap;

    // Spring自动注入所有实现RouteService接口的Bean,key为Bean名称
    public RouteFactoryImpl(Map<String, RouteService> routeServiceMap) {
        this.routeServiceMap = routeServiceMap;
    }

    @Override
    public RouteService getRouteService(String routeType) {
        RouteService service = routeServiceMap.get(routeType);
        if (service == null) {
            throw new IllegalArgumentException("不支持的路由类型: " + routeType);
        }
        return service;
    }
}

2. 定义统一的RouteService接口,规范服务类

解决之前服务类类名重复、职责混乱的问题,定义统一接口:

public interface RouteService {
    int createRouteByType(Route route);
    int deleteRouteByRouteType(String routeType);
}

然后让各路由类型的服务实现该接口:

@Service("nationaleRoad")
public class NationalRouteService implements RouteService {

    @Autowired
    private RouteRepository routeRepository;

    @Override
    public int createRouteByType(Route route) {
        Route _route = new Route();
        _route.setRouteType("nationaleRoad");
        _route.setRouteName(route.getRouteName());
        _route.setRouteWidth(route.getRouteWidth() * 4); // 修正之前的setRouteName错误
        _route.setDescription(route.getDescription());
        routeRepository.save(_route);
        return 1;
    }

    @Override
    public int deleteRouteByRouteType(String routeType) {
        return routeRepository.deleteRouteByRouteType(routeType);
    }
}
@Service("regionaleRoad")
public class RegionalRouteService implements RouteService {

    @Autowired
    private RouteRepository routeRepository;

    @Override
    public int createRouteByType(Route route) {
        Route _route = new Route();
        _route.setRouteType("regionaleRoad");
        _route.setRouteName(route.getRouteName());
        _route.setRouteWidth(route.getRouteWidth() * 2); // 修正setRouteWidth
        _route.setDescription(route.getDescription());
        routeRepository.save(_route);
        return 1;
    }

    @Override
    public int deleteRouteByRouteType(String routeType) {
        return routeRepository.deleteRouteByRouteType(routeType);
    }
}

3. 修正RouteFactory接口泛型

调整接口返回统一的RouteService类型,避免类型转换问题:

public interface RouteFactory {
    RouteService getRouteService(String routeType);
}

4. 修正控制器注入方式

使用构造注入(Spring推荐方式)确保RouteFactory被正确注入:

@Slf4j
@CrossOrigin(origins = "http://localhost:8080")
@RestController
@RequestMapping("/api")
public class RouteController {
  
    private static final Logger log = LoggerFactory.getLogger(RouteController.class);
  
    private final RouteFactory factory;
  
    public RouteController(RouteFactory factory) {
        this.factory = factory;
    }
  
    @PostMapping("/route/")
    public void createRoute(@RequestBody Route route) {
        log.info("Logging the Routefactory {}", factory);
        RouteService service = factory.getRouteService(route.getRouteType());
        service.createRouteByType(route);
        System.out.println("Successfully created the road = ' " + route + " '");
    }
}

5. 修复RouteRepository自定义方法

RouteRepository中的自定义方法需要添加@Query注解实现,比如deleteRouteByRouteType:

@Modifying
@Query("DELETE FROM Route r WHERE r.routeType = :routeType")
int deleteRouteByRouteType(@Param("routeType") String routeType);

createRouteByType方法建议删除,因为创建逻辑已在服务层实现,避免职责混淆。

6. 解决事务相关日志错误

确保项目引入spring-boot-starter-data-jpa依赖,并配置正确的数据源:

Maven依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

application.properties配置示例:

spring.datasource.url=jdbc:mysql://localhost:3306/your_db
spring.datasource.username=root
spring.datasource.password=your_password
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

内容的提问来源于stack exchange,提问作者Himmels DJ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 23:32:32