Một số câu hỏi về Spring, Spring Boot được nhà tuyển dụng lựa chọn

Spring và Spring Boot có lẽ là những framework mạnh mẽ nhất của Java ở thời điểm hiện tại dùng để xây dựng các ứng dụng chạy ở phía server (backend). Nếu các bạn là các Java dev đang trên con đường chinh phục 2 framework và tìm cho mình một công việc tốt thì chắc hẳn những câu phỏng vấn sau đây sẽ giúp bạn nhìn nhận lại bản thân một chút về kiến thức của mình.

Đây là những câu hỏi mình được hỏi khi tham gia buổi phỏng vấn từ một số công ty (mình xin không công khai danh tính các công ty) mà mình thấy rất hay có thể giúp mình nhìn ra những thiếu xót trong kiến thức của bản thân.

Một lưu ý nữa là mình không hoàn toàn trả lời được những câu hỏi phỏng vấn này, nên mình chỉ nói ý mình trả lời khi tham gia phỏng vấn. Các bạn có bổ sung góp ý thì comment bên dưới để mọi người cùng tham khảo nhé.

Spring với Spring Boot khác nhau

Đây có lẽ là một câu tốt để bắt đầu buổi pv về Spring, Spring Boot mà nếu như bạn trả lời không được thì khả năng rớt là 80% nhé. Nhà tuyển dụng sẽ đánh giá các bạn làm việc như một con robot, cứ copy paste của người khác miễn sao chạy là ok.

Gợi ý:

  • Spring Boot chỉ là một phần mở rộng của spring cung cấp cho chúng ta các công cụ và cấu hình mặc định để có thể start ứng dụng một cách nhanh chóng. Còn về cơ bản Spring Boot cũng base trên Spring.
  • Ví dụ Spring Boot mặc định nhúng sẵn Apache Tomcat vào để project của chúng ta có thể chạy trên đó mà không cần phải cấu hình thêm tomcat trên máy. Hay các gói starter của spring boot cung cấp các cấu hình mặc định, quản lý version giúp chúng ta có thể bắt đầu sử dụng các lib một cách nhanh chóng chỉ với một vài bước cấu hình bắt buộc.

Có bao nhiêu bean scope trong Spring

Phần gợi ý:

Spring định nghĩa 6 kiểu Scope như sau:

  • singleton
  • prototype
  • request
  • session
  • application
  • websocket

Mình biết chắc là đa số chúng ta nhiều khi còn không để ý hoặc nếu siêng lắm thì chỉ nhớ 2 thằng đầu singleon và prototype. Nên hãy nhanh chóng kể 6 cái tên trên và bảo “thông thường em chỉ dùng 2 thằng singleton và prototype thôi ạ”

Sau khi nói được tính chất của singleton và prototype  scope thì nhà tuyển dụng sẽ hỏi thêm một số câu mở rộng.

Singleton scope thì bean sẽ được khởi tạo lúc nào?

Hãy tỏ ra mình là một người thông thái và hãy nhăc đến Lazy trong spring, nếu dùng Lazy thì nó sẽ khởi tạo tại lần đầu tiên được sử dụng. Còn không thì sẽ được khởi tạo tại thời điểm khởi chạy ứng dụng.

Prototype scrope thì bean sẽ được khởi tạo lúc nào?

Một bean với prototype scope sẽ trả về các instance khác nhau mỗi khi có một yêu mới sử dụng chúng đến IoC container.

Có bao nhiêu cách định nghĩa bean?

Trong spring để định nghĩa bean chúng ta có thể sử dụng @Component, @Service, @Repository, @Bean để định nghĩa bean. Tuy nhiên nhà tuyển dụng có thể hỏi thêm

@Bean và @Component được sử dụng trong những trường hợp cụ thể nào?

@Bean mình thường dùng để định nghĩa bean đối với các class từ thư viện bên thứ 3. Ví dụ gần đây mình có viết sample sử dụng API của google để lấy đoạn subtitle của một video bất kỳ. Trong đấy mình sử dụng lib của google cung cấp để gửi request đến Google Cloud.

SpeechClient class là một class mình cần dùng để gửi audio lên APi và nhận về đoạn text subtitle của audio. Do đó mình đã định nghĩa SpeechClient với @Bean annotation bên trong configuration class.

Configuration
public class SpeechToTextAPIConfig {


    @Autowired
    private GoogleCloudEnv googleCloudEnv;

    @Bean
    public GoogleCredentials googleCredentials() throws IOException {

        return GoogleCredentials.fromStream(new FileInputStream(googleCloudEnv.getKeyPath()))
                .createScoped(Lists.newArrayList("https://www.googleapis.com/auth/cloud-platform"));
    }

    @Bean
    public SpeechClient speechClient() throws IOException {
        return SpeechClient.create(SpeechSettings.newBuilder()
                .setCredentialsProvider(() -> googleCredentials()).build());
    }

    @Bean
    public Storage storage() throws IOException {
        return StorageOptions.newBuilder()
                .setProjectId(googleCloudEnv.getProjectId())
                .setCredentials(googleCredentials()).build().getService();
    }

    @Bean
    public TranslationServiceClient translationServiceClient() throws IOException {
        return TranslationServiceClient.create(TranslationServiceSettings.newBuilder()
                .setCredentialsProvider(() -> googleCredentials())
                .build());
    }
}

