@Autowired构造方法如何传入非Spring托管的自定义变量?
错误原因
被Spring管理的Vaadin路由视图,在容器初始化时会自动解析构造方法的所有参数,要求每个参数都能在Spring上下文找到对应注册的Bean。你把动态传入的业务实体Movie加到构造参数后,Spring会尝试从容器中查找Movie类型的Bean完成注入,但Movie是运行时动态关联的业务数据,不是提前注册到容器的Bean,自然会抛出自动装配失败的错误。
解决方法
不要把动态业务参数放在被@Autowired标记的构造方法里,Vaadin路由视图的动态传参要通过路由参数+生命周期钩子实现,具体实现逻辑如下:
- 构造方法只保留需要Spring注入的服务类参数,不要加
Movie类型的构造入参 - 实现
BeforeEnterObserver接口,在视图进入前从路由参数中读取影片ID,查询得到对应的Movie实体 - 其他视图跳转时,通过路由参数传递目标影片的ID即可
完整实现代码:
@PageTitle("GiveReview") @Route(value = "givereview", layout = MainLayout.class) @PermitAll public class GiveReviewView extends Div implements BeforeEnterObserver { private final AuthenticatedUser authenticatedUser; private final ReviewService reviewService; private final MovieService movieService; private Movie movie; @Autowired public GiveReviewView(AuthenticatedUser authenticatedUser, ReviewService reviewService, MovieService movieService) { this.authenticatedUser = authenticatedUser; this.reviewService = reviewService; this.movieService = movieService; } @Override public void beforeEnter(BeforeEnterEvent event) { // 从路由参数中获取影片ID Optional<String> movieIdOpt = event.getRouteParameters().get("movieId"); if (movieIdOpt.isEmpty()) { // 未传影片ID时直接转发回影片列表页,避免空指针 event.forwardTo(MovieListView.class); return; } try { Long movieId = Long.parseLong(movieIdOpt.get()); this.movie = movieService.getById(movieId); if (this.movie == null) { event.forwardTo(MovieListView.class); return; } // 拿到关联的影片对象后再初始化影评表单 initForm(); } catch (NumberFormatException e) { event.forwardTo(MovieListView.class); } } private void initForm() { // 在这里写影评表单的渲染、提交逻辑,可以直接使用this.movie关联影评 } }
其他类跳转到影评页的传参示例:
// 传入目标影片的ID作为路由参数即可 getUI().ifPresent(ui -> ui.navigate(GiveReviewView.class, RouteParameters.of("movieId", String.valueOf(currentMovie.getId())) ));
注意:不要在其他业务类中手动new
GiveReviewView实例,Vaadin路由视图统一由导航机制触发初始化,手动实例化的视图不会走Spring自动装配逻辑,服务类会出现空指针问题。如果不希望URL暴露影片ID,也可以在跳转前把Movie对象存入Session属性,在beforeEnter方法中取出使用,但路由参数的方案更稳定,刷新页面、分享链接都不会丢失上下文。
内容的提问来源于stack exchange,提问作者Alabama92
相关产品推荐
相关产品推荐

