spring自定义封装jdbc操作

1.@ComponentScan实现原理

1.上下文创建
new AnnotationConfigApplicationContext(MainConfig.class)

具体过程有参考spring上下文参考
2.register(componentClasses);//就是配置类的注册

3.refresh();
具体过程有参考ioc容器的刷新

ComponentScan的解析在invokeBeanFactoryPostProcessors(beanFactory);这一步

有一个后置处理器beanfactory的后置处理器
ConfigurationClassPostProcessor
ConfigurationClassPostProcessor类图
遍历所有的后置处理器优先执行实现了优先级接口(PriorityOrdered或者Order的)的

// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
			//第一个就是BeanDefinitionRegistryPostProcessor	
			String[] postProcessorNames =
		beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);

//执行后置处理器的

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
		List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
		String[] candidateNames = registry.getBeanDefinitionNames();
		//获取所有的bean定义遍历
		for (String beanName : candidateNames) {
			BeanDefinition beanDef = registry.getBeanDefinition(beanName);
			//获取@Configuration的属性值,获得bean定义候选者
			if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
				if (logger.isDebugEnabled()) {
					logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
				}
			}
			else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
			}
		}

		// Return immediately if no @Configuration classes were found
		if (configCandidates.isEmpty()) {
			return;
		}
		//候选者排序
		// Sort by previously determined @Order value, if applicable
		configCandidates.sort((bd1, bd2) -> {
			int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
			int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
			return Integer.compare(i1, i2);
		});
		//是不是单例,设置名称生成器
		//设置环境
		//开始解析
		//先判断这个注解是不是@Component注解的
		//配置文件@PropertySources处理
		//ComponentScans.class, ComponentScan.class处理
		// Parse each @Configuration class
		//注意关键到了,后面解析上面扫描的basePackages开始配置并扫描
		
		ConfigurationClassParser parser = new ConfigurationClassParser(
				this.metadataReaderFactory, this.problemReporter, this.environment,
				this.resourceLoader, this.componentScanBeanNameGenerator, registry);

		Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
		Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
		do {
			parser.parse(candidates);
			parser.validate();

			Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
			configClasses.removeAll(alreadyParsed);
		//后面就不看了
		
	}
  • 上面关键的步骤是解析候选者 parser.parse(candidates);
    • 先判断这个注解是不是@Component注解的
    • basePackages开始配置并扫描,解析源码
      org.springframework.context.annotation.ComponentScanAnnotationParser#parse
    • 最后一步是 returnscanner.doScan(StringUtils.toStringArray(basePackages));

2.自定义

1.MyMapperScan注解

这里面用了@Import语法

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(MapperScan.class)
public @interface MyMapperScan {
    String[] basePackages() default {};
    Class<?>[] classes() default {};
}

MapperScans实现了ImportBeanDefinitionRegistrar接口,也是beanfactory的后置处理器

/**
 * @author authorZhao
 * @date 2019/12/13
 */
public class MapperScan implements ImportBeanDefinitionRegistrar, ApplicationContextAware {

    private static final Logger logger = LoggerFactory.getLogger(MapperScan.class);
    /**
     * 扫描的包路径
     */
    private String[] basePackage;
    /**
     * 需要扫描的类
     */
    private Class[] classes;

    private ApplicationContext applicationContext;

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    	//获取注解的值
        Map<String, Object> annotationAttributes = importingClassMetadata.getAnnotationAttributes(MyMapperScan.class.getName());
        this.basePackage = (String[])annotationAttributes.get("basePackages");

        this.classes = (Class[])annotationAttributes.get("classes");
        //importingClassMetadata.getMetaAnnotationTypes()
        //名字生成器采用spring默认的,不设置也行
        //重点到了,自己的scan,扫描包
        MySqlMapperScanner mapperScanner = new MySqlMapperScanner(registry);
        //mapperScanner.setBeanNameGenerator(AnnotationBeanNameGenerator.INSTANCE);
        mapperScanner.setResourceLoader(this.applicationContext);
        //mapperScanner.isCandidateComponent()
        //this.scan(StringUtils.tokenizeToStringArray((String) this.basePackage, (String) ",; \t\n"));
        logger.info("开始扫描包:{}",basePackage);
        mapperScanner.doScan(this.basePackage);
        logger.info("开始扫描类:{}",classes);
        if(classes!=null&&classes.length>0){
		//对于claess属性就直接手工注册
            for (Class clzz:classes){
                if(!clzz.isInterface())continue;
                if(!registry.containsBeanDefinition(clzz.getSimpleName())){
                    //if(
                    BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clzz);
                    GenericBeanDefinition definition = (GenericBeanDefinition) builder.getRawBeanDefinition();
                    definition.getConstructorArgumentValues().addGenericArgumentValue(clzz);
                    definition.setBeanClass(MyFactoryBean.class);
                    //这里采用的是byType方式注入,类似的还有byName等
                    definition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);
                    registry.registerBeanDefinition(clzz.getSimpleName(), definition);
                    logger.info("{}定义信息注册完毕",clzz.getSimpleName());
                }
            }

        }

    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

