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));
    }

省略

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值