An Interview experience

How to use Spring to reference Bean objects from external containers, or how Spring manages beans from external containers, for example: Suppose your project is launched by SpringBoot, and the boot class package name is com.springboot.test, so your managed Bean in the Spring container is scanned by com.springboot.test by default This is an external container named demo.test. It is not in com.springboot.test, so it will not be detected. @autowired private TestUtil TestUtil; testUtil.methodOne() Springboot. test is not the name of the third party package. The TestUtil class under the third party package is not managed by the Spring container. Therefore, TestUtil must be null and will fail So how did this problem get solved?Copy the code

SpringBoot auto assembly from interview experience

What is automatic assembly
Let's say we have a project to connect to Mysql, use Mybatis, use Redis, etc. If we write the code by ourselves, we need to do a lot of fancy things, configuration database connection, connection pool,Redis method packaging, etc. But we actually import one in the development process The ***stater package is complete, which encapsulates various methods such as: Starter springboot- starter springboot-mybatis-starter springboot-mybatis-starter springboot-mybatis-starter For example, if you want to store data in redis, use the following gesture: @autoWired private RedisUtil RedisUtil RedisUtil. Set (key,value) That is, we can use annotations or some simple configuration to achieve a certain function with the help of SpringBoot, which is automatic assembly, just like I introduced springboot-Redis-starter, configure the redis connection information, point annotations, directly use the method insideCopy the code
Talk about the interview experience
We've introduced some springboot-Redis-starter packages that we use for RedisUtil, Combining the above interview experience see springboot - redis - the starter package name is * srpingboot redis * *, and how did it RedisUtil inside my Spring container management? Why am I using it without a null pointer? Specifically, file cross-module instantiationCopy the code

Meta-inf/Spring. factories

If you're a source-loving student, you'll be familiar with this file as it appears in various ** Springboot -*-starter* source packages, or in the SRC /main/resources/ meta-INF /* directory of the corporate architect's out-of-the-box toolkitCopy the code

The content of the spring.factories file is the implementation class corresponding to the interface. The content of the spring.factories file must be in kv formatCopy the code

Meta-inf /spring.factories

Our own build a SpringBoot project, because a **springboot-starter**, and Debug look at the source code process about SpringBoot source code start process here not much force force, here directly on dry products, into the main process Debug order: Start the class @ SpringBootApplication -- -- >Copy the code

Compound annotation @enableAutoConfiguration -->Copy the code

@Import(EnableAutoConfigurationImportSelector.class)-->
Copy the code

AutoConfigurationImportSelector.selectImports()-->
Copy the code

List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); -->Copy the code

!!!!!!!!! The storm has appeared!! Source, seen here as soon as a important class SpringFactoriesLoader and its corresponding methods, we further look at this class, and what did you do this method SpringFactoriesLoader loadFactoryNames ( getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());Copy the code

Public static final String FACTORIES_RESOURCE_LOCATION = "meta-INF /spring.factories"; public static List<String> loadFactoryNames(Class<? > factoryClass, ClassLoader classLoader) { String factoryClassName = factoryClass.getName(); Try {// Use the classLoader to obtain the Spring. factories file Enumeration<URL> urls = (classLoader! = null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); List<String> result = new ArrayList<String>(); // Start reading the spring.factories file while (urls.hasmoreElements ()) {URL URL = urls.nextelement (); / / get the configuration information inside the Properties Properties. = PropertiesLoaderUtils loadProperties (new UrlResource (url)); String factoryClassNames = properties.getProperty(factoryClassName); result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames))); } return result; } catch (IOException ex) { throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories  from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); }}Copy the code
Here you can see the screenshot of my Debug data section where you can see that I **druid** was scanned Under the package of the spring. Factories files, and get the org. Springframework. Boot. Autoconfigure. EnableAutoConfiguration this key corresponding configuration values, also is the bean needs to be loadedCopy the code

Or let me be plain: the corporate architect wrote a third-party package,com.demo.TestUtil, and now he wants to give me the TestUtil to Spring to load in and puts the TestUtil information into a Spring-.Factories file This will be read by the SpringFactoriesLoader file in Spring, after which ******Copy the code

As for how Spring is loaded into the bean, that is another point. If you are interested, you can learn about several injection methods of Spring bean. Injection of ImportBeanDefinitionRegistrar ImportSelector here also is the core entrance class AutoConfigurationImportSelector. SelectImports in ()Copy the code

Spring. The factories

Role summary
SpringBoot does not scan the contents of submodules during package scanning, which prevents beans from other modules from being injected into the Spring container. SpringBoot provides us with a spring.Factories file that allows us to annotate beans from other modules For example, when we introduce third-party JAR packages such as druid-starter and Redis-starter, we will inject the beans we need to inject Write to the spring.factories file, and SpringBoot scans the information in spring.factories to load the bean This answers the above question. Even if our module is com.test.demo,Spring does not automatically scan and inject beans from third-party modules such as demo.util, so cross-module instantiation can be doneCopy the code
The principle of summary
1 Springboot start, start class @ SpringBootApplication composite annotation EnableAutoConfiguration inherited EnableAutoConfigurationImportSelector, AutoConfigu RationImportSelector AutoConfigurationImportSelector class 2 core method selectImports (), will need to scan the current Spring loaded Bean object information 3 Spring provides the core class SpringFactoriesLoader, The main purpose of this class is to scan the meta-INF /spring.factories file under jar and load the spring.factories file with the key value of EnableAutoConfiguration Interest 4 SpringFactoriesLoader will scan the information back to the AutoConfigurationImportSelector instantiated by SpringCopy the code

Write in the back

Qualification is limited, hard to avoid mistakes, but also hope that beautiful son generous instructionCopy the code