为什么要在 Spring Boot 中使用 @Service 构造型?

Why should I use @Service stereotype in Spring Boot?

我知道@Service 是@Component 的一种,就像@Controller 和@Repository 一样。我还了解到,这些类型级别(class 级别)构造型有助于组件扫描在您的 spring 项目中选择不同的类型。

我注意到 class 我创建的处理业务逻辑的 FileResourceManager 在没有 @Service 的情况下也能正常工作。 我想更好地理解这种刻板印象的作用,以及为什么它是有益的。如果对解释@Component 有帮助,请做。

这是一个示例 class 我很想将 @Service 添加到其中,因为它根据从 @Controller classes 收集的信息为与 spring 无关的包准备文件运行业务逻辑

@Service
public class FileResourceManager {

    private ConfigProp configProp;

    @Autowired
    private FormModel formModel;

    public FileResourceManager(FormModel formModel) {
        this.formModel = formModel;
    }

    public FormModel getformModel() {
        return formModel;
    }

    public void init() throws IOException {
        System.out.println("Initializing resources...");
        clearDirectories();
        writeTextboxToInputDirectories();
        writeMultifileToInputDirectories();
    }

    private void clearDirectories() throws IOException {
        configProp = configProp.getInstance();
        RwUtils.clearDirectory(System.getProperty("user.dir")+configProp.getProperty("input.dir")+"input/");
        RwUtils.clearDirectory(System.getProperty("user.dir")+configProp.getProperty("input.dir")+"file/");
    }

    private void writeMultifileToInputDirectories() throws IOException {

        configProp = configProp.getInstance();
        String inputDir = System.getProperty("user.dir")+configProp.getProperty("input.dir")+"input/";
        String fileDir = System.getProperty("user.dir")+configProp.getProperty("input.dir")+"file/";

        RwUtils.writeMultipartIntoFile(fileDir,formModel.getFile1());
        RwUtils.writeMultipartIntoFile(fileDir,formModel.getFile2());
        RwUtils.writeMultipartIntoFile(fileDir,formModel.getFile3());

        for (MultipartFile record: formModel.getFiles4()) {
            RwUtils.writeMultipartIntoFile(inputDir,record);
        }
    }

    private void writeTextboxToInputDirectories() throws IOException {
        configProp = configProp.getInstance();
        String inputDir = System.getProperty("user.dir")+configProp.getProperty("input.dir")+"input/";
        String fileDir = System.getProperty("user.dir")+configProp.getProperty("input.dir")+"file/";

        if(formModel.getFile1File().isEmpty()) RwUtils.writeStringToFile(fileDir+"file1.txt",formModel.getFile1Text());
        if(formModel.getFile2File().isEmpty()) RwUtils.writeStringToFile(fileDir+"file2.txt",formModel.getFile2Text());
        if(formModel.getFile3File().isEmpty()) RwUtils.writeStringToFile(fileDir+"file3.txt",formModel.getFile3Text());

        int i = 1;
        String recordFileStr;
        for (String record:formModel.getOldJsonText().split(";;;")) {
            recordFileStr = inputDir+"textboxRecord"+i+".json";
            RwUtils.writeStringToFile(recordFileStr,record);
            i++;
        }
    }

    // this class calls logic from a package that has no relation to spring-boot framework
    public void runBusinessLogic() throws IOException, InvalidEntryException {

        // logic

    }

    public void download(ZipOutputStream zippedOut) throws IOException {
        ConfigProp configProp = ConfigProp.getInstance();
        String downloadFormat = getformModel().getDownloadFormat();
        FileSystemResource resource;
        ZipEntry zipEntry;
        File dir;

        for (String dirStr:downloadFormat.split("-")) {
            dir = new File(System.getProperty("user.dir")+configProp.getProperty("output.dir")+dirStr);
            for (File file:dir.listFiles()) {
                resource = new FileSystemResource(System.getProperty("user.dir")+configProp.getProperty("output.dir")+dirStr+"/"+file.getName());

                zipEntry = new ZipEntry(file.getName());
                // Configure the zip entry, the properties of the file
                zipEntry.setSize(resource.contentLength());
                zipEntry.setTime(System.currentTimeMillis());
                // etc.
                zippedOut.putNextEntry(zipEntry);
                // And the content of the resource:
                StreamUtils.copy(resource.getInputStream(), zippedOut);
                zippedOut.closeEntry();
            }
        }
        zippedOut.finish();
    }


    public static void main(String[] args) throws IOException {

        // used to test runBusinessLogic() method

    }

}

这是一个示例服务class,其中@Service 似乎很重要

@Service
public class MyUserDetailsService implements UserDetailsService {

    @Autowired
    private MyUserRepository repo;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        MyUser user = repo.findByUsername(username);
        if(user==null)
            throw new UsernameNotFoundException("Username not found");

        return new UserPrincipal(user);
    }

    public MyUser getUser(String username) throws UsernameNotFoundException {
        MyUser user = repo.findByUsername(username);
        if(user==null)
            throw new UsernameNotFoundException("Username not found");

        return user;
    }

    public MyUser createUser(MyUser user) {
        String email = user.getEmail();
        String username = user.getUsername();
        if(repo.existsUserByEmail(email)) {
            user = repo.findByEmail(email);
        } else  if(repo.existsUserByUsername(username)) {
            user = repo.findByUsername(username);
        } else {
            this.repo.save(user);
            user = repo.findByEmail(email);
        }
        return user;
    }
}

如果一个 java class 被注解 @Service , Spring 将管理它并且它可以享受 Spring 提供的好处,例如申请一些 AOP 魔术(例如那些 @Transactional@Async@PreAuthorize 等东西)。其他实例也可以使用 @Autowired 来访问它而不是 DIY(即依赖注入想法)。想一想,如果您的对象由许多依赖项组成,而这些依赖项又由许多依赖项组成,那么手动配置该实例以具有正确的依赖关系图可能不是一件令人愉快的事情。更不用说依赖对象应该来自正确的范围。

另一方面,如果 java class 不需要 Spring 提供的任何功能,也许它很简单或者只被一些 class 在内部,您可以保持简单并自己创建它,例如:

ResourceManager = new FileResourceManager(formModel);

所以这取决于您是否需要 class 上的 spring 功能。如果你不需要它,你可以保持简单不需要注释@Service就可以了。