@Component thì thường dùng đối với các class do mình tự định nghĩa ví dụ JwtTokenUtil dùng để triển khai các hàm liên quan đến JWT như sinh token mới, decode token v.v

@Component
@Log4j2
public class JwtTokenUtil implements Serializable {...}

Ngoài ra nhà tuyển dụng sẽ hỏi thêm 

Phân biệt giữa @Service, @Component và @Repository

Các bạn cần lưu ý là @Service và @Repositoty bản thân bên trong nó đã được chú thích với @Component nên một điểm chung là chúng đều được dùng để tạo bean.

Tuy nhiên @Service còn được dùng với mục đích phân loại bean thuộc dạng Service trong ứng dụng, nên các bạn hoàn toàn có thể thay thế @Service bằng @Component mà không gặp bất kỳ vấn đề gì.

Tuy nhiên @Repositoty ngoài việc phân loại bean là các Repo thì nó còn có một công dụng đặc biệt trong Spring Data (mình chỉ biết đến đây thôi). Nên chúng ta không thể thay thế @Repositoty bằng @Component đâu nhé (Nhà tuyển dụng gài chỗ này, bạn ok cái coi như bạn đang nói điêu đấy nhé).

Nếu có nhiều bean có cùng type (cùng implement interface) thì làm thế nào để sử dụng một bean cụ thể

Đối với câu này chúng ta có nhiều cách để trả lời. Đối với mình thì mình sẽ sử dụng @Quatifier để chỉ định tên của bean cụ thể cần dùng. Ngoài ra có thể sử dụng @Primary annotation để chỉ định bean mặc định trong trường hợp không dùng @Quatifier để chỉ định bean cụ thể thì @Primary bean sẽ được sử dụng.

Hỏi về Spring data transaction

Giả sử mình có một Service A chứa method A được chú thích với @Transactional annotation. Trong method A ghi log xuống database, gọi đến methodB của Service B.

Class ServiceA {
   @Autowire
   private ServiceB b;
   @Transactional
   pubic void methodA() {
      // write log to db
      b.methodB();
      // do something to db
   }
}

ServiceB chứa method B cũng chứa đoạn mã thao tác xuống database.

Class ServiceB {
   @Transactional
   pubic void methodB() {
      // do something to db
   }
}

Câu hỏi nếu từ controller mình gọi đến methodA() thì sẽ có bao nhiêu transaction tồn tại trong quá trình này.

Câu trả lời chỉ là 1, vì trong @Transactional chứa thuộc tính Propagation mặc định có giá trị là Propagation.REQUIRED. Gía trị này chỉ ra rằng nếu một method được chú thích với @Transactional (propagation = Propagation.REQUIRED) thì nếu nơi gọi chưa có transaction nào tồn tại thì một transaction mới sẽ được khởi tạo, nếu đã có rồi thì nó sẽ sử dụng lại.

Vì vậy trong trường hợp này nếu một transaction mới sẽ được khởi tạo tại thời điểm controller gọi đến methdoA, methodB sẽ sử dụng chung transaction này.

Nhà tuyển dụng lại hỏi tiếp,

Nếu methodB() thực thi gây ra một exception thì chuyện gì sẽ xảy ra?

Thì transaction sẽ bị rollback, mà tại đây methodA và methodB đều sử dụng chung transaction nên tất cả những gì methodA và methodB thực thi đều bị rollback.

Nhà tuyển dụng lại tiếp tục hỏi

Vậy nếu anh muốn khi methodB gây exception anh không muốn những gì thực thi bên methodA bị rollback theo thì làm như thế nào?

Ok, mình sẽ đặt methodB lại như sau

Class ServiceB {
   @Transactional(propagation =  REQUIRES_NEW)
   pubic void methodB() {
      // do something to db
   }
}

Như vậy methodB sẽ mở một transaction con trong transaction của methodA. Tại methodA mình sẽ try-catch để xử lý lỗi khi B ném ra

Class ServiceA {
   @Autowire
   private ServiceB b;
   @Transactional
   pubic void methodA() {
      // write log to db
      try {
         b.methodB();
      } catch (Exception e) {
       // log something 
      }
      // do something to db
   }
}

Nếu có 3 bean của một interface, trên 3môi trường khác nhau thì sử dụng mỗi bean tương ứng thì làm thế nào?

Câu này mình trả lời được ngay là sử dụng spring profile cho phép active mỗi bean tương ứng trên mỗi môi trường khác nhau. 

Tuy nhiên nhà tuyển dụng lại hỏi thêm

Nếu code đã được đóng gói rồi và mình không thể build lại thì làm thế nào?

Thực sự là mình không biết dùng cách nào luôn, ai biết giúp mình câu này với nhé.

Tóm lược

Ở trên đều là câu trả lời theo kiến thức của mình thì có thể sai nên các bạn chỉ tham khảo thôi nhé. Có sai gì thì các bạn cứ feedback cho mình để chúng ta có thể chinh chiến với các cuộc phỏng vấn tiếp theo tốt hơn.

4 5 votes
Article Rating
Subscribe
Notify of
guest
3 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments
3
0
Would love your thoughts, please comment.x
()
x