Czech

Czech

biubiu

Framework Interview Questions - Reference Answers

Framework Interview Questions - Reference Answers#

Interviewer: Are singleton beans in the Spring framework thread-safe?#

Candidate:

Well!

They are not thread-safe. Here's why:

When multiple users simultaneously request a service, the container assigns a thread to each request. These multiple threads execute the business logic (member methods) corresponding to the request concurrently. If there are modifications to the singleton state in this processing logic (reflected in the member attributes of the singleton), thread synchronization must be considered.

The Spring framework does not provide any multi-threaded encapsulation for singleton beans. Developers need to handle the thread safety and concurrency issues of singleton beans themselves.

For example: The Spring beans we typically use in projects are immutable (such as Service classes and DAO classes), so to some extent, Spring's singleton beans are thread-safe.

If your bean has multiple states (such as View Model objects), you need to ensure thread safety yourself. The simplest solution is to change the role of the polymorphic bean from "singleton" to "prototype".

Interviewer: What is AOP?

Candidate:

AOP stands for Aspect-Oriented Programming. In Spring, it is used to extract common behaviors and logic that are unrelated to business but affect multiple objects, enabling their reuse and reducing coupling. For example, it can be used for common log saving and transaction processing.

Interviewer: Have you used AOP in your project?

Candidate:

In our backend management system, we used AOP to record system operation logs.

The main idea is to use the around advice and pointcut expression in AOP. The expression is used to find the methods to be logged. Then, the parameters of the around advice are used to obtain the parameters of the request method, such as class information, method information, annotations, request methods, etc. After obtaining these parameters, they are saved to the database.

Interviewer: How is transaction implemented in Spring?

Candidate:

The transaction implemented by Spring is essentially completed by AOP. It intercepts the methods before and after execution, opens the transaction before executing the method, and commits or rolls back the transaction based on the execution result after executing the target method.

Interviewer: What are the scenarios where transactions fail in Spring?

Candidate:

Well! I have encountered this before in a project. Let me think.

The first scenario is if the exception is caught and handled in the method and not thrown, it will cause the transaction to fail. So after handling the exception, don't forget to throw it.

The second scenario is if the method throws a checked exception, it will also cause the transaction to fail. In the Spring transaction annotation, set the rollbackFor attribute of @Transactional to Exception. This way, no matter what exception occurs, the transaction will be rolled back.

The third scenario is if the method is not public, it will also cause the transaction to fail.

Well, that's all I can think of.

Interviewer: What is the lifecycle of a Spring bean?

Candidate:

Well! There are quite a few steps involved in this process. I have read some source code before, and the general process is as follows:

First, the BeanDefinition, a very important class, is used to obtain the definition information of the bean. It encapsulates all the information of the bean, such as the full path of the class, whether it is lazy-loaded, whether it is a singleton, etc.

When creating a bean, the first step is to call the constructor to instantiate the bean.

The second step is dependency injection of the bean, such as injecting through set methods, which is similar to @Autowired used in normal development.

The third step is to process the Aware interface. If a bean implements the Aware interface, the methods will be overridden and executed.

The fourth step is the BeanPostProcessor, which is the preprocessor.

The fifth step is the initialization method, such as implementing the InitializingBean interface or defining the init-method tag or @PostConstruct.

The sixth step is to execute the BeanPostProcessor, mainly to enhance the bean. It is possible to generate proxy objects here.

The last step is to destroy the bean.

Interviewer: What is circular reference in Spring?

Candidate:

Well, let me explain.

Circular dependency means circular reference, which means that two or more beans hold each other, forming a closed loop. For example, A depends on B, and B depends on A.

Circular dependency is allowed to exist in Spring. The Spring framework solves most circular dependencies based on the three-level cache.

① First-level cache: Singleton pool, caching beans that have gone through the complete lifecycle and have been initialized. After the Session is flushed or closed, all caches in that Session will be cleared. By default, the first-level cache is enabled.

② Second-level cache: Caches early-stage bean objects (lifecycle not yet completed).

③ Third-level cache: Caches ObjectFactory, which represents the object factory used to create a specific object.

Interviewer: Do you know the specific resolution process?

Candidate:

First, the A object is instantiated, and at the same time, the ObjectFactory object is created and stored in the third-level cache singletonFactories.

Second, when A needs B during initialization, the creation logic of B is executed.

Third, after B is instantiated, the ObjectFactory object is also created and stored in the third-level cache singletonFactories.

Fourth, when B needs to inject A, an A object is generated from the ObjectFactory obtained from the third-level cache, and it is stored in the second-level cache. There are two possibilities here: one is a normal A object, and the other is a proxy object of A. The ObjectFactory can produce the corresponding object, which is the key to the third-level cache.

Fifth, after B obtains the A object from the second-level cache earlySingletonObjects, it can be injected normally. After B is created successfully, it is stored in the first-level cache singletonObjects.

Sixth, back to the initialization of the A object, because the B object has been created, A can be injected directly. After A is created successfully, it is stored in the first-level cache singletonObjects once again.

Seventh, the temporary object A in the second-level cache is cleared.

Interviewer: How to solve circular dependencies when they occur in constructors?

Candidate:

Since the constructor is the first to be executed in the bean lifecycle, the Spring framework cannot solve the dependency injection in the constructor. You can use @Lazy to delay the creation of the bean until it is needed.

Interviewer: Do you know the execution process of Spring MVC?

Candidate:

