catalogue
1: spring source code analysis
2: Control inversion, dependency injection
4: aop transaction and transaction invalidation
5.1: what is circular dependency
5.2: how to solve circular dependency
1: spring source code analysis
ApplicationContext applicationContext1=new ClassPathXmlApplicationContext("spring configuration file");
The core of spring source code is the refresh method. Read this method
The 11 method in the source code is the focus, initializing the singleton bean
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh"); // Prepare this context for refreshing. //1: Initialize spring configuration environment, container start time and other information prepareRefresh(); // Tell the subclass to refresh the internal bean factory. //2: Get the beanfactory. The default is the DefaultListableBeanFactory factory //And load the bean definition map and put all the configured bean information into the map ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. //3: Prepare beanfactory and set beanfactory, such as context class loader and various ware interfaces) prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. //4: Post processing after BeanFactory preparation postProcessBeanFactory(beanFactory); StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process"); // Invoke factory processors registered as beans in the context. // 5. Method of executing beanfactoryprocessor; invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. //6: Method of executing beanfactoryprocessor; registerBeanPostProcessors(beanFactory); beanPostProcess.end(); // Initialize message source for this context. // 7 initMessageSource(); Initialize MessageSource component (internationalization function; message binding and message parsing); initMessageSource(); // Initialize event multicaster for this context. // 8 initialize event dispatcher initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. // Subclass 9 overrides this method to customize the logic when the container is refreshed; onRefresh(); // Check for listener beans and register them. // 10 register the ApplicationListener in all items in the container registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. //11 instantiate all remaining (non lazy load initialization) singleton bean s. //The point is this method finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); contextRefresh.end(); } } }
Method 11 analysis helps us understand how spring manages bean s by controlling flipping and dependency injection
2: Control inversion, dependency injection
The bean generated by spring managed beandefiniton is controlled to flip. It is managed by container
Dependency injection is injected by the spring container
3: aop section
aop aspect depends on dynamic proxy of jdk and cglib. Generate proxy classes and enhance them in proxy classes
4: aop transaction and transaction invalidation
/** * 1:REQUIRED * The transaction code test simply inserts data from two tables * Insert class table and student table */ @Test public void REQUIRED() { ClassService classService = applicationContext.getBean("classServiceImpl", ClassService.class); Classs classs = new Classs(); classs.setCaption("One year of College 3"); Student student = new Student(); student.setSname("Test 2333333"); student.setSsex("male"); student.setSdatetime(new Date()); classService.REQUIRED(student, classs); } /** * 2:SUPPORTS * If the caller does not open the transaction, there will be no transaction. If it is opened, it will be executed according to the transaction * If it fails, the caller will roll back * */ @Test public void SUPPORTS() throws Exception { ClassService classService = applicationContext.getBean("classServiceImpl", ClassService.class); Classs classs = new Classs(); classs.setCaption("University 1"); Student student = new Student(); student.setSname("test"); student.setSsex("male"); student.setSdatetime(new Date()); classService.SUPPORTS(student, classs); } /** * 3:NOT_SUPPORTED * Does not follow the caller transaction * The caller commits rollback without affecting himself * * NEVER Error reporting: the parent method cannot have transactions */ @Test public void NOT_SUPPORTED() { ClassServiceController classServiceController = applicationContext.getBean("classServiceController", ClassServiceController.class); Classs classs = new Classs(); classs.setCaption("first grade"); Student student = new Student(); student.setSname("test hu"); student.setSsex("male"); student.setSdatetime(new Date()); classServiceController.NOT_SUPPORTED(student, classs); } /** * 4:REQUIRES_NEW * No matter whether the caller has a transaction or not, it will start its own transaction submission or rollback, which will not affect the caller */ @Test public void REQUIRES_NEW() { ClassService classService = applicationContext.getBean("classServiceImpl", ClassService.class); Classs classs = new Classs(); classs.setCaption("Grade 1 2"); Student student = new Student(); student.setSname("test hu"); student.setSsex("male"); student.setSdatetime(new Date()); classService.REQUIRES_NEW(student,classs); } /** * 5:MANDATORY * The caller must have a transaction, or an error will be reported */ @Test public void MANDATORY() { ClassService classService = applicationContext.getBean("classServiceImpl", ClassService.class); Classs classs = new Classs(); classs.setCaption("Grade one 5"); Student student = new Student(); student.setSname("Test 5"); student.setSsex("male"); student.setSdatetime(new Date()); classService.mandatory(student,classs); } /** * 6:NESTED * Your own exceptions will not affect the caller * The caller exception rolls back all of itself */ @Test public void NESTED() { ClassService classService = applicationContext.getBean("classServiceImpl", ClassService.class); Classs classs = new Classs(); classs.setCaption("Grade one 6"); Student student = new Student(); student.setSname("Test 6"); student.setSsex("male"); student.setSdatetime(new Date()); classService.NESTED(student,classs); } /** * propagation Transaction propagation behavior * * REQUIRED(0),Indicates that the transaction is currently running in a transaction. If it is not, the transaction execution result will be started directly. If there is a transaction inserted in multiple tables, it will either succeed or fail * SUPPORTS(1),It means to follow the transaction, if any, or not. Execution result: multi table insertion has no transaction, some succeed and some fail * MANDATORY(2),The caller must have a transaction, or an error will be reported * REQUIRES_NEW(3),No matter whether the caller has a transaction or not, it will start its own transaction submission or rollback, which will not affect the caller * NOT_SUPPORTED(4),It means I don't follow the business. The boss's business has nothing to do with me * NEVER(5),Said that there can be no business, the boss will report an error if there is a business * NESTED(6);Exceptions made by the caller will not affect the caller, and the caller will roll back the transaction itself */
5: Cyclic dependence
5.1: what is circular dependency
Two classes refer to each other
5.2: how to solve circular dependency
To solve circular dependency, first of all, we know that when the constructor creates an object, the object will first initialize and allocate memory space, and then instantiate and assign values to attributes. The two steps here are separated. Just like the double verification of our singleton. Therefore, this provides a solution space for circular dependency.
1: We first initialize A and find that A depends on B, and then put the initialization of A into the L3 cache. At this time, A is incomplete.
2: Then initialize B. the code under the B loop cannot find a in the first and second level cache. A has not completed the complete initialization, and the third level cache can find a. at this time, B has completed the complete initialization and put B into the first level cache
3: Then a initializes, finds B in the L1 cache, and completes the initialization of A
First, check the source code:
public static void main(String[] args) { @Nullable protected Object getSingleton(String beanName, boolean allowEarlyReference) { // Quick check for existing instance without full singleton lock //1: Is there an existing bean in the L1 cache Object singletonObject = this.singletonObjects.get(beanName); //2: The L1 cache singleton pool does not exist and is being created if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { //3: Get bean from L2 cache singletonObject = this.earlySingletonObjects.get(beanName); //4: The L2 cache also has no and allows circular dependencies if (singletonObject == null && allowEarlyReference) { synchronized (this.singletonObjects) { // Consistent creation of early reference within full singleton lock //5: The first level cache may query the bean again during the creation process singletonObject = this.singletonObjects.get(beanName); //6: L1 cache does not exist if (singletonObject == null) { //7: Query the L2 cache again singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null) { //8: There is no query buffer in L2 cache ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { //9: The third buffer exists, the third buffer is stored in the second buffer, and the third buffer is removed singletonObject = singletonFactory.getObject(); this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } } } return singletonObject; } }
Circular dependency resolves the internal three-level cache that relies on spring:
/** L1 cache: complete beans without circular dependency Cache of singleton objects: bean name to bean instance */ private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); /** L2 cache: used to solve AOP facet Cache of early singleton objects: bean name to bean instance */ private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16); /** Third level cache: store incomplete beans to solve circular dependency, and put aop's aspect proxy beans into the second level cache cache of single ton factories: bean name to objectfactory */ private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);