3.MySqlMapperScanner 直接继承ClassPathBeanDefinitionScanner ,利用spring的扫描方法实现扫描

/**
 * @author authorZhao
 * @date 2019/12/13
 */
public class MySqlMapperScanner extends ClassPathBeanDefinitionScanner {
	
	//这个构造器必须的
    public MySqlMapperScanner(BeanDefinitionRegistry registry) {
        super(registry);
    }
	
	//扫描
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
   		 //直接调用父类的扫描方法,bean的定义已经被注册
        Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
        for (BeanDefinitionHolder holder : beanDefinitions) {
        //循环设置属性,为后面实例化做准备
            GenericBeanDefinition definition = (GenericBeanDefinition) holder.getBeanDefinition();
            //spring源码就是采用这种方式给工厂类注入属性
            //serviceInterface方法名,第二个参数是bean定义
            //definition.getPropertyValues().add("serviceInterface", (Object) definition.getBeanClassName());
            //我的工厂采用的是构造注入,并且只有一个参数
            ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues();
            constructorArgumentValues.addIndexedArgumentValue(0,definition.getBeanClassName());
            definition.getConstructorArgumentValues().addArgumentValues(constructorArgumentValues);
            //设置自己的工厂类
            definition.setBeanClass(MyFactoryBean.class);
        }
        return beanDefinitions;
    }
    
    protected void registerDefaultFilters() {
        this.addIncludeFilter((metadataReader,metadataReaderFactory)->{
            if(metadataReader.getClassMetadata().isInterface())return true;
            return false;
        });
    }

    @Override
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
        return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
    }
}

MyFactoryBean里面生成代理类的方法见上文(上一篇文章)

**
 * 为Mapper生成代理对象
 * @author authorZhao
 * @param <T>
 */
public class MyFactoryBean<T> implements FactoryBean<T> {

    private Logger logger = LoggerFactory.getLogger(MyFactoryBean.class);

    private Class<T> interfaceClass;
    
    
    public MyFactoryBean(Class<T> interfaceClass) {
        this.interfaceClass = interfaceClass;
    }
    public MyFactoryBean() {
    }

    @Override
    public T getObject() throws Exception {
        logger.info("正在为{}生成代理对象",interfaceClass.getName());
        T t = (T)MapperProxy.getObject(interfaceClass);
        if(t==null){
            logger.error("{}代理对象,生成失败",interfaceClass.getName());
        }
        logger.info("{}代理对象,生成成功",interfaceClass.getName());
        return t;
    }

    @Override
    public Class<T> getObjectType() {
        return interfaceClass;
    }

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

    /**
     * 如果采用方法注入属性,必须准备无参构造,不然报错
     * @param serviceInterface
     */
    public void setServiceInterface(Class<T> serviceInterface) {
        this.interfaceClass = serviceInterface;
    }
}

3.测试

准备了四个接口,四个Mapper,名字不一样

在这里插入图片描述

启动类

@SpringBootApplication
@MyMapperScan(basePackages = {"com.git.sql.mapper","com.git.sql.mapper2"},classes = MyMapper4.class)
public class SqlApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(SqlApplication.class, args);
        Arrays.stream(run.getBeanDefinitionNames()).forEach(System.out::println);
        System.out.println("启动完毕");

    }
//输出结果包含
//myMapper
//myMapper2
//myMapper3
//MyMapper4
}

结束

  • 本文是上一篇文章的补充自己封装jdbc与spring整合
    上一篇写死只为某一个特定的类生成代理,现在通过追踪spring源码的角度为某一写接口生成代理
  • 其实在spring的scan里面还是有很多学文的,如何根据路径扫描,扫描本项目和其他jjar包,这里暂时没深入研究
  • 下一篇将补充cglib的代理,并且将代理类生成为文件,并且使用工具反编译,这里有坑
  • 本文为作者原创,转载请申明出去
    参考:spring源码
    源代码地址dubbo练习
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