主题:Beetlsql的Dao注入研究,自定义的Interface注入动态生成实现

wddark 2019年06月12日 116

(proxy部分后面补充)

继承BaseMapper的接口可以注入到项目之中,

如:  public interface CityDao extends BaseMapper<City> 

实现方式:

开发一个类 实现ImportBeanDefinitionRegistrar,参考BeetlMapperScannerRegister

不要使用@Service注册,而是再@Configuration 的类上使用@Import 导入猜测是为了再加载bean之前执行 。

@Configuration
@ComponentScan
@EnableAutoConfiguration
@Import(FrameworkInitializingScannerConfigurer.class)
public class Application {

   public static void main(String[] args) throws Exception {
      SpringApplication.run(Application.class, args);
   }

}

实现一个类 作为核心的动态bean注入

该类implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware,

其中:通过ApplicationContextAware接口获得applicationContext


BeanDefinitionRegistryPostProcessor继承自BeanFactoryPostProcessor,是一种比较特殊的BeanFactoryPostProcessor。BeanDefinitionRegistryPostProcessor中定义的postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)方法 可以让我们实现自定义的注册bean定义的逻辑。


postProcessBeanDefinitionRegistry方法之中实现一种扫描器,可以继承ClassPathBeanDefinitionScanner,实现扫描逻辑,比如必须继承BaseMapper的操作。参考 BeetlSqlClassPathScanner类。


doScan方法里面 拿到Set<BeanDefinitionHolder> 针对 BeanDefinitionHolder就是扫描到的一个个接口。


构造出一个 BeanDefinitionHolder需要BeanDefinition,可以直接new GenericBeanDefinition或者子类

以下为 beetsql代码

logger.debug(holder.toString());
definition = (GenericBeanDefinition) holder.getBeanDefinition();
String mapperClassName = definition.getBeanClassName();
// 必须在这里加入泛型限定,要不然在spring下会有循环引用的问题
definition.getConstructorArgumentValues().addGenericArgumentValue(mapperClassName);
//mapperClassName 形如com.cpsdna.iov.thava.dpe.service.map.dao.DpeCityDao
definition.getPropertyValues().add("mapperInterface", mapperClassName);
// 根据工厂的名称创建出SqlManager
definition.getPropertyValues().add("sqlManager", new RuntimeBeanReference(this.sqlManagerFactoryBeanName));
definition.setBeanClass(BeetlSqlFactoryBean.class);
// 设置Mapper按照接口组装
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
if (logger.isDebugEnabled()) {
   logger.debug("已开启BeetSql自动按照类型注入 '" + holder.getBeanName() + "'.");
}

可以看到实际注入的是BeetlSqlFactoryBean,并且设置了2个属性。

新生成的bean,需要再beanDefinitionRegistry中注册beanDefinitionRegistry.registerBeanDefinition(dh.getBeanName(),dh.getBeanDefinition());


BeetlSqlFactoryBean 是泛型类,实现了 FactoryBean接口。由于dao这种是泛型接口,需要拿到泛型的类型,可以再 BeetlSqlFactoryBean这样的实现类里面加一个 private Class<T> mapperInterface;构建BeetlSqlFactoryBean时候注入进去。 

FactoryBean 对应的注入假如是一个类,已经可用;假如是一个接口(比如dao),关键是public T getObject() 这个方法,需要使用proxy动态生成Dao的子类。

闲大赋 2019年06月12日

厉害了