Aop simple simulation based ImportSelector

ImportSelector interfaces are introduced into the spring core interfaces to the external configuration of the class, which may be implemented in the switch based on the mode on a feature can be seen in the large number of annotations @EnableXXX SpringBoot, the points into the ImportSelector are found.

Spring parse source code analysis @Import

Spring class configuration when parsing, processing for Import follows:

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
      Collection<SourceClass> importCandidates, boolean checkForCircularImports) {


   if (importCandidates.isEmpty()) {
      return;
   }


   if (checkForCircularImports && isChainedImportOnStack(configClass)) {
      this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
   }
   else {
      this.importStack.push(configClass);
      try {
         for (SourceClass candidate : importCandidates) {
           //处理ImportSelector
            if (candidate.isAssignable(ImportSelector.class)) {
               Candidate IS AN ImportSelector class // -> IT to the delegate to the Determine Imports 
               // if deferredImportSelectors type, require a delay process on behalf of, temporarily into List <DeferredImportSelectorHolder> deferredImportSelectors in @Configuration processed until all the rearmost before treatment class that implements the interface DeferredImportSelector    
               <?> = Candidate.loadClass candidateClass class (); 
               ImportSelector Selector = BeanUtils.instantiateClass (candidateClass, ImportSelector.class); 
               S); 
               // if the interface implementation class while achieving EnvironmentAware, BeanFactoryAware, BeanClassLoaderAware or ResourceLoaderAware, then the call first call interface methods corresponding to the above prior methods which selectImports    
               ParserStrategyUtils.invokeAwareMethods ( 
                     Selector, this.environment, this.resourceLoader, this.registry); 
               IF (! = null && Selector this.deferredImportSelectors the instanceof DeferredImportSelector) { 
                  this.deferredImportSelectors.add ( 
                        new new DeferredImportSelectorHolder (the configClass, (DeferredImportSelector) Selector));
               }
               else {
                  String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
                  Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
                  processImports(configClass, currentSourceClass, importSourceClasses, false);
               }
            }
            //处理ImportBeanDefinitionRegistrar
            else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
               // Candidate class is an ImportBeanDefinitionRegistrar ->
               // delegate to it to register additional bean definitions
               Class<?> candidateClass = candidate.loadClass();
               ImportBeanDefinitionRegistrar registrar =
                     BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
               ParserStrategyUtils.invokeAwareMethods(
                     registrar, this.environment, this.resourceLoader, this.registry);
               configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
            }
            //处理普通的配置类
            else {
               // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
               // process it as an @Configuration class
               this.importStack.registerImport(
                     currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
               processConfigurationClass(candidate.asConfigClass(configClass));
            }
         }
      }
      catch (BeanDefinitionStoreException ex) {
         throw ex;
      }
      catch (Throwable ex) {
         throw new BeanDefinitionStoreException(
               "Failed to process import candidates for configuration class [" +
               configClass.getMetadata().getClassName() + "]", ex);
      }
      finally {
         this.importStack.pop();
      }
   }

For the treatment of ImportSelector: instantiation of its objects:

ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);

Then call its methods: selector.selectImports () to get the class name, which will ultimately generate BeanDefinition objects according to the relevant class and added to the instance of the bean beanMap go. Thus based on ImportSelector we can do a dynamic Aop and controlled by a switch, in fact, probably so SpringAop implemented.

 

Analog implementation SpringAop

Define an interface

public interface IUserDao {
   void query();
}

Define an implementation class

@Repository
public class UserDao implements IUserDao {
   public void query() {
      System.out.println("from db.....");
   }
}

Aop proxy implementation

public class MyAop implements BeanPostProcessor {
   @Override
   public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
   
      if (beanName.equals("userDao")) {
         bean = Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{IUserDao.class}, new MyInvokeHandler(bean));
      }
      return bean;
   }


   @Override
   public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
      return bean;
   }
}


public class MyInvokeHandler implements InvocationHandler {
   Object target;


   public MyInvokeHandler(Object target) {
      this.target = target;
   }


   @Override
   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      System.out.println("proxy 方法");
      return method.invoke(target, args);
   

Definition of a switch

@Retention(RetentionPolicy.RUNTIME)
@Import(MyImportSelect.class)
public @interface EanableAop {


}

Configuration class

@Configuration
@ComponentScan("com.tian")
@EanableAop
public class AppConfig {}

test

@Test
public void test_import() {
   AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
   String[] names = context.getBeanDefinitionNames();
   for (String name : names) {
      System.out.println(name);
   }
   IUserDao dao = (IUserDao) context.getBean("userDao");
   dao.query();
}

The end result, of course, if the @EanableAop removed, it will no longer perform the proxy method:

 

Guess you like

Origin www.cnblogs.com/tianboblog/p/12619262.html