spring小結(2)----ImportBeanDefinitionRegistrar

上一節主要說了bean註冊流程,下面再補充介紹其中關鍵的流程

再解析有@Config主機類時,也會處理@import

 

@Configuration
@ComponentScan("com.lmq.BaseService")
@Import("實現ImportBeanDefinitionRegistrar接口的類") //也可以是normal類,importSelect
public class AppConfig {

...........

//實現ImportBeanDefinitionRegistrar接口的類可以幫beanfactory加入某個bean對象,尤其是爲接口生成動態代理對象添加到spring的bean中,比如mybatis的mapper接口

spring註冊類方法:

    1,register()  //需要是一個類,無法參與生成bd

    2, scan()  //需要是一個類,或者註解,無法參與生成bd

    3,ImportBeanDefinitionRegistrar, 好處參與生成bd ,好比MapperScan把@mapper接口變成對象,

@Documented
@Import({MapperScannerRegistrar.class})
public @interface MapperScan {
    String[] value() default {};

其中MapperScannerRegistrar.class幫助註冊一個bean,

class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
    private ResourceLoader resourceLoader;

    public MapperScannerRegistrar() {
    }

    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {。。。。//這裏registry上節講過是beanfactory

以上是例子,幫助理解ImportBeanDefinitionRegistrar

扯遠了

進去此方法,

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) {
            if (candidate.isAssignable(ImportSelector.class)) {
               // Candidate class is an ImportSelector -> delegate to it to determine imports
               Class<?> candidateClass = candidate.loadClass();
               ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
               ParserStrategyUtils.invokeAwareMethods(
                     selector, this.environment, this.resourceLoader, this.registry);
               if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
                  this.deferredImportSelectors.add(
                        new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
               }
               else {
                  String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
                  Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
                  processImports(configClass, currentSourceClass, importSourceClasses, false);
               }
            }
            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 {//import 普通類
               // 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();
      }
   }
}

 

順便提下

AService{

@Autowired

Adao dao

 

}

對於Bservice extends Aservice

@Autowired

Adao dao  不會實例化

對於Bservice implements Aservice

@Autowired

Adao dao  會實例化

spring的自動裝配

繼續介紹,
@Configuration
@ComponentScan("com.lmq.BaseService")
//@Import("ImportBeanDefinitionRegistrar")
@Import(MyImportSelect.class) //相當於後面註冊UserController.class,並實例化添加到spring的bean
public class AppConfig {

 。。。。。。。

}

public class MyImportSelect  implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{UserController.class.getName()};
    }
}

但引用@Import(MyImportSelect.class) ,UserController.class是需要存在項目的,無法創建代理對象,所以需要

ImportBeanDefinitionRegistrar;

這裏以uerMapper接口爲例來模仿mybatis的mapperscan,註冊並添加實例對象到spring的bean中

其中UserMapper:

public interface UserMapper {

    @Select("select * from user")
    public List<User> findUserInfo(String name);


}

自定義MyImportBeanDefinitionRegistrar

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        /**
         * 得到bd,或者類信息,這裏對於接口類,假設實現創建代理對象,
         */
        //這裏先寫死去爲某個接口去創建動態代理對象,其實可以模擬掃描註解的接口,類似mybatis的mapperscan, UserMapper是個接口

//        UserMapper userMapper= (UserMapper) Proxy.newProxyInstance(MainTest.class.getClassLoader(), new Class[]{UserMapper.class}, new InvocationHandler() {
//            @Override
//            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//                System.out.println("in proxy");
//                return null;
//            }
//        });

       // BeanDefinitionBuilder beanDefinitionBuilder= BeanDefinitionBuilder.genericBeanDefinition(userMapper.getClass()); //實際無法獲取代理類信息,使用factorybean
        BeanDefinitionBuilder beanDefinitionBuilder= BeanDefinitionBuilder.genericBeanDefinition(UserMapper.class);
        GenericBeanDefinition beanDefinition= (GenericBeanDefinition) beanDefinitionBuilder.getBeanDefinition();

        //爲了傳參數,可以給bd添加構造函數
        beanDefinition.getConstructorArgumentValues().addGenericArgumentValue("com.lmq.dao.UserMapper");
        beanDefinition.setBeanClass(MyFactoryBean.class); //MyFactoryBean不能加Componenrt註解
        registry.registerBeanDefinition("userMapper",beanDefinition);
    }
}

