ImportBeanDefinitionRegistrar source code and usage
first step
The defined Mapper layer:
@Mapper public interface PayMapper { @Select("select * from city") public List<Map<String,Object>> list(); }
Step 2
Using FactoryBean, create an object through getObject and put it into the spring container. Here, use a proxy object and put it into the spring container.
public class MyFactoryBean implements FactoryBean, InvocationHandler { private Class aClass; public MyFactoryBean(Class aClass) { = aClass; } @Override public Object getObject() throws Exception { Class[] interfaces = new Class[]{aClass}; Object proxyInstance = (().getClassLoader(), interfaces, this); return proxyInstance; } @Override public Class<?> getObjectType() { return null; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { ("Proxy object, get sql statement"); Method method1 = ().getInterfaces()[0].getMethod((), null); Select declaredAnnotation = (); (()[0]); return null; } }
Step 3
Spring's ImportBeanDefinitionRegistrar processor can operate on spring's BeanDefinitionMap and modify the description of the bean. It has not become an object yet. Here is the type of creation injection, creating the interface required in the construction method, and finally the name of the bean is: payServiceTest, a BeanDefinition description.
public class MyImportDefinitionRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { BeanDefinitionBuilder beanDefinitionBuilder = (); AbstractBeanDefinition beanDefinition = (); //TODO: Injection type (); //TODO: Injection construction method ().addGenericArgumentValue(""); //TODO: Put it into beanDefinitionMap ("payServiceTest",beanDefinition); } }
Step 4
Custom annotation, put @Import() annotation, and put the MyImportDefinitionRegistrar class into the sprinig to run.
@Retention() @Target() @Documented @Import() public @interface LuoyanImportBeanDefinitionRegistrar { }
Step 5
Configuration class: You need to use the custom annotation @LuoyanImportBeanDefinitionRegistrar to execute the code content of the post-processor.
@Configuration @ComponentScan("") @MapperScan("") @LuoyanImportBeanDefinitionRegistrar public class AppConfig { }
Step 6
Startup class:
public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); (); (new MyBeanFactoryPostProcessor()); (); PayMapper payServiceTest = (PayMapper) ("payServiceTest"); (); }
Source code:
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter, boolean checkForCircularImports) { if (()) { return; } if (checkForCircularImports && isChainedImportOnStack(configClass)) { (new CircularImportProblem(configClass, )); } else { (configClass); try { /** * * Because @Import(,) can put multiple * importCandidates: Indicates the registration + class name of the class class placed in the @Import annotation. for example:. * candidate: means */ for (SourceClass candidate : importCandidates) { /** * ImportSelector, determine whether this implements the ImportSelector class */ if (()) { // Candidate class is an ImportSelector -> delegate to it to determine imports //Get Import's class loadClass Class<?> candidateClass = (); //Reflection implements an object //The underlying layer of this instantiateClass() method is quite complicated /*************************** InstantiateClass() This method is very important*********************************/ //New came out the class object that currently implements the ImportSelector interface ImportSelector selector = (candidateClass, , , , ); Predicate<String> selectorFilter = (); if (selectorFilter != null) { exclusionFilter = (selectorFilter); } if (selector instanceof DeferredImportSelector) { (configClass, (DeferredImportSelector) selector); } else { /** * Here's the focus * Normal class is added with @component class */ //Get all strings.//Running references are used to recurse, which means that you have @Impont on the configuration class, but you still have @Impont on the class that implements the ImportSelector class //TODO: selector represents the object of the class that implements the ImportSelector interface. String[] importClassNames = (()); //Pass the name in to get importSourceClasses, add this class to the annotation variable and use the asSourceClasses() method. //importClassNames=.TestService3 Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter); //Then the loop judgment is performed. Continue to call the processImports() method, which is also the same when I first came in. //Recursively, the second call to processImports is here. //If it is a normal class, it will enter else processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false); } } /** * ImportBeanDefinitionRegistrar implements the class of this interface and puts it into the addImportBeanDefinitionRegistrar() method * importBeanDefinitionRegistrarsMap. * and * The class that implements the ImportSelector interface is placed in the configurationClassesMap. * So when parsing these classes, different methods are used to store (configClasses); * */ else if (()) { // Candidate class is an ImportBeanDefinitionRegistrar -> // delegate to it to register additional definitions Class<?> candidateClass = (); ImportBeanDefinitionRegistrar registrar = (candidateClass, , , , ); (registrar, ()); } /** * Normal */ else { // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar -> // process it as an @Configuration class /** * Otherwise, after adding to importStack, call processConfigurationClass for processing * processConfiguration mainly puts classes in configurationClasses * You can see that the normal class is registered when it is scanned again * If importSelector, the echo is placed behind configurationClasses for registration * Note that the processConfigurationClass here has been explained before */ ( (), ().getClassName()); //The processConfigurationClass() method continues to judge whether the @Configuration annotation is added to the current ordinary class. //(configClass) This method is to use the class obtained through the @Import annotation, and after executing the method, the returned class string is obtained and the reflected class is put into the (importedBy); collection. // When importing it into spring's BeanDefinitionMap processConfigurationClass((configClass), exclusionFilter); } } } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to process import candidates for configuration class [" + ().getClassName() + "]", ex); } finally { (); } } }
Source code:
private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) { ((registrar, metadata) -> /** * This is to implement the ImportBeanDefinitionRegistrar interface by itself *'s logic in class, method registered in beanMap */ (metadata, , )); }
Summarize
The above is personal experience. I hope you can give you a reference and I hope you can support me more.