Yes, I know it. It can be divided into several steps.

  1. The user sends a request to the front controller DispatcherServlet, which is the dispatching center.

  2. DispatcherServlet receives the request and calls the HandlerMapping.

  3. HandlerMapping finds the specific handler (can be found in XML configuration or annotation configuration) and generates the handler object and handler interceptors (if any), and returns them to DispatcherServlet.

  4. DispatcherServlet calls the HandlerAdapter.

  5. The HandlerAdapter calls the specific handler (Handler/Controller) through adaptation.

  6. The controller completes the execution and returns a ModelAndView object.

  7. The HandlerAdapter returns the ModelAndView to DispatcherServlet.

  8. DispatcherServlet passes the ModelAndView to ViewResolver.

  9. ViewResolver resolves and returns the specific View.

  10. DispatcherServlet renders the view (fills the model data into the view).

  11. DispatcherServlet responds to the user.

Of course, nowadays, most development is based on front-end and back-end separation, and there are no views. Usually, the handler directly returns the result using Response.

Interviewer: What is the principle of Spring Boot's auto-configuration?

Candidate:

Well, it works like this.

In a Spring Boot project, the @SpringBootApplication annotation on the bootstrap class encapsulates three annotations:

  • @SpringBootConfiguration

  • @EnableAutoConfiguration

  • @ComponentScan

Among them, @EnableAutoConfiguration is the core annotation for automatic configuration. This annotation imports the corresponding configuration selector through @Import. The key is to read the fully qualified class names of the classes configured in the classpath of the project and the Jar packages referenced by the project from the META-INF/spring.factories file. The beans defined in these configuration classes will be imported into the Spring container based on the conditions specified by the conditional annotations.

Typically, conditional annotations like @ConditionalOnClass are used to determine whether the corresponding class file exists. If it does, the class is loaded and all the beans in this configuration class are put into the Spring container for use.

Interviewer: What are the common annotations in Spring?

Candidate:

Well, there are many of them.

The first category is for declaring beans, including @Component, @Service, @Repository, and @Controller.

The second category is for dependency injection, including @Autowired, @Qualifier, and @Resource.

The third category is for setting the scope, such as @Scope.

The fourth category is for Spring configuration, such as @Configuration, @ComponentScan, and @Bean.

The fifth category is for AOP-related enhancements, such as @Aspect, @Before, @After, @Around, and @Pointcut.

Interviewer: What are the common annotations in Spring MVC?

Candidate:

There are many of them as well.

There is @RequestMapping, which is used to map the request path.

@RequestBody: Used to receive JSON data from an HTTP request and convert it into a Java object.

@RequestParam: Specifies the name of the request parameter.

@PathVariable: Retrieves the request parameter from the request path (/user/{id}) and passes it to the method as a formal parameter.

@ResponseBody: Converts the return object of the controller method into a JSON object and responds to the client.

@RequestHeader: Retrieves the specified request header data, as well as annotations like @PostMapping and @GetMapping.

Interviewer: What are the common annotations in Spring Boot?

Candidate:

Well~~

The core annotation of Spring Boot is @SpringBootApplication, which encapsulates three annotations:

  • @SpringBootConfiguration: Combines the @Configuration annotation to implement the functionality of configuration files.
  • @EnableAutoConfiguration: Enables automatic configuration. You can also disable specific automatic configuration options.
  • @ComponentScan: Scans Spring components.

Interviewer: What is the execution process of MyBatis?

Candidate:

Okay, I know this, but there are also many steps.

① Read the MyBatis configuration file: mybatis-config.xml, which loads the runtime environment and mapping files.

② Construct the session factory SqlSessionFactory, which is a singleton. Typically, it is managed by Spring.

③ The session factory creates the SqlSession object, which contains all the methods for executing SQL statements.

④ The executor, which is responsible for database operations and query cache maintenance, is an interface.

⑤ The executor's execution method has a MappedStatement parameter, which encapsulates the mapping information.

⑥ Input parameter mapping.

⑦ Output result mapping.

Interviewer: Does MyBatis support lazy loading?

Candidate:

Yes, it does.

Lazy loading means that the data is loaded only when it is needed and not loaded when it is not needed.

MyBatis supports lazy loading of one-to-one associated objects and one-to-many associated collection objects.

In the MyBatis configuration file, you can configure whether to enable lazy loading (lazyLoadingEnabled=true|false). By default, it is disabled.

Interviewer: Do you know the underlying principle of lazy loading?

Candidate:

Well, let me think.

Lazy loading is mainly implemented using CGLIB dynamic proxies.

First, a proxy object of the target object (the mapper with lazy loading enabled) is created using CGLIB.

Second, when the target method is called, it enters the interceptor's invoke method. If the target method is null, an SQL query is executed.

Third, after obtaining the data, the set method is called to set the attribute value, and then the target method is queried again, which now has a value.

Interviewer: Have you used the first-level and second-level caches in MyBatis?

Candidate:

Yes, I have used them.

The first-level cache of MyBatis is a local cache based on PerpetualCache and HashMap. Its scope is the session. When the session is flushed or closed, all caches in that session will be cleared. By default, the first-level cache is enabled.

The second-level cache needs to be enabled separately.

The second-level cache is based on the namespace and mapper scope. It does not depend on the SQL session. By default, it also uses PerpetualCache and HashMap for storage.

If you want to enable the second-level cache, you need to configure it in the global configuration file and the mapping file.

Interviewer: When will the data in the cache be cleared in MyBatis's second-level cache?

Candidate:

Well!

When there is an insert, update, or delete operation in a scope (first-level cache session/second-level cache namespaces), all the caches in that scope will be cleared by default.

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.