其中

public class MyFactoryBean implements FactoryBean {
    Class clazz;
    public MyFactoryBean( Class clazz)
    {
        this.clazz=clazz;
    }

    @Override
    public Object getObject() throws Exception {

        Class []clazz= new Class[]{this.clazz};
               Object  proxy= (UserMapper) Proxy.newProxyInstance(MainTest.class.getClassLoader(),clazz, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {


                System.out.println("in proxy");

                //爲了模仿mybatis執行sql
                Method method1 =proxy.getClass().getInterfaces()[0].getMethod(method.getName(),String.class);
                Select select =method1.getDeclaredAnnotation(Select.class);
                System.out.println(select.value()[0]);

                return null;
            }
        });
    return proxy;
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }
}

這裏AppConfig引入MyImportBeanDefinitionRegistrar.class

@Configuration
@ComponentScan("com.lmq.BaseService")
@Import(MyImportBeanDefinitionRegistrar.class)

public class AppConfig {


}
 AnnotationConfigApplicationContext lmqcontext = new AnnotationConfigApplicationContext(AppConfig.class);
  //方式一
// LmqService lmq = lmqcontext.getBean(LmqService.class);
 // LmqService lmq = lmqcontext.getBean("lmqService");
 // lmq.printSys();
  UserMapper lmq = (UserMapper) lmqcontext.getBean("userMapper");
  lmq.findUserInfo();

 

輸出結果:

便實現往spring添加bean對象實例了哈,生成動態代理實例,類似mybtais mapperScan掃描接口.

核心是MyFactoryBean, 類似的其實mybatis有MapperFactoryBean

public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
    private Class<T> mapperInterface;  //同樣是接口參數,MyFactoryBean參考類似的,目標是爲接口生成代理對象
    private boolean addToConfig = true;

    public MapperFactoryBean() {
    }

......................

再看下MapperScannerRegistrar,也用了MapperFactoryBean

public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
    private ResourceLoader resourceLoader;

    public MapperScannerRegistrar() {
    }

    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
        ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
        if (this.resourceLoader != null) {
            scanner.setResourceLoader(this.resourceLoader);
        }

        Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
        if (!Annotation.class.equals(annotationClass)) {
            scanner.setAnnotationClass(annotationClass);
        }

        Class<?> markerInterface = annoAttrs.getClass("markerInterface");
        if (!Class.class.equals(markerInterface)) {
            scanner.setMarkerInterface(markerInterface);
        }

        Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
        if (!BeanNameGenerator.class.equals(generatorClass)) {
            scanner.setBeanNameGenerator((BeanNameGenerator)BeanUtils.instantiateClass(generatorClass));
        }

        Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
        if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
            scanner.setMapperFactoryBean((MapperFactoryBean)BeanUtils.instantiateClass(mapperFactoryBeanClass));
        }

        scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef"));
        scanner.setSqlSessionFactoryBeanName(annoAttrs.getString("sqlSessionFactoryRef"));
        List<String> basePackages = new ArrayList();
        String[] var10 = annoAttrs.getStringArray("value");
        int var11 = var10.length;

        int var12;
        String pkg;
        for(var12 = 0; var12 < var11; ++var12) {
            pkg = var10[var12];
            if (StringUtils.hasText(pkg)) {
                basePackages.add(pkg);
            }
        }

        var10 = annoAttrs.getStringArray("basePackages");
        var11 = var10.length;

        for(var12 = 0; var12 < var11; ++var12) {
            pkg = var10[var12];
            if (StringUtils.hasText(pkg)) {
                basePackages.add(pkg);
            }
        }

        Class[] var14 = annoAttrs.getClassArray("basePackageClasses");
        var11 = var14.length;

        for(var12 = 0; var12 < var11; ++var12) {
            Class<?> clazz = var14[var12];
            basePackages.add(ClassUtils.getPackageName(clazz));
        }

        scanner.registerFilters();
        scanner.doScan(StringUtils.toStringArray(basePackages));
    }

省略

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章