Spring 高级 工厂后处理器模拟实现-Mapper

一、源方式自动注入

package com.mangoubiubiu.show.a05;

import com.alibaba.druid.pool.DruidDataSource;
import com.mangoubiubiu.show.a05.component.Bean2;
import com.mangoubiubiu.show.a05.mapper.Mapper1;
import com.mangoubiubiu.show.a05.mapper.Mapper2;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Configuration
@ComponentScan("com.mangoubiubiu.show.a05.component")
public class Config {


    @Bean
    public Bean1 bean1(){
        return new Bean1();
    }

    public Bean2 bean2(){
        return new Bean2();
    }

    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        return sqlSessionFactoryBean;
    }


    @Bean(initMethod = "init")
    public DruidDataSource druidDataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl("jdbc:mysql://localhost:3306/zeal_user");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        return dataSource;
    }

    @Bean
    public MapperFactoryBean<Mapper2> mapper2(SqlSessionFactory sqlSessionFactory){
        MapperFactoryBean<Mapper2> factory = new MapperFactoryBean<>(Mapper2.class);
        factory.setSqlSessionFactory(sqlSessionFactory);
        return factory;
    }
    @Bean
    public MapperFactoryBean<Mapper1> mapper1(SqlSessionFactory sqlSessionFactory){
        MapperFactoryBean<Mapper1> factory = new MapperFactoryBean<>(Mapper1.class);
        factory.setSqlSessionFactory(sqlSessionFactory);
        return factory;
    }

}
package com.mangoubiubiu.show.a05;

import com.mangoubiubiu.show.a05.component.ComponentScanPostProcessor;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.JmxEnabled;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.MethodMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.stereotype.Component;

import java.awt.*;
import java.io.IOException;
import java.util.List;
import java.util.Set;

@Slf4j
public class A05Application {

    private MetadataReader reader;

    public static void main(String[] args) throws IOException {
        GenericApplicationContext context = new GenericApplicationContext();
        //将config注册到容器里面
        context.registerBean("config",Config.class);
//        context.registerBean(ComponentScanPostProcessor.class);
//        context.registerBean(MapperScannerConfigurer.class,beanDefinition -> {
//            beanDefinition.getPropertyValues().add("basePackage","com.mangoubiubiu.show.a05.mapper");
//        });

        context.registerBean(AtBeanPostProcessor.class);

        //初始化容器

        context.refresh();

        for (String name: context.getBeanDefinitionNames()) {
            System.out.println(name);
        }

        context.close();
    }



}

发现Mapper1 Mapper2 确实被注入进来了

二、自己定义Bean后处理器将Mapper注入到容器中

package com.mangoubiubiu.show.a05;

import lombok.SneakyThrows;
import org.mybatis.spring.mapper.MapperFactoryBean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;

public class MyMapperPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @SneakyThrows
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        Resource[] resources = resolver.getResources("classpath:com/mangoubiubiu/show/a05/mapper/**/*.class");
        CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
        AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
        for (Resource resource : resources) {
            MetadataReader metadataReader = factory.getMetadataReader(resource);
            //得到类的源信息
            ClassMetadata classMetadata = metadataReader.getClassMetadata();
            //如果当前类是接口
            if(classMetadata.isInterface()){
                AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(MapperFactoryBean.class)
                        //加进class  的类名
                        .addConstructorArgValue(classMetadata.getClassName())
                        //设置自动装配
                        .setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE)
                        .getBeanDefinition();
                String beanName = generator.generateBeanName(beanDefinition, beanFactory);
                generator.generateBeanName(beanDefinition, beanFactory);
                beanFactory.registerBeanDefinition(beanName,beanDefinition);

            }


        }


    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }
}
package com.mangoubiubiu.show.a05;

import com.mangoubiubiu.show.a05.component.ComponentScanPostProcessor;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.JmxEnabled;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.MethodMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.stereotype.Component;

import java.awt.*;
import java.io.IOException;
import java.util.List;
import java.util.Set;

@Slf4j
public class A05Application {

    private MetadataReader reader;

    public static void main(String[] args) throws IOException {
        GenericApplicationContext context = new GenericApplicationContext();
        //将config注册到容器里面
        context.registerBean("config",Config.class);
//        context.registerBean(ComponentScanPostProcessor.class);
//        context.registerBean(MapperScannerConfigurer.class,beanDefinition -> {
//            beanDefinition.getPropertyValues().add("basePackage","com.mangoubiubiu.show.a05.mapper");
//        });

//        context.registerBean(AtBeanPostProcessor.class); //解析bean
        context.registerBean(MyMapperPostProcessor.class);
        //初始化容器

        context.refresh();

        for (String name: context.getBeanDefinitionNames()) {
            System.out.println(name);
        }

        context.close();
    }



}

运行发现报错了,为啥会报错了,因为此时 

这个Bean组件并没有注入到IOC容器里面,所有我们自定义的Processor自动装配失败了。

解决方案:开启我们上次写的解析Bean的 Proceesor就行啦

但是发现Mapper1 和 Mapper2 并没有注入进来,

Bean的名称是根据bean定义里面的一些信息去生成名字 而我们要注入的Mapper有2个 第一个注入后Bean名字叫mapperFactoryBean,第二个Bean注入后由于BeanDefinition里面的信息相同,生成的Bean的名字也叫mapperFactoryBean,2个相同bean名的组件,后生成的bean会把前面的bean给覆盖掉 所以这里只生成一个叫mapperFactoryBean的Bean。

三、解决方案

根据接口生成BeanDefinition就行啦

package com.mangoubiubiu.show.a05;

import lombok.SneakyThrows;
import org.mybatis.spring.mapper.MapperFactoryBean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;

public class MyMapperPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @SneakyThrows
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        Resource[] resources = resolver.getResources("classpath:com/mangoubiubiu/show/a05/mapper/**/*.class");
        CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
        AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
        for (Resource resource : resources) {
            MetadataReader metadataReader = factory.getMetadataReader(resource);
            //得到类的源信息
            ClassMetadata classMetadata = metadataReader.getClassMetadata();
            //如果当前类是接口
            if(classMetadata.isInterface()){
                AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(MapperFactoryBean.class)
                        //加进class  的类名
                        .addConstructorArgValue(classMetadata.getClassName())
                        //设置自动装配
                        .setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE)
                        .getBeanDefinition();
                //根据Mapper接口生成 beanDefinition
                AbstractBeanDefinition bd = BeanDefinitionBuilder.genericBeanDefinition(classMetadata.getClassName()).getBeanDefinition();
                String beanName = generator.generateBeanName(bd, beanFactory);
                generator.generateBeanName(beanDefinition, beanFactory);
                beanFactory.registerBeanDefinition(beanName,beanDefinition);

            }


        }


    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2022-08-28 13:31  KwFruit  阅读(31)  评论(0编辑  收藏  举报