首页 > 其他分享 >Spring 高级 工厂后处理器模拟实现-Mapper

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

时间:2022-08-28 13:45:55浏览次数:64  
标签:Mapper core Spring factory springframework 处理器 context org import

一、源方式自动注入

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 {

    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

标签:Mapper,core,Spring,factory,springframework,处理器,context,org,import
From: https://www.cnblogs.com/mangoubiubiu/p/16632633.html

相关文章

  • Spring源码-自定义标签
    一、新建实体类publicclassUserimplementsSerializable{privateStringid;privateStringname;privateIntegerage;publicStringgetId(){ return......
  • spring源码具体细节 super setConfigLocations
      1首先先调用super父类构造方法 classPathXmlApplicaitonContext 初始化成员属性  依然掉父类构造方法 调用父类 资源处理器 当前系统需要运行所......
  • Spring源码01:环境搭建
    写在开始:这个系列会陆续更新我学习Spring源码的一些笔记与自己的理解,由于本人水平有限,难免对有些知识理解不到位,亦或者手误导致文中有不正确的地方,欢迎各位指正与探讨。......
  • Spring(二)-生命周期 + 自动装配(xml) +自动装配(注解)
    1、生命周期**Spring容器的bean**的生命周期;1.1默认生命周期1.1.1生命周期调用构造方法,创建实例对象;set方法,给实例对象赋值;init初始化方法初始化对象;(手......
  • Spring中的SPI机制
    前言在面向对象编程领域中,六大原则之一的依赖倒置原则提到的原则规定:高层次的模块不应该依赖于低层次的模块,两者都应该依赖于抽象接口;抽象接口不应该依赖于具体实现,而......
  • 理解Spring Security和实现动态授权
    一、SpringSecurity架构SpringSecurity是基于SpringAOP和Servlet过滤器的安全框架,提供全面的安全性解决方案。SpringSecurity核心功能包括用户认证(Authenticati......
  • Cannot resolve org.springframework.cloud:spring-cloud-starter-netflix-eureka-ser
    Cannotresolveorg.springframework.cloud:spring-cloud-starter-netflix-eureka-server:unknown前言:启动eureka项目,发现右侧maven中的项目dependencies报红,reimport也......
  • Spring @Repository 注解
    Spring的项目严重依赖注解。@Repository 注解在Spring2.0之前的版本中,@Repository注解可以标记在任何的类上,用来表明该类是用来执行与数据库相关的操作(即dao对象),并支......
  • Spring 最常用的几个注解
    大家都知道Spring严重依赖注解。实际开发的时候,我们用得最多的可能就是下面几个注解了。注解用途@Component最最普通的注解,表示这个类可以被注入到Spring容......
  • Spring Bean工具类
    SpringUtils工具类importcn.caijiajia.framework.util.EnvUtil;importorg.springframework.beans.BeansException;importorg.springframework.context.ApplicationCo......