After preparing eight-legged essays for a month, and after more than 20 interviews, I found that Spring is very popular with interviewers. Recently, I have summarized Spring's common interview questions when I have time. I hope it will be helpful to everyone.
Article Directory:
- Advantages of Spring
- What design patterns does Spring use?
- What is AOP?
- What are the ways to implement AOP?
- What is the difference between JDK dynamic proxy and CGLIB dynamic proxy?
- Spring AOP related terms
- What are the types of Spring notifications?
- What is IOC?
- What are the advantages of IOC?
- What is dependency injection?
- IOC container initialization process?
- Bean's life cycle
- What is the difference between BeanFactory and FactoryBean?
- What are the ways to inject Bean into the container?
- Bean scope
- What are the ways to automate Spring?
- What is the difference between @Autowired and @Resource?
- What does the @Qualifier annotation do
- What is the difference between @Bean and @Component?
- What is the difference between @Component, @Controller, @Repositor and @Service?
- What are the Spring transaction implementation methods?
- What kind of transaction spread behavior?
- How does Spring solve the problem of circular dependencies?
- Spring startup process
- Does Spring's singleton bean have thread safety issues?
Advantages of Spring
- Lightweight , the basic version is about 2MB.
- loosely coupled to through inversion of control and dependency injection.
- Supports aspect-oriented , and separates application business logic from system services.
- Reduce boilerplate code through aspects and templates.
- Facilitate the integration of various excellent frameworks. Direct support for various excellent frameworks (such as Hibernate, MyBatis, etc.) is provided internally.
- It is convenient to test the program. Spring supports Junit4, and you can test Spring programs by adding annotations.
What design patterns does Spring use?
1. Simple factory mode: BeanFactory
is the embodiment of the simple factory mode. Bean objects are obtained according to a unique identifier passed in.
@Override
public Object getBean(String name) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(name);
}
2. Factory method mode: FactoryBean
is a typical factory method mode. When spring uses the getBean()
call to obtain the bean, it will automatically call the bean's getObject()
method. Each Bean corresponds to a FactoryBean
, such as SqlSessionFactory
corresponds to SqlSessionFactoryBean
.
3. Singleton mode: A class has only one instance, providing a global access point to access it. Spring creates a Bean instance by default as a singleton.
4. Adapter mode: the adapter HandlerAdatper
SpringMVC. Since the application will have multiple Controller implementations, if you need to call the Controller method directly, you need to first determine which Controller handles the request, and then call the corresponding method. When adding a new Controller, the original logic needs to be modified, which violates the opening and closing principle (closed for modification, open for extension).
To this end, Spring provides an adapter interface, each corresponding to one kind Controller HandlerAdapter
implementation class, when the request came, SPRINGMVC calls getHandler()
obtain the corresponding Controller, the Controller then obtains the corresponding HandlerAdapter
, the last call HandlerAdapter
the handle()
method for processing requests , Actually calling handleRequest()
of Controller. Every time you add a new Controller, you only need to add an adapter class, without modifying the original logic.
Commonly used processor adapters: SimpleControllerHandlerAdapter
, HttpRequestHandlerAdapter
, AnnotationMethodHandlerAdapter
.
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
public class HttpRequestHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {//handler是被适配的对象,这里使用的是对象的适配器模式
return (handler instanceof HttpRequestHandler);
}
@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
((HttpRequestHandler) handler).handleRequest(request, response);
return null;
}
}
5. Proxy mode: Spring's aop uses dynamic proxy. There are two ways: JdkDynamicAopProxy
and Cglib2AopProxy
.
6. Observer mode: The commonly used observer mode in spring is the implementation of listener, such as ApplicationListener
.
7. Template mode: In Spring jdbcTemplate
, hibernateTemplate
etc., template mode is used.
What is AOP?
Aspect-oriented programming, as a supplement to object-oriented, encapsulates common logic (transaction management, log, cache, etc.) into aspects and separates it from business code, which can reduce system duplication of code and reduce the coupling between modules. Aspects are those common logic that has nothing to do with the business, but all business modules will call.
What are the ways to implement AOP?
There are two ways to implement AOP: static proxy and dynamic proxy.
static proxy
Static proxy: The proxy class is generated during the compilation phase, and the notification is woven into the Java bytecode during the compilation phase, which is also called compile-time enhancement. AspectJ uses a static proxy.
Disadvantages: The proxy object needs to implement the same interface as the target object, and the method to implement the interface will have redundant code. At the same time, once methods are added to the interface, both the target object and the proxy object must be maintained.
dynamic proxy
Dynamic proxy: The proxy class is created when the program is running. The AOP framework does not modify the bytecode, but temporarily generates a proxy object in the memory. The business method is enhanced during the run, and no new class is generated.
What is the difference between JDK dynamic proxy and CGLIB dynamic proxy?
There are two main ways of dynamic proxy in Spring AOP: JDK dynamic proxy and CGLIB dynamic proxy.
JDK dynamic proxy
If the target class implements the interface, Spring AOP will choose to use the JDK dynamic proxy target class. The proxy class is dynamically generated based on the interface implemented by the target class, and there is no need to write it yourself. The generated dynamic proxy class and the target class implement the same interface. The core of the JDK dynamic proxy is the InvocationHandler
interface and the Proxy
class.
Disadvantages: The target class must have an implemented interface. If a certain class does not implement the interface, then this class cannot use JDK dynamic proxy.
CGLIB to dynamically proxy
Realized through inheritance. If the target class does not implement the interface, Spring AOP will choose to use CGLIB to dynamically proxy the target class. CGLIB (Code Generation Library) can dynamically generate the bytecode of the class at runtime, dynamically create the subclass object of the target class, and enhance the target class in the subclass object.
CGLIB is a dynamic proxy through inheritance, so if a class is marked as final
, then it cannot use CGLIB as a dynamic proxy.
Advantages: The target class does not need to implement a specific interface, which is more flexible.
When to use which dynamic proxy?
- If the target object implements the interface, the dynamic proxy of the JDK will be used to implement AOP by default
- If the target object implements the interface, you can force the use of CGLIB to implement AOP
- If the target object does not implement the interface, the CGLIB library must be used
The difference between the two :
- The jdk dynamic proxy uses the class Proxy in jdk to create proxy objects. It uses reflection technology to implement it and does not need to import other dependencies. Cglib needs to introduce related dependencies: asm.jar, which uses bytecode enhancement technology to achieve.
- When the target class implements the interface, Spring Aop uses the jdk dynamic proxy method to enhance the method by default, and uses the cglib dynamic proxy method to enhance the method when the interface is not implemented.
Spring AOP related terms
(1) Aspect: Aspect is a combination of notice and point of contact. The notice and the point of contact together define the entire content of the aspect.
(2) Join point: refers to a method. In Spring AOP, a join point always represents the execution of a method. A connection point is a point that can be inserted into the aspect during application execution. This point can be when a method is called, when an exception is thrown, or even when a field is modified. The aspect code can use these points to insert into the normal flow of the application and add new behaviors.
(3) Advice: In AOP terminology, aspect work is called advice.
(4) Pointcut: The definition of the pointcut will match the one or more connection points to be woven into the notification. We usually use explicit class and method names, or use regular expressions to define matching class and method names to specify these pointcuts.
(5) Introduction: Introduction allows us to add new methods or properties to existing classes.
(6) Target Object: An object that is advised by one or more aspects. It is usually a proxy object.
(7) Weaving: Weaving is the process of applying aspects to target objects and creating new proxy objects. There are the following points in the life cycle of the target object that can be woven:
- Compile time: Aspects are woven into when the target class is compiled. AspectJ's weaving compiler weaves aspects in this way.
- Class loading period: The aspect is woven when the target class is loaded into the JVM. A special class loader is required, which can enhance the bytecode of the target class before it is introduced into the application. AspectJ5's load-time weaving supports weaving aspects in this way.
- Runtime: The aspect is woven in at some point during the running of the application. Under normal circumstances, when weaving aspects, the AOP container dynamically creates a proxy object for the target object. SpringAOP is woven into aspects in this way.
What are the types of Spring notifications?
In AOP terminology, aspect work is called notification. Notification is actually a code segment to be triggered by the Spring AOP framework when the program is running.
There are 5 types of notifications that can be applied to the Spring aspect:
- Before notification (Before): Call the notification function before the target method is called;
- After notification (After): The notification is called after the target method is completed, and you don't care about the output of the method at this time;
- After-returning: the notification is called after the target method is successfully executed;
- Exception notification (After-throwing): call notification after the target method throws an exception;
- Around notification (Around): The notification wraps the notified method, and executes custom logic before and after the notified method is called.
What is IOC?
IOC: Inversion of control, the entire life cycle of the bean is managed by the Spring container. Through reflection to achieve control of other objects, including initialization, creation, destruction, etc., to liberate the process of manually creating objects, while reducing the coupling between classes.
The benefits of IOC: reduce the coupling between classes, object creation and initialization are handed over to the Spring container to manage, and only need to apply to the container when needed.
What are the advantages of IOC?
- IOC and dependency injection reduce the amount of code in the application.
- Loosely coupled.
- Supports hungry Chinese-style initialization and lazy loading when loading services.
What is dependency injection?
In the process of creating an object in Spring, the attributes that the object depends on are injected into the object. There are two main ways of dependency injection: constructor injection and attribute injection.
IOC container initialization process?
The initialization process of the ioc container: resource location, analysis and registration of BeanDefinition.
- Read the configuration file from XML.
- Parse the bean tag into BeanDefinition, such as parsing the property element, and inject it into the BeanDefinition instance.
- Register the BeanDefinition in the container BeanDefinitionMap.
- BeanFactory creates instantiated and initialized beans based on the definition information of BeanDefinition.
The initialization and dependency injection of singleton beans are generally carried out in the container initialization stage. Only lazy-loaded (lazy-init is true) singleton beans are initialized and dependency injected when the application calls getBean() for the first time.
// AbstractApplicationContext
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
Many beans are not instantiated when the container is started. Even if lazy-init is set to false, it is useless. The instantiation is performed only when getBean() is called.
loadBeanDefinitions
adopts the template mode, and the specific BeanDefinition
is completed by each subclass.
Bean's life cycle
1. Instantiate the Bean
2. Dependency injection
3. If the Bean implements BeanNameAware
interfaces, Spring will call setBeanName
(), set Bean
the above mentioned id's (id xml file bean labels)
4. If the Bean implements the BeanFactoryAware
interface, Spring will call setBeanFactory()
5. If the Bean implements the ApplicationContextAware
interface, the Spring container will call setApplicationContext()
6. If BeanPostProcessor
exists, Spring will call their postProcessBeforeInitialization
(pre-initialization) method to process it before the Bean is initialized
7. If the Bean implements the InitializingBean
interface, Spring will call its afterPropertiesSet
method, and then call the init-method method defined by xml. The two methods have similar functions and are executed when the bean is initialized.
8. If BeanPostProcessor
exists, Spring will call their postProcessAfterInitialization
(post-initialization) method to process it after the Bean is initialized
9. Bean initialization is complete, application use, until the application is destroyed
10. If the Bean implements the DisposableBean
interface, Spring will call its destory
method, and then call the destory-method
method defined in xml. These two methods have similar functions and are executed before the Bean instance is destroyed.
public interface BeanPostProcessor {
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
What is the difference between BeanFactory and FactoryBean?
BeanFactory: A container that manages Beans. Beans generated in Spring are managed by the implementation of this interface.
FactoryBean: Usually used to create more complex beans, general beans can be configured directly with xml, but if a bean creation process involves many other beans and complex logic, it is more troublesome to configure directly with xml. You can consider using FactoryBean, which can hide the details of instantiating complex Beans.
When the implementation class of the class attribute configuration of the bean tag in the configuration file is FactoryBean, what is returned by the getBean() method is not the FactoryBean itself, but the object returned by calling the FactoryBean#getObject() method, which is equivalent to FactoryBean#getObject() proxy The getBean() method. If you want to get the FactoryBean, you must use'&' + beanName to get it.
Mybatis provides SqlSessionFactoryBean, which can simplify the configuration of SqlSessionFactory:
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
@Override
public void afterPropertiesSet() throws Exception {
notNull(dataSource, "Property 'dataSource' is required");
notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
state((configuration == null && configLocation == null) || !(configuration != null && configLocation != null),
"Property 'configuration' and 'configLocation' can not specified with together");
this.sqlSessionFactory = buildSqlSessionFactory();
}
protected SqlSessionFactory buildSqlSessionFactory() throws IOException {
//复杂逻辑
}
@Override
public SqlSessionFactory getObject() throws Exception {
if (this.sqlSessionFactory == null) {
afterPropertiesSet();
}
return this.sqlSessionFactory;
}
}
Configure SqlSessionFactoryBean in xml:
<bean id="tradeSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="trade" />
<property name="mapperLocations" value="classpath*:mapper/trade/*Mapper.xml" />
<property name="configLocation" value="classpath:mybatis-config.xml" />
<property name="typeAliasesPackage" value="com.bytebeats.mybatis3.domain.trade" />
</bean>
SqlSessionFactory
when the application starts, and store it sqlSessionFactory
What are the ways to inject Bean into the container?
The common classes are handed over to the Spring container for management, usually in the following ways:
1. Use @Configuration
and @Bean
annotations
2. Use @Controller
, @Service
, @Repository
, @Component
annotations to mark this category, and then enable @ComponentScan
automatic scanning
3. Use the @Import
method. Use the @Import annotation to import the bean into the current container, the code is as follows:
//@SpringBootApplication
@ComponentScan
/*把用到的资源导入到当前容器中*/
@Import({Dog.class, Cat.class})
public class App {
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext context = SpringApplication.run(App.class, args);
System.out.println(context.getBean(Dog.class));
System.out.println(context.getBean(Cat.class));
context.close();
}
}
Bean scope
1. Singleton: Singleton, beans in Spring are singleton by default.
2. Prototype: Each request will create a new bean instance.
3. Request: Each HTTP request will generate a new bean, which is only valid in the current HTTP request.
4. Session: Every HTTP request will generate a new bean, which is only valid in the current HTTP session.
5. Global-session: global session scope.
What are the ways to automate Spring?
Spring's automatic assembly has three modes: byType (according to the type), byName (according to the name), and constructor (according to the constructor).
byType
Find a bean of the same dependency type and inject it into another bean. This process needs to be completed with the help of setter injection, so there must be a set method, otherwise the injection fails.
When there are multiple instance beans of the same type and different names in the xml file, the Spring container dependency injection will still fail. Because there are multiple suitable options, the Spring container cannot know which to inject. At this time, we need to provide help for the Spring container. , Specify which Bean instance is injected. You can filter the instance beans that do not need to be injected by setting the autowire-candidate of the <bean> tag to false
<bean id="userDao" class="com.zejian.spring.springIoc.dao.impl.UserDaoImpl" />
<!-- autowire-candidate="false" 过滤该类型 -->
<bean id="userDao2" autowire-candidate="false" class="com.zejian.spring.springIoc.dao.impl.UserDaoImpl" />
<!-- byType 根据类型自动装配userDao-->
<bean id="userService" autowire="byType" class="com.zejian.spring.springIoc.service.impl.UserServiceImpl" />
byName
Match the attribute name with the bean name, and if found, inject the dependent bean.
<bean id="userDao" class="com.zejian.spring.springIoc.dao.impl.UserDaoImpl" />
<bean id="userDao2" class="com.zejian.spring.springIoc.dao.impl.UserDaoImpl" />
<!-- byName 根据名称自动装配,找到UserServiceImpl名为 userDao属性并注入-->
<bean id="userService" autowire="byName" class="com.zejian.spring.springIoc.service.impl.UserServiceImpl" />
constructor
If there is a single instance, the parameters will be matched by type first (regardless of whether the name matches). When there are multiple instances of the same type, the name will be matched first. If the corresponding name is not found, the injection will fail. In this case, you can use autowire-candidate=" false" filter to solve.
<!--只存在userDao2,userDao3 无法成功注入-->
<bean id="userDao2" class="com.zejian.spring.springIoc.dao.impl.UserDaoImpl" />
<bean id="userDao3" class="com.zejian.spring.springIoc.dao.impl.UserDaoImpl" />
<bean id="userService" autowire="constructor" class="com.zejian.spring.springIoc.service.impl.UserServiceImpl" />
@Autowired can pass a required=false attribute, false indicates that when the userDao instance exists, it will be ignored if the injection does not exist. If it is true, it must be injected. If the userDao instance does not exist, an exception will be thrown. Since @Autowired is matched by type (byType) by default, if you need to match by name (byName), you can use the @Qualifier annotation combined with @Autowired.
public class UserServiceImpl implements UserService {
//标注成员变量
@Autowired
@Qualifier("userDao1")
private UserDao userDao;
}
ByName mode xml configuration:
<!-- 根据@Qualifier("userDao1")自动识别 -->
<bean id="userDao1" class="com.zejian.spring.springIoc.dao.impl.UserDaoImpl" />
<bean id="userDao2" class="com.zejian.spring.springIoc.dao.impl.UserDaoImpl" />
<bean id="userService" class="com.zejian.spring.springIoc.service.impl.UserServiceImpl" />
@Resource, automatically injected in byName mode by default. @Resource has two important attributes: name and type. The Spring container resolves the name attribute of the @Resource annotation to the name of the bean, and the type attribute resolves to the type of the bean. Therefore, if the name attribute is used, the automatic injection strategy according to the byName mode is used, and if the type attribute is used, the automatic injection strategy according to the byType mode is used. If neither the name nor the type attribute is specified, the Spring container will inject in the byName mode by default through reflection technology.
@Resource(name=“userDao”)
private UserDao userDao;//用于成员变量
//也可以用于set方法标注
@Resource(name=“userDao”)
public void setUserDao(UserDao userDao) {
this.userDao= userDao;
}
The above two types of auto-assembly dependency injection are not suitable for simple value types, such as int, boolean, long, String, and Enum. For these types, the Spring container also provides @Value injection. @Value receives a String value, which specifies the value to be injected into the built-in java type attribute, and the Spring container will do the type conversion. In general, @Value will be used in conjunction with the properties file.
The jdbc.properties file is as follows:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/test?characterEncoding=UTF-8&allowMultiQueries=true
jdbc.username=root
jdbc.password=root
Use the annotation @Value to get the values of jdbc.url and jdbc.username, the implementation is as follows:
public class UserServiceImpl implements UserService {
//占位符方式
@Value("${jdbc.url}")
private String url;
//SpEL表达方式,其中代表xml配置文件中的id值configProperties
@Value("#{configProperties['jdbc.username']}")
private String userName;
}
xml configuration file:
<!--基于占位符方式 配置单个properties -->
<!--<context:property-placeholder location="conf/jdbc.properties"/>-->
<!--基于占位符方式 配置多个properties -->
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer">
<property name="location" value="conf/jdbc.properties"/>
</bean>
<!--基于SpEL表达式 配置多个properties id值为configProperties 提供java代码中使用 -->
<bean id="configProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="locations">
<list>
<value>classpath:/conf/jdbc.properties</value>
</list>
</property>
</bean>
What is the difference between @Autowired and @Resource?
The @Autowired annotation assembles dependent objects according to the type (byType), but there are multiple beans of the same type. When the byType annotation cannot be used, the byName will be used for the annotation. If it is still impossible to determine which one is to be annotated The bean will be UnsatisfiedDependencyException.
@Resource will first assemble according to byName. If no bean is found, it will automatically find byType again.
What does the @Qualifier annotation do
When you need to create multiple beans of the same type and want to assemble only one of the beans using attributes, you can use the @Qualifier annotation and @Autowired to eliminate ambiguity by specifying which bean should be assembled.
What is the difference between @Bean and @Component?
Both use annotations to define Beans. @Bean is the use of Java code to assemble the Bean, and @Component is the automatic assembly of the Bean.
The @Component annotation is used on a class, indicating that a class will be used as a component class, and telling Spring to create a bean for this class, and each class corresponds to a bean.
The @Bean annotation is used on methods to indicate that this method will return a Bean. @Bean needs to be used in the configuration class, that is, the class needs to be annotated with @Configuration.
@Component
public class Student {
private String name = "lkm";
public String getName() {
return name;
}
}
@Configuration
public class WebSocketConfig {
@Bean
public Student student(){
return new Student();
}
}
The @Bean annotation is more flexible. When you need to assemble a third-party class into the Spring container, because there is no way to add @Component annotations to the source code, you can only use the @Bean annotation method, of course, you can also use the xml method.
What is the difference between @Component, @Controller, @Repositor and @Service?
@Component: The most common components can be injected into the spring container for management.
@Controller: Mark the class as a Spring Web MVC controller.
@Service: Mark the class as a business layer component.
@Repository: Mark the class as a data access component, that is, a DAO component.
What are the Spring transaction implementation methods?
A transaction is a series of operations performed atomically. Spring transaction mechanism mainly includes declarative transaction and programmatic transaction.
- Programmatic transactions: Manage transactions programmatically. This approach brings a lot of flexibility, but it is difficult to maintain.
- Declarative transaction: Separate the transaction management code from the business method and encapsulate it through aop. Spring declarative transactions eliminate the need for us to deal with operations such as obtaining connections, closing connections, committing transactions, and rolling back. Use
@Transactional
annotation to open declarative transaction.
@Transactional
related attributes of 061d4680939d65 are as follows:
Attributes | type | describe |
---|---|---|
value | String | Optional qualified descriptor, specifying the transaction manager used |
propagation | enum: Propagation | Optional transaction propagation behavior settings |
isolation | enum: Isolation | Optional transaction isolation level settings |
readOnly | boolean | Read-write or read-only transaction, default read-write |
timeout | int (in seconds granularity) | Transaction timeout setting |
rollbackFor | Class object array, must inherit from Throwable | Array of exception classes that caused the transaction to roll back |
rollbackForClassName | Array of class names, must inherit from Throwable | Array of exception class names that caused the transaction to roll back |
noRollbackFor | Class object array, must inherit from Throwable | An array of exception classes that will not cause the transaction to roll back |
noRollbackForClassName | Array of class names, must inherit from Throwable | Array of exception class names that will not cause the transaction to roll back |
What kind of transaction spread behavior?
Seven transaction propagation behaviors are defined in the TransactionDefinition interface:
PROPAGATION_REQUIRED
If there is a transaction, the current transaction is supported. If there is no transaction, start a new transaction. If the two methods of nested calls are annotated with transactions and run in the same thread, the two methods use the same transaction. If running in a different thread, a new transaction will be started.PROPAGATION_SUPPORTS
If there is a transaction, support the current transaction. If there is no transaction, then non-transactional execution.PROPAGATION_MANDATORY
If there is already a transaction, support the current transaction. If there is no transaction, the exceptionIllegalTransactionStateException
is thrown.PROPAGATION_REQUIRES_NEW
always starts a new transaction. Need to use JtaTransactionManager as the transaction manager.PROPAGATION_NOT_SUPPORTED
always executes non-transactionally and suspends any existing transactions. Need to use JtaTransactionManager as the transaction manager.PROPAGATION_NEVER
is always executed non-transactionally. If there is an active transaction, an exception is thrown.PROPAGATION_NESTED
If an active transaction exists, it runs in a nested transaction. If there is no active transaction, it will be executed according to the PROPAGATION_REQUIRED property.
PROPAGATION_NESTED and PROPAGATION_REQUIRES_NEW:
When using PROPAGATION_REQUIRES_NEW
, the inner transaction and the outer transaction are two independent transactions. Once the inner transaction is committed, the outer transaction cannot roll back it. The two transactions do not affect each other.
When using PROPAGATION_NESTED
, the rollback of the outer transaction can cause the rollback of the inner transaction. The exception of the inner transaction does not cause the rollback of the outer transaction, it is a true nested transaction.
How does Spring solve the problem of circular dependencies?
Cyclic dependency injected by the constructor: Spring cannot handle it, and directly throws an exception BeanCurrentlylnCreationException
Cyclic dependency of attribute injection in singleton mode: the cyclic dependency is handled through the three-level cache.
Non-singleton circular dependency: cannot be processed.
The following analyzes how to deal with the circular dependency of attribute injection in the singleton mode:
First of all, the initialization of Spring singleton objects is roughly divided into three steps:
createBeanInstance
: instantiate the bean, use the constructor to create the object, and allocate memory for the object.populateBean
: Perform dependency injection.initializeBean
: Initialize the bean.
In order to solve the circular dependency problem of a singleton, Spring uses a three-level cache:
singletonObjects
: completed the initialization of the singleton object map, bean name --> bean instance
earlySingletonObjects
: Complete instantiation of uninitialized singleton object map, bean name --> bean instance
singletonFactories
: Singleton object factory map, bean name --> ObjectFactory, singletonFactories will be added after the singleton object is instantiated.
After calling createBeanInstance for instantiation, addSingletonFactory will be called to place the singleton object in singletonFactories.
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
Suppose A depends on the instance object of B, and B also depends on the instance object of A.
- A first completes the instantiation and adds itself to singletonFactories
- Then perform dependency injection, find that you depend on object B, and then try to get(B)
- Found that B has not been instantiated, instantiate B
- Then B found that he relied on object A during initialization, so he tried get(A), tried first-level cache singletonObjects and second-level cache earlySingletonObjects but did not find it, tried third-level cache singletonFactories, because A added himself to singletonFactories when it was initialized, so B can get the A object, and then move A from the third-level cache to the second-level cache
- After B gets the A object, it successfully completes the initialization, and then puts itself into the first-level cache singletonObjects
- Return to A at this time, and A can get the object of B at this time to successfully complete its initialization
It can be seen that the circular dependency of attribute injection is mainly realized by adding the instantiated bean to singletonFactories. Beans that use constructor dependency injection will undergo dependency injection when they are instantiated and will not be added to singletonFactories. For example, A and B are both through constructor dependency injection. When A calls the constructor to instantiate, it finds that it depends on B. B is not instantiated, and B will be instantiated. At this time, A is not instantiated. Will not be added to singtonFactories. And B depends on A, B will go to the third-level cache to look for the A object and find that it does not exist, so it will instantiate A again, and A will be instantiated twice, which causes an exception to be thrown.
Summary: 1. Use the cache to identify the nodes that have been traversed; 2. Use Java references to set the object address in advance, and then complete the object.
Spring startup process
- Read the web.xml file.
- Create a ServletContext to provide a host environment for the ioc container.
- Trigger the container initialization event and call the contextLoaderListener.contextInitialized() method. This method will initialize an application context WebApplicationContext, that is, Spring's ioc container. After the ioc container is initialized, it will be stored in the ServletContext.
- Initialize the Servlet configured in web.xml. Such as DispatcherServlet, used to match and process each servlet request.
Does Spring's singleton bean have thread safety issues?
When multiple users request a service at the same time, the container will assign a thread to each request. At this time, multiple threads will execute the business logic corresponding to the request concurrently. Example member attributes), you must consider thread safety issues.
If there are only read operations on global variables and static variables in each thread, but no write operations, then there will be no thread safety issues; if multiple threads perform write operations at the same time, thread synchronization generally needs to be considered, otherwise the threads may be affected Safety.
Stateless beans and stateful beans
- Beans with instance variables can save data and are not thread-safe.
- Objects without instance variables. Cannot save data, it is thread safe.
Stateless Beans in Spring are suitable for singleton mode, so that instances can be shared to improve performance. Stateful Beans are not safe in a multi-threaded environment. Generally, Prototype mode or ThreadLocal is used to solve thread safety issues.
If useful, a thumbs up , support it~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。