我有一个Spring AppUser类,它具有一个@Autowired注释字段(FriendList),如下所示:

@Getter
@Setter
@Builder
@Document(collection = "app_users")
@Component
public class AppUser {

  @Id
  @NotBlank(message = ErrorConstants.ANDROID_USER_ACCOUNT_MANAGER_ID_IS_NULL)
  private String androidUserAccountManagerId;

  @NotBlank(message = ErrorConstants.NULL_NAME)
  private String name;

  private Friend bestFriend;

  @Autowired
  @Setter(AccessLevel.NONE)
  private FriendList friendList;

  private boolean manualBestFriendOverride;

  public Optional<Friend> getFriend(String friendName) {
    return friendList.getFriend(friendName);
  }

  public void calculateBestFriend() {
    if (!manualBestFriendOverride) {
      bestFriend = friendList.calculateAndReturnBestFriend();
    }
  }
}


这个想法是,每次创建新的AppUser时,它将@Autowire相同的默认friendList从头开始。

正在通过WebController方法创建AppUser:

  @PostMapping("/{androidUserAccountManagerId}/setNewAppUser/{appUserName}")
  public void setNewAppUser(
      @NotNull @PathVariable String androidUserAccountManagerId,
      @NotNull @PathVariable @Pattern(regexp = "^[A-z]{2,20}$", message = "Incorrect name format!")
          String appUserName) {
    databaseQueryClass.save(
        AppUser.builder()
            .androidUserAccountManagerId(androidUserAccountManagerId)
            .name(appUserName)
            .build());
  }


但是,当在其他方法中调用friendList字段时,出现了空指针异常。本质上,自动装配似乎无法与AppUser构建器一起使用。

经过一番阅读后,由于IoC和Dependency Injection是由Spring排序的,因此在实例化的类中调用new或build和autowire一个字段似乎是一种不好的做法。

我的问题是,我该如何解决这个设计问题?这可能吗?还是应该停止尝试在必须创建的新实例中自动装配字段?或者,是否有一种方法可以在命中此端点时自动为新用户布线?

感谢您的帮助。

上下文的FriendList类:

@ToString
@EqualsAndHashCode
@Builder
public class FriendList {

  @NotNull private List<Friend> listOfFriends;

  public Optional<Friend> getFriend(String friendName) {
    return listOfFriends.stream().filter(o -> o.getName().equals(friendName)).findAny();
  }

  public Friend calculateAndReturnBestFriend() {
    if(listOfFriends.isEmpty()){
      return null;
    }

    java.util.Collections.sort(listOfFriends);
    return listOfFriends.get(0);
  }

  public boolean addToFriendList(String friendName) {
    if (getFriend(friendName).isPresent()) {
      return false;
    }
    return listOfFriends.add(
        Friend.builder().name(friendName).meetingDates(new TreeSet<>()).meetUpNumber(0).build());
  }
}


编辑(对不起,我错过了此上下文...)

我在AppConfig类中定义了一个bean:

@Configuration
public class AppConfig {

  @Bean
  @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
  public FriendList getFriendList() {
    return FriendList.builder().listOfFriends(new ArrayList<>()).build();
  }
}

最佳答案

关于您的@Autowired问题,可以使用新的运算符或生成器,只要您让spring容器为您管理该新bean。

例如,您可以执行以下操作:

@Configuration
public class AppConfig {
    @Bean
    public FriendList firendList() {
        return FriendList.builder()
                      //...
                    .build());
    }
}


然后像这样使用它:@Import(AppConfig.class)

请注意,只有在开头创建FriendList时,如上面的默认值以及所有可用信息,以上内容才有效。而且它也只能在由spring管理的AppUser组件上工作。
如果使用控制器中的构建器创建AppUser,则需要@Autowired控制器中的FriendList并将其设置在构建器上。

另一个需要注意的是,如果是动态创建的Friends,那么以示例为例,如果开始时有10个朋友,而1小时后又有10个朋友,则需要查看全部20个朋友,那么您需要另一种方法。
最简单的方法是将朋友存储在数据库中,每次仅获取每个朋友并将其设置在AppUser上。或从缓存映射中检索它们。

您也可以在这种情况下使用@Autowired,但更为复杂,您将需要直接自动连接好友列表:

@Autowired
private List<Friend> friends;


每个朋友应该动态创建。
像这样

Friend friend = new Friend();
context.registerBean(Friend.class, () -> friend);  //context here is an ApplicationContext type aka Spring Container.


还要使用ObjectProvider中的here来检查此示例。

关于java - Spring Autowired和Builder批注,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/60976452/

10-11 17:39