以下选项(@ Service,@ Bean或静态方法)之间有什么区别?

时间:2019-02-01 15:57:04

标签: java spring-boot

我对Spring启动有一个一般的编码问题。 假设您有一个控制器,当用户转到某个页面时,我们从数据库中读取了一些数据,我们使用该数据执行了一些业务逻辑,并根据业务逻辑转到了另一个页面。我可以通过3种方式对此进行编程。问题是,哪种方法最好,为什么呢?这样,我试图理解不同的选项。可能还有其他选择,因此,如果您有更好的建议,请告诉我。 另一个问题是,您总是在Spring中创建bean /组件,还是有时用Java方式编写类?

选项1:静态方法 我从控制器类中的数据库读取数据,在另一个类中,我在静态方法中执行一些业务逻辑,然后返回新字符串。 看起来像这样:

控制器类:

@Controller
public class TestController {

    private final RouteRepository routeRepository;

    @Autowired
    public TestController (RouteRepository routeRepository) {
        this.routeRepository = routeRepository;
    }

    @GetMapping("/test")
    public String getTestController() {
        List<Route> route= routeRepository.findAll();
        String total= Test.testMethod(route);
        return total;
    }
}

业务逻辑类:

public class Test {

    public static String testMethod(List<Route> route) {
        // do some business logic
        return "index";
    }
}

选项2: 我在@Service类中读取数据,在同一类中执行业务逻辑。在我的控制器类中,我为服务类自动接线,并在@Service类中调用了一个方法:

控制器类:

@Controller
public class TestController {

    private final Test test;

    @Autowired
    public TestController (Test test) {
        this.test = test;
    }

    @GetMapping("/test")
    public String getTestController() {
        String total= test.testMethod();
        return total;
    }
}

业务逻辑类:

@Service
public class Test {

    private final RouteRepository routeRepository;

    @Autowired
    public Test (RouteRepository routeRepository) {
        this.routeRepository = routeRepository;
    }

    public String testMethod() {
        List<Route> route= routeRepository.findAll();
        // do some business logic
        return "index";
    }
}

选项3: 或者我和option1一样,但是使用@Bean

控制器类:

@Controller
public class TestController {

    ApplicationContext context = new AnnotationConfigApplicationContext(ConfigAll.class);
    Test test = context.getBean(Test.class);

    private final RouteRepository routeRepository;

    @Autowired
    public TestController (RouteRepository routeRepository) {
        this.routeRepository = routeRepository;
    }

    @GetMapping("/test")
    public String getTestController() {
        List<Route> routes = routeRepository.findAll();
        String total= test.testMethod(routes);
        return total;
    }
}

业务逻辑:

@Service
public class Test {
    public String testMethod(List<Route> routes) {
        // do some business logic
        return "index";
    }
} 

配置类:

@Configuration
public class ConfigAll {

    @Bean
    public Test getAddress() {
        return new Test();
    }
}  

2 个答案:

答案 0 :(得分:0)

使用选项2,但是您不会返回“索引”,而是自己返回实际的Routes

内幕中,@Controller@Service@Repository都是bean,它们不同的一个原因是允许Spring Boot实现“ {{3}”的思想。 }”。这使您可以单独测试应用程序的特定部分。

例如,如果您有RouteService,则可以完全模拟该服务以返回Route,而无需连接到数据库,然后将其直接传递到表示层,例如一个Thymeleaf模板,并使用@WebMvcTest对其进行测试。您的表示/ HTTP层应尽可能简单,并且不包含逻辑。逻辑属于@Service

通过使用@Service,您还可以受益于@Transactional之类的注释,该注释可以在出现问题时自动回滚工作单元。在选项1中,您仅从存储库中读取了所有路由,但是想像一下是否还需要更新某些内容,并且您的静态方法抛出了一个例外:系统不会回滚更新,因为它已经被提交

根据经验,请勿使用静态方法,除非它们是库函数的一部分,例如base64编码器,可以完全隔离对其进行测试。静态方法的使用使您的系统难以测试,因为您无法轻松地模拟它们。

使用选项3没有任何好处,因为组件扫描和注释应使手动配置变得不必要。

答案 1 :(得分:0)

由于您的服务类应该处理业务逻辑,因此我建议您使用以下微服务(如设计):

TestController.java

@RestController
@RequestMapping(path= "test-api")
public call TestController.java
    private final TestService testService;

    public TestController(TestService testService) {
        this.testService = testService;
    }

    @GetMapping(produces= "application/json")
    public ResponseEntity<?> getTestController() {
            List<Route> routeList = testService.findAllRoutes();

            return ResponseEntity.ok(routeList);
    }
}

TestService.java

@Service
public class TestService {
    private final TestDAO testRespository;

    public TestService(TestRespository testRepository) {
        this.testRepository = testRepository;
    }

    public List<Route> findAllRoutes() {
        return testRepository.findAllRoutes();
    }
}

TestDAO.java

public interface TestDAO {
    List<Route> findAllRoutes();
}

TestDAOImpl.java

@Repository
public class TestDAOImpl implements TestDAO {
    private static final String FIND_QUERY = <insert query here>;

    @Override
    public List<Route> findAllRoutes() {
        // Use query and return the list
    }
} 

请注意,您将在其构造函数中初始化控制器类和服务类的依赖关系。这是由于这样的事实,它会使事情更容易为你嘲笑这些对象时,它使用的Mockito,谈到时间,测试等,现在,当它涉及到以下问题:

  

假设您有一个控制器,当用户转到某个页面时,   我们从数据库中读取一些数据,并使用该数据进行一些业务逻辑   并根据业务逻辑转到另一个页面

由于您要从数据库返回“路由”列表,因此从技术上讲,您可以处理路由列表,并且仅在ResponseEntity中返回一条路由,以供客户端使用并最终重定向。

另一种选择是将路由列表返回到客户端,然后让客户端的业务逻辑根据您提供给它的路由来处理自己的重定向。