美文网首页
2020-12-15_Spring与Mybatis底层facto

2020-12-15_Spring与Mybatis底层facto

作者: kikop | 来源:发表于2020-12-15 12:20 被阅读0次

Spring与Mybatis底层factoryBean源码深度分析笔记

1概述

本系列知识要点如下,主要是借助FacoryBean不断演化Bean的注入过程:

  1. BeanDefinition定义的几种方式概述
  2. 快速开始
  3. 借助 factoryBean接口把普通pojo类生成 bean
  4. 借助 factoryBean接口把mapper接口生成 bean
  5. 借助 factoryBean接口把mapper接口生成 bean应用1之refresh之前
  6. 借助 factoryBean接口把mapper接口生成 bean应用2之实现MyImportBeanDefinitionRegistrar1接口
  7. 借助 factoryBean接口把mapper接口生成 bean之实现MyImportBeanDefinitionRegistrar2接口硬编码扫描包
  8. 配置一个SqlSessionFactoryBean,手动注入SqlSession
  9. 引入扫描注解,配置包扫描路径
  10. 配置一个SqlSessionFactoryBean,自动注入SqlSession

2BeanDefinition定义的几种方式概述

2.1编程方式

借助AbstractBeanDefinition将mapper接口转为代理对象。参见2.1节。

2.2申明方式

借助注解,@Transactional、@Component、@Bean、@Import,但他们的底层原理均为@AutoWired。

3源码实战分析

3.1快速开始

普通pojo对象

package com.kikop.dao;

/**
 * @author kikop
 * @version 1.0
 * @project Name: mybatisspringdemo
 * @file Name: AppConfig
 * @desc MyUser普通对象
 * @date 2019/5/19
 * @time 10:50
 * @by IDE: IntelliJ IDEA
 */
public class MyUser {

    private String userName;
    private int age;

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public int getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

//    public MyUser(String userName, int age) {
//        this.userName = userName;
//        this.age = age;
//    }

//    @Override
//    public String toString() {
//        return "MyUser{" +
//                "userName='" + userName + '\'' +
//                ", age=" + age +
//                '}';
//    }
}

mapper

package com.kikop.mapper;


import com.alibaba.fastjson.JSONObject;
import org.apache.ibatis.annotations.Select;

import java.util.List;

/**
 * @author kikop
 * @version 1.0
 * @project Name: mybatisspringdemo
 * @file Name: MyUserMapper
 * @desc MyUserMapper接口
 * @date 2019/5/19
 * @time 10:50
 * @by IDE: IntelliJ IDEA
 */
public interface MyUserMapper {

    @Select("select * from users")
    List<JSONObject> queryUser();
}

service

package com.kikop.service;


import com.alibaba.fastjson.JSONObject;
import com.kikop.mapper.MyOrderMapper;
import com.kikop.mapper.MyUserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * @author kikop
 * @version 1.0
 * @project Name: mybatisspringdemo
 * @file Name: MyUserService
 * @desc MyUserMapper代码接口文件
 * @date 2019/5/19
 * @time 10:50
 * @by IDE: IntelliJ IDEA
 */
@Component
public class MyUserService {

    /**
     * 自动注入实现类
     * required = false:表示可赋null
     * myUserMapper 原则上接口是不能注入的(原因:没有实现类)
     * 需要 mybatis框架代理对象
     */
    @Autowired(required = false)
//    @Autowired
    private MyUserMapper myUserMapper;


    /**
     * 自动注入实现类
     * required = false:表示可赋null
     * myUserMapper 原则上接口是不能注入的(原因:没有实现类)
     * 需要 mybatis框架代理对象
     */
    @Autowired(required = false)
//    @Autowired
    private MyOrderMapper myOrderMapper;

    public List<JSONObject> queryUser() {
        return myUserMapper.queryUser();
    }

    public void test() {
        System.out.printf("MyUserService");
    }
}

mybatis配置

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <!--1.mybatis 自己管理数据库连接信息,引入外部属性文件-->
    <properties resource="mysqldb.properties"></properties>

    <!--2.mybatis environments-->
    <environments default="development">
        <environment id="development">
            <!--1.配置mysql数据库事务-->
            <transactionManager type="JDBC"/>

            <!-- 2.配置mysql数据库连接信息 -->
            <dataSource type="POOLED">
                <property name="driver" value="${mysql.driver}"/>

                <!--url注意点:-->
                <!--1.xmls里面写&时,需要转义 &amp-->
                <!--2.需要开启多行执行功能, allowMultiQueries=true-->
                <!--<property name="url" value="jdbc:mysql://localhost:3306/mybatis?userUnicode=true&amp;characterEncoding=UTF-8&amp;allowMultiQueries=true"/>-->
                <property name="url" value="${mysql.url}"/>
                <property name="username" value="${mysql.username}"/>
                <property name="password" value="${mysql.password}"/>
            </dataSource>
        </environment>

    </environments>

    <!--去掉,就要手动加入-->
    <!--<mappers>-->
        <!--<package name="com.kikop.mapper"></package>-->
    <!--</mappers>-->

</configuration>

mysqldb配置

mysql.driver=com.mysql.jdbc.Driver

#jdbc:mysql://localhost:3306/mybatis?userUnicode=true&amp;characterEncoding=UTF-8&amp;allowMultiQueries=true&amp;autoReconnect=true&amp;failOverReadOnly=false"
#jdbc:mysql://localhost:3306/mybatis?userUnicode=true&amp;characterEncoding=UTF-8&amp;useSSL=false&amp;serverTimezone=UTC&amp;allowMultiQueries=true"

#需要开启多行执行功能
mysql.url=jdbc:mysql://localhost:3306/mybatis?userUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
mysql.username=root
mysql.password=123456

实现FactoryBean接口

定义scan注解

实现ImportBeanDefinitionRegistrar接口

测试类

package com.kikop;


import com.kikop.dao.MyUser;
import com.kikop.mapper.MyUserMapper;
import com.kikop.service.MyUserService;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;


/**
 * @author kikop
 * @version 1.0
 * @project Name: mybatisspringdemo
 * @file Name: AppConfig
 * @desc SimpleSpringApplication启动类(配置类)
 * Spring与Mybatis底层源码深度分析
 * 快速开始
 * @date 2019/5/19
 * @time 10:50
 * @by IDE: IntelliJ IDEA
 */
@ComponentScan("com.kikop")
// 导入普通类生成 bean
public class Test0_SimpleSpringApplicationQuickStart {


    public static void main(String[] args) {
//        runSpringBuilder1();

//        runSpringBuilder2();

//        runSpringBuilderError();
    }

    /**
     * 运行Spring 上下文
     * 运行时开启:  myUserService:@Autowired(required = false)
     */
    public static void springbeantest1() {

        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();

        annotationConfigApplicationContext.register(Test0_SimpleSpringApplicationQuickStart.class); // 配置类


        annotationConfigApplicationContext.refresh();

        MyUserService myUserService = annotationConfigApplicationContext.getBean("myUserService", MyUserService.class);
        myUserService.test();
    }


    /**
     * 接口转为 Bean,接口无法实例化
     */
    public static void springbeantest2() {

        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        annotationConfigApplicationContext.register(Test0_SimpleSpringApplicationQuickStart.class); // 注册配置类之后


        // 1.注册配置类之后
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition.setBeanClass(MyUserMapper.class); // 接口转为 Bean,接口无法实例化
        annotationConfigApplicationContext.registerBeanDefinition("MyUserMapperXXX", beanDefinition);
        // 2.启动之前

        annotationConfigApplicationContext.refresh();  // 启动之前

        MyUserMapper myUserMapperXXX = annotationConfigApplicationContext.getBean("MyUserMapperXXX", MyUserMapper.class);
        System.out.println(myUserMapperXXX);
    }


    /**
     * 普通类生成Bean
     */
    public static void springbeantest3() {

        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        annotationConfigApplicationContext.register(Test0_SimpleSpringApplicationQuickStart.class); // 注册配置类之后


// 1.注册配置类之后
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition.setBeanClass(MyUser.class);
        beanDefinition.setScope("prototype");
        beanDefinition.setLazyInit(true);
        annotationConfigApplicationContext.registerBeanDefinition("MyUserXXX", beanDefinition);
// 2.启动之前


        annotationConfigApplicationContext.refresh();  // 启动之前

        MyUser myUserXXX = annotationConfigApplicationContext.getBean("MyUserXXX", MyUser.class);
        System.out.println(myUserXXX);
    }


}

3.2借助 factoryBean接口把普通pojo类生成 bean

实现FactoryBean接口

package mock.org.mybatis.spring.solution0;

import com.kikop.dao.MyUser;
import org.springframework.beans.factory.FactoryBean;

/**
 * @author kikop
 * @version 1.0
 * @project Name: mybatisspringdemo
 * @file Name: MyNormapPojoFactoryBean
 * @desc 创建代理对象(类或接口)
 * 针对普通pojo对象
 * @date 2019/5/19
 * @time 10:50
 * @by IDE: IntelliJ IDEA
 */
public class MyNormapPojoFactoryBean implements FactoryBean {

    @Override
    public Object getObject() throws Exception {


        MyUser myUser = new MyUser();
        System.out.println(myUser);
        return myUser;

    }

    @Override
    public Class<?> getObjectType() {
        return MyUser.class;
    }
}

定义scan注解

实现ImportBeanDefinitionRegistrar接口

测试类

package mock.org.mybatis.spring.solution0;

import com.kikop.dao.MyUser;
import org.springframework.beans.factory.FactoryBean;

/**
 * @author kikop
 * @version 1.0
 * @project Name: mybatisspringdemo
 * @file Name: MyNormapPojoFactoryBean
 * @desc 创建代理对象(类或接口)
 * 针对普通pojo对象
 * @date 2019/5/19
 * @time 10:50
 * @by IDE: IntelliJ IDEA
 */
public class MyNormapPojoFactoryBean implements FactoryBean {

    @Override
    public Object getObject() throws Exception {


        MyUser myUser = new MyUser();
        System.out.println(myUser);
        return myUser;

    }

    @Override
    public Class<?> getObjectType() {
        return MyUser.class;
    }
}
package com.kikop;


import mock.org.mybatis.spring.solution0.MyNormapPojoFactoryBean;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;


/**
 * @author kikop
 * @version 1.0
 * @project Name: mybatisspringdemo
 * @file Name: AppConfig
 * @desc SimpleSpringApplication启动类(配置类)
 * Spring与Mybatis底层源码深度分析:借助 factoryBean接口把普通pojo类生成 bean
 * @date 2019/5/19
 * @time 10:50
 * @by IDE: IntelliJ IDEA
 */
@ComponentScan("com.kikop")
public class Test0_MyNormapPojoFactoryBean {



    public static void main(String[] args) {
        springbeantest();
    }



    public static void springbeantest() {

        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        annotationConfigApplicationContext.register(Test0_MyNormapPojoFactoryBean.class); // 注册配置类之后


        // 1.注册配置类之后
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition.setBeanClass(MyNormapPojoFactoryBean.class);
        annotationConfigApplicationContext.registerBeanDefinition("MyUserFactoryBeanXXX", beanDefinition);
        // 2.启动之前

        annotationConfigApplicationContext.refresh();  // 启动之前

        Object myUserFactoryBeanXXX = annotationConfigApplicationContext.getBean("MyUserFactoryBeanXXX");
        System.out.println(myUserFactoryBeanXXX);

        Object myUserFactoryBeanXXXSelf = annotationConfigApplicationContext.getBean("&MyUserFactoryBeanXXX");
        System.out.println(myUserFactoryBeanXXXSelf);
    }




}

3.3借助 factoryBean接口把mapper接口生成 bean

实现FactoryBean接口

package mock.org.mybatis.spring.solution0;

import com.kikop.mapper.MyUserMapper;
import org.springframework.beans.factory.FactoryBean;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**

 * @author kikop

 * @version 1.0

 * @project Name: mybatisspringdemo

 * @file Name: MyFixedMapperFactoryBean

 * @desc 创建代理对象(类或接口)

 * 针对单个mapper

 * @date 2019/5/19

 * @time 10:50

 * @by IDE: IntelliJ IDEA
   */
   public class MyFixedMapperFactoryBean implements FactoryBean {

   @Override
   public Object getObject() throws Exception {

       // 创建mapper接口的代理对象
       Object myUserMapper = Proxy.newProxyInstance(MyFixedMapperFactoryBean.class.getClassLoader(), new Class<?>[]{MyUserMapper.class}, new InvocationHandler() {
           @Override
           public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
       
               // 执行业务逻辑
               System.out.printf(method.getName());
       
               return null;
           }
       });
       return myUserMapper;


    }
    
    @Override
    public Class<?> getObjectType() {
        return MyUserMapper.class;
    }

}

定义scan注解

实现ImportBeanDefinitionRegistrar接口

测试类

package com.kikop;


import com.kikop.service.MyUserService;
import mock.org.mybatis.spring.solution0.MyFixedMapperFactoryBean;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;


/**
 * @author kikop
 * @version 1.0
 * @project Name: mybatisspringdemo
 * @file Name: AppConfig
 * @desc SimpleSpringApplication启动类(配置类)
 * Spring与Mybatis底层源码深度分析:
 * 借助 factoryBean接口把mapper接口生成 bean
 * @date 2019/5/19
 * @time 10:50
 * @by IDE: IntelliJ IDEA
 */
@ComponentScan("com.kikop")
public class Test0_MyFixedMapperFactoryBean {



    public static void main(String[] args) {
        springbeantest();
    }

    public static void springbeantest() {

        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        annotationConfigApplicationContext.register(Test0_MyFixedMapperFactoryBean.class); // 注册配置类之后


        // 1.注册配置类之后
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition.setBeanClass(MyFixedMapperFactoryBean.class);
        annotationConfigApplicationContext.registerBeanDefinition("MyCommonFactoryBeanXXX", beanDefinition);
        // 2.启动之前

        annotationConfigApplicationContext.refresh();  // 启动之前

        Object myCommonFactoryBeanXXX = annotationConfigApplicationContext.getBean("MyCommonFactoryBeanXXX");
        myCommonFactoryBeanXXX.toString();

        MyUserService myUserService = annotationConfigApplicationContext.getBean("myUserService", MyUserService.class);
        myUserService.queryUser();

    }





}

3.4借助 factoryBean接口把mapper接口生成 bean应用1之refresh之前

实现FactoryBean接口

package mock.org.mybatis.spring.solution1;

import org.springframework.beans.factory.FactoryBean;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @author kikop
 * @version 1.0
 * @project Name: mybatisspringdemo
 * @file Name: MyCommonFactoryBean2
 * @desc 创建代理对象(类或接口)
 * 针对某个mapper.class列表
 * @date 2019/5/19
 * @time 10:50
 * @by IDE: IntelliJ IDEA
 */
public class MyCommonMapperClazzFactoryBean1 implements FactoryBean {

    private Class<?> mapperClazz;


    /**
     * 构造注入
     * @param mapperClazz
     */
    public MyCommonMapperClazzFactoryBean1(Class<?> mapperClazz) {
        System.out.println("构造注入");
        this.mapperClazz = mapperClazz;
    }

    /**
     * set注入
     * @param clazz
     */
    public void setClazz(Class<?> clazz) {
        System.out.println("set注入");
        this.mapperClazz = clazz;
    }

    @Override
    public Object getObject() throws Exception {

        // 创建mapper接口的代理对象
        Object myUserMapper = Proxy.newProxyInstance(MyCommonMapperClazzFactoryBean1.class.getClassLoader(),
                new Class<?>[]{mapperClazz}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                // 执行业务逻辑
                System.out.println(method.getName());

                return null;
            }
        });
        return myUserMapper;

    }

    @Override
    public Class<?> getObjectType() {
        return mapperClazz;
    }
}

定义scan注解

实现ImportBeanDefinitionRegistrar接口

测试类

package com.kikop;


import com.kikop.mapper.MyOrderMapper;
import com.kikop.mapper.MyUserMapper;
import com.kikop.service.MyUserService;
import mock.org.mybatis.spring.solution1.MyCommonMapperClazzFactoryBean1;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;


/**
 * @author kikop
 * @version 1.0
 * @project Name: mybatisspringdemo
 * @file Name: AppConfig
 * @desc SimpleSpringApplication启动类(配置类)
 * Spring与Mybatis底层源码深度分析:
 * 借助 factoryBean接口把mapper接口生成 bean应用1之refresh之前
 * @date 2019/5/19
 * @time 10:50
 * @by IDE: IntelliJ IDEA
 */
@ComponentScan("com.kikop")
public class Test1_1_MyCommonMapperClazzFactoryBean1 {



    public static void main(String[] args) {
        springbeantest();
    }


    public static void springbeantest() {

        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        annotationConfigApplicationContext.register(Test1_1_MyCommonMapperClazzFactoryBean1.class); // 注册配置类之后


        // 1.注册配置类之后

        // 注册 MyUserMapper
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition.setBeanClass(MyCommonMapperClazzFactoryBean1.class);
        beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(MyUserMapper.class);
        annotationConfigApplicationContext.registerBeanDefinition("MyUserCommonFactoryBean2XXX", beanDefinition);

        // 注册 MyOrderMapper
        AbstractBeanDefinition beanDefinition2 = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition2.setBeanClass(MyCommonMapperClazzFactoryBean1.class);
        beanDefinition2.getConstructorArgumentValues().addGenericArgumentValue(MyOrderMapper.class);
        annotationConfigApplicationContext.registerBeanDefinition("MyOrderCommonFactoryBean2XXX", beanDefinition2);


        // 2.启动之前

        annotationConfigApplicationContext.refresh();  // 启动之前

        MyUserService myUserService = annotationConfigApplicationContext.getBean("myUserService", MyUserService.class);
        myUserService.queryUser();

    }



}

3.5借助 factoryBean接口把mapper接口生成 bean应用2之实现MyImportBeanDefinitionRegistrar1接口

实现FactoryBean接口

定义scan注解

实现ImportBeanDefinitionRegistrar接口

package mock.org.mybatis.spring.solution1;

import com.kikop.mapper.MyOrderMapper;
import com.kikop.mapper.MyUserMapper;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;


/**
 * @author kikop
 * @version 1.0
 * @project Name: mybatisspringdemo
 * @file Name: MyImportBeanDefinitionRegistrar
 * @desc 注册BeanDefinition
 * @date 2019/5/19
 * @time 10:50
 * @by IDE: IntelliJ IDEA
 */
public class MyImportBeanDefinitionRegistrar1 implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {

        // 传clazz对象

        // 注册 MyUserMapper
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition.setBeanClass(MyCommonMapperClazzFactoryBean1.class);
        beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(MyUserMapper.class);
        beanDefinitionRegistry.registerBeanDefinition("MyUserCommonFactoryBean1XXX", beanDefinition);

        // 注册 MyOrderMapper
        AbstractBeanDefinition beanDefinition2 = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition2.setBeanClass(MyCommonMapperClazzFactoryBean1.class);
        beanDefinition2.getConstructorArgumentValues().addGenericArgumentValue(MyOrderMapper.class);
        beanDefinitionRegistry.registerBeanDefinition("MyOrderCommonFactoryBean1XXX", beanDefinition2);


    }
}

测试类

package com.kikop;


import com.kikop.service.MyUserService;
import mock.org.mybatis.spring.solution1.MyImportBeanDefinitionRegistrar1;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;


/**
 * @author kikop
 * @version 1.0
 * @project Name: mybatisspringdemo
 * @file Name: AppConfig
 * @desc SimpleSpringApplication启动类(配置类)
 * Spring与Mybatis底层源码深度分析
 * 借助 factoryBean接口把mapper接口生成 bean应用2之实现MyImportBeanDefinitionRegistrar1接口
 * @date 2019/5/19
 * @time 10:50
 * @by IDE: IntelliJ IDEA
 */
@ComponentScan("com.kikop")
@Import(MyImportBeanDefinitionRegistrar1.class)
public class Test1_2_MyCommonMapperClazzFactoryBean1 {



    public static void main(String[] args) {
        springbeantest();
    }


    public static void springbeantest() {

        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        annotationConfigApplicationContext.register(Test1_2_MyCommonMapperClazzFactoryBean1.class); // 注册配置类之后


//        // 1.注册配置类之后


//        // 注册 MyUserMapper
//        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
//        beanDefinition.setBeanClass(MyCommonMapperClazzFactoryBean1.class);
//        beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(MyUserMapper.class);
//        annotationConfigApplicationContext.registerBeanDefinition("MyUserCommonFactoryBean2XXX", beanDefinition);
//
//        // 注册 MyOrderMapper
//        AbstractBeanDefinition beanDefinition2 = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
//        beanDefinition2.setBeanClass(MyCommonMapperClazzFactoryBean1.class);
//        beanDefinition2.getConstructorArgumentValues().addGenericArgumentValue(MyOrderMapper.class);
//        annotationConfigApplicationContext.registerBeanDefinition("MyOrderCommonFactoryBean2XXX", beanDefinition2);


//        // 2.启动之前

        annotationConfigApplicationContext.refresh();  // 启动之前

        MyUserService myUserService = annotationConfigApplicationContext.getBean("myUserService", MyUserService.class);
        myUserService.queryUser();

    }




}

3.6借助 factoryBean接口把mapper接口生成 bean之实现MyImportBeanDefinitionRegistrar2接口硬编码扫描包

实现FactoryBean接口

定义scan注解

实现ClassPathBeanDefinitionScanner

package mock.org.mybatis.spring.solution2;

import mock.org.mybatis.spring.solution1.MyCommonMapperClazzFactoryBean1;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;

import java.util.Set;

/**
 * @author kikop
 * @version 1.0
 * @project Name: mybatisspringdemo
 * @file Name: MyBeanDefinitionScanner
 * @desc 利用Spring的扫描器进行包扫描
 * @date 2019/5/19
 * @time 10:50
 * @by IDE: IntelliJ IDEA
 */
public class MyBeanDefinitionScanner2 extends ClassPathBeanDefinitionScanner {

    public MyBeanDefinitionScanner2(BeanDefinitionRegistry registry) {
        super(registry);
    }


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

    @Override
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Set<BeanDefinitionHolder> beanDefinitionHolders = super.doScan(basePackages);// spring扫描,忽略接口


        // 修改 beanDefinitionHolders进行代理
        for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
            // 得到 beandefinition
            BeanDefinition beanDefinition = beanDefinitionHolder.getBeanDefinition();
            System.out.println(beanDefinition.getBeanClassName()); //-->com.kikop.mapper.MyUserMapper

            // 1.先设置构造参数
            beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(beanDefinition.getBeanClassName());

            // 2.后修改 BeanClsName
            beanDefinition.setBeanClassName(MyCommonMapperClazzFactoryBean1.class.getName());
        }
        return beanDefinitionHolders;
    }
}

实现ImportBeanDefinitionRegistrar接口

package mock.org.mybatis.spring.solution2;

import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;

import java.io.IOException;


/**
 * @author kikop
 * @version 1.0
 * @project Name: mybatisspringdemo
 * @file Name: MyImportBeanDefinitionRegistrar
 * @desc 注册BeanDefinition
 * @date 2019/5/19
 * @time 10:50
 * @by IDE: IntelliJ IDEA
 */
public class MyImportBeanDefinitionRegistrar2 implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {

        // 1.扫描mapper接口,得到bean class
        // spring默认不扫描接口
        String path = "com.kikop.mapper";

        MyBeanDefinitionScanner2 myBeanDefinitionScanner = new MyBeanDefinitionScanner2(beanDefinitionRegistry);

        myBeanDefinitionScanner.addIncludeFilter(new TypeFilter() {
            @Override
            public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
//                return false;
                return true;
            }
        });
        int scan = myBeanDefinitionScanner.scan(path);
        System.out.println(scan);





    }
}

测试类

package com.kikop;


import com.kikop.service.MyUserService;
import mock.org.mybatis.spring.solution2.MyImportBeanDefinitionRegistrar2;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;


/**
 * @author kikop
 * @version 1.0
 * @project Name: mybatisspringdemo
 * @file Name: AppConfig
 * @desc SimpleSpringApplication启动类(配置类)
 * Spring与Mybatis底层源码深度分析:
 * 借助 factoryBean接口把mapper接口生成 bean之实现MyImportBeanDefinitionRegistrar2接口硬编码扫描包
 * @date 2019/5/19
 * @time 10:50
 * @by IDE: IntelliJ IDEA
 */
@ComponentScan("com.kikop")
@Import(MyImportBeanDefinitionRegistrar2.class)
public class Test2_SimpleSpringApplicationHardCodePathScan {


    public static void main(String[] args) {
        springbeantest();
    }

    public static void springbeantest() {

        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        annotationConfigApplicationContext.register(Test2_SimpleSpringApplicationHardCodePathScan.class); // 注册配置类之后


//        // 1.注册配置类之后
//        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
//        beanDefinition.setBeanClass(MyCommonMapperClazzFactoryBean1.class);
//        annotationConfigApplicationContext.registerBeanDefinition("MyCommonFactoryBeanXXX", beanDefinition);
//        // 2.启动之前

        annotationConfigApplicationContext.refresh();  // 启动之前

        MyUserService myUserService = annotationConfigApplicationContext.getBean("myUserService", MyUserService.class);
        myUserService.queryUser();

    }





}

3.7配置一个SqlSessionFactoryBean,手动注入SqlSession

实现FactoryBean接口

package mock.org.mybatis.spring.solution3;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * @author kikop
 * @version 1.0
 * @project Name: mybatisspringdemo
 * @file Name: MyCommonFactoryBean2
 * @desc 创建代理对象(类或接口)
 * set注入SqlSession
 * @date 2019/5/19
 * @time 10:50
 * @by IDE: IntelliJ IDEA
 */
public class MyCommonMapperClazzBySqlSessionFactoryBean3 implements FactoryBean {

    private Class<?> mapperClazz;

    private SqlSession sqlSession;


    /**
     * 构造注入
     * @param mapperClazz
     */
    public MyCommonMapperClazzBySqlSessionFactoryBean3(Class<?> mapperClazz) {
        System.out.println("构造注入");
        this.mapperClazz = mapperClazz;
    }

    /**
     * set注入注解
     * @param sqlSessionFactory
     */
    @Autowired
    public void setSqlSession(SqlSessionFactory sqlSessionFactory) {

        // 加到 knownMappers
        //         去掉,就要手动加入-->
        //    <mappers>-->
        //        <package name="com.kikop.mapper"></package>-->
        //    </mappers>-->
                
        sqlSessionFactory.getConfiguration().addMapper(mapperClazz);
        this.sqlSession = sqlSessionFactory.openSession();
    }

    /**
     * set注入
     * @param clazz
     */
    public void setClazz(Class<?> clazz) {
        System.out.println("set注入");
        this.mapperClazz = clazz;
    }

    @Override
    public Object getObject() throws Exception {
        // 创建mapper接口的代理对象
        Object mapper = sqlSession.getMapper(mapperClazz);
        return mapper;
    }

    @Override
    public Class<?> getObjectType() {
        return mapperClazz;
    }
}

定义scan注解

继承ClassPathBeanDefinitionScanner

package mock.org.mybatis.spring.solution3;

import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;

import java.util.Set;

/**
 * @author kikop
 * @version 1.0
 * @project Name: mybatisspringdemo
 * @file Name: MyBeanDefinitionScanner
 * @desc 利用Spring的扫描器进行包扫描
 * @date 2019/5/19
 * @time 10:50
 * @by IDE: IntelliJ IDEA
 */
public class MyBeanDefinitionScanner3 extends ClassPathBeanDefinitionScanner {

    public MyBeanDefinitionScanner3(BeanDefinitionRegistry registry) {
        super(registry);
    }


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

    @Override
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Set<BeanDefinitionHolder> beanDefinitionHolders = super.doScan(basePackages);// spring扫描,忽略接口


        // 修改 beanDefinitionHolders进行代理
        for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
            // 得到 beandefinition
            BeanDefinition beanDefinition = beanDefinitionHolder.getBeanDefinition();
            System.out.println(beanDefinition.getBeanClassName()); //-->com.kikop.mapper.MyUserMapper

            // 1.先设置构造参数
            beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(beanDefinition.getBeanClassName());

            // 2.后修改 BeanClsName
            beanDefinition.setBeanClassName(MyCommonMapperClazzBySqlSessionFactoryBean3.class.getName());
        }
        return beanDefinitionHolders;
    }
}

实现ImportBeanDefinitionRegistrar接口

package mock.org.mybatis.spring.solution3;

import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;

import java.io.IOException;


/**
 * @author kikop
 * @version 1.0
 * @project Name: mybatisspringdemo
 * @file Name: MyImportBeanDefinitionRegistrar
 * @desc 注册BeanDefinition
 * @date 2019/5/19
 * @time 10:50
 * @by IDE: IntelliJ IDEA
 */
public class MyImportBeanDefinitionRegistrar3 implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {

        // 1.扫描mapper接口,得到bean class
        // spring默认不扫描接口
        String path = "com.kikop.mapper";

        MyBeanDefinitionScanner3 myBeanDefinitionScanner = new MyBeanDefinitionScanner3(beanDefinitionRegistry);

        myBeanDefinitionScanner.addIncludeFilter(new TypeFilter() {
            @Override
            public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
//                return false;
                return true;
            }
        });
        int scan = myBeanDefinitionScanner.scan(path);
        System.out.println(scan);





    }
}

测试类

package com.kikop;


import com.alibaba.fastjson.JSONObject;
import com.kikop.service.MyUserService;
import mock.org.mybatis.spring.solution3.MyImportBeanDefinitionRegistrar3;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;


/**
 * @author kikop
 * @version 1.0
 * @project Name: mybatisspringdemo
 * @file Name: AppConfig
 * @desc SimpleSpringApplication启动类(配置类)
 * Spring与Mybatis底层源码深度分析
 * 配置一个SqlSessionFactoryBean,手动注入SqlSession
 * @date 2019/5/19
 * @time 10:50
 * @by IDE: IntelliJ IDEA
 */
@ComponentScan("com.kikop")
@Import(MyImportBeanDefinitionRegistrar3.class)
public class Test3_SimpleSpringApplicationManualInjectSqlSession {

    /**
     * 配置一个SqlSessionFactoryBean
     * 可借助 mybatis-spring:SqlSessionFactoryBean解决
     * @return
     * @throws IOException
     */
    @Bean
    public SqlSessionFactory sqlSessionFactory() throws IOException {

        InputStream resourceAsStream = Resources.getResourceAsStream("mybatisconfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        return sqlSessionFactory;
    }

    public static void springbeantest() {

        // AnnotationConfigApplicationContext实现了 BeanDefinitionRegistry
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        annotationConfigApplicationContext.register(Test3_SimpleSpringApplicationManualInjectSqlSession.class); // 注册配置类之后


        // 1.注册配置类之后

//        引入mybatis-springjar扩展点。
//        jar执行包扫描。
//        生成mybatis的代理对象。

        // 2.启动之前

        annotationConfigApplicationContext.refresh();  // 启动之前

        MyUserService myUserService = annotationConfigApplicationContext.getBean("myUserService", MyUserService.class);
        List<JSONObject> userList = myUserService.queryUser();
        userList.forEach(currentRow -> {
            System.out.println(currentRow.getString("name"));
        });
    }

    public static void main(String[] args) {
        springbeantest();
    }
}

3.8引入扫描注解,配置包扫描路径

实现FactoryBean接口


定义scan注解

package mock.org.mybatis.spring.solution4;

import org.springframework.context.annotation.Import;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author kikop
 * @version 1.0
 * @project Name: mybatisspringdemo
 * @file Name: MyImportBeanDefinitionRegistrar
 * @desc 注册BeanDefinition
 * @date 2019/5/19
 * @time 10:50
 * @by IDE: IntelliJ IDEA
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(MyImportBeanDefinitionRegistrar4.class)
public @interface MyScanner4 {
    String value();
}

继承ClassPathBeanDefinitionScanner

package mock.org.mybatis.spring.solution4;

import mock.org.mybatis.spring.solution3.MyCommonMapperClazzBySqlSessionFactoryBean3;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;

import java.util.Set;

/**
 * @author kikop
 * @version 1.0
 * @project Name: mybatisspringdemo
 * @file Name: MyBeanDefinitionScanner
 * @desc 利用Spring的扫描器进行包扫描
 * @date 2019/5/19
 * @time 10:50
 * @by IDE: IntelliJ IDEA
 */
public class MyBeanDefinitionScanner4 extends ClassPathBeanDefinitionScanner {

    public MyBeanDefinitionScanner4(BeanDefinitionRegistry registry) {
        super(registry);
    }


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

    @Override
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Set<BeanDefinitionHolder> beanDefinitionHolders = super.doScan(basePackages);// spring扫描,忽略接口


        // 修改 beanDefinitionHolders进行代理
        for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
            // 得到 beandefinition
            BeanDefinition beanDefinition = beanDefinitionHolder.getBeanDefinition();
            System.out.println(beanDefinition.getBeanClassName()); //-->com.kikop.mapper.MyUserMapper

            // 1.先设置构造参数
            beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(beanDefinition.getBeanClassName());

            // 2.后修改 BeanClsName
            beanDefinition.setBeanClassName(MyCommonMapperClazzBySqlSessionFactoryBean3.class.getName());
        }
        return beanDefinitionHolders;
    }
}

实现ImportBeanDefinitionRegistrar接口

package mock.org.mybatis.spring.solution4;

import mock.org.mybatis.spring.solution3.MyBeanDefinitionScanner3;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;

import java.io.IOException;
import java.util.Map;


/**
 * @author kikop
 * @version 1.0
 * @project Name: mybatisspringdemo
 * @file Name: MyImportBeanDefinitionRegistrar
 * @desc 注册BeanDefinition
 * @date 2019/5/19
 * @time 10:50
 * @by IDE: IntelliJ IDEA
 */
public class MyImportBeanDefinitionRegistrar4 implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {

        // 1.扫描mapper接口,得到bean class
        // spring默认不扫描接口
//        String path = "com.kikop.mapper";

        Map<String, Object> annotationAttributes = annotationMetadata.getAnnotationAttributes(MyScanner4.class.getName());
        String path = (String) annotationAttributes.get("value");


        MyBeanDefinitionScanner4 myBeanDefinitionScanner = new MyBeanDefinitionScanner4(beanDefinitionRegistry);

        myBeanDefinitionScanner.addIncludeFilter(new TypeFilter() {
            @Override
            public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
//                return false;
                return true;
            }
        });
        int scan = myBeanDefinitionScanner.scan(path);
        System.out.println(scan);





    }
}

测试类

package com.kikop;


import com.alibaba.fastjson.JSONObject;
import com.kikop.service.MyUserService;
import mock.org.mybatis.spring.solution4.MyScanner4;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;


/**
 * @author kikop
 * @version 1.0
 * @project Name: mybatisspringdemo
 * @file Name: AppConfig
 * @desc SimpleSpringApplication启动类(配置类)
 * Spring与Mybatis底层源码深度分析
 * 引入扫描注解,配置包扫描路径
 * @date 2019/5/19
 * @time 10:50
 * @by IDE: IntelliJ IDEA
 */
@ComponentScan("com.kikop")
@MyScanner4("com.kikop.mapper")
public class Test4_SimpleSpringApplicationIncludeScanAnnotation {

    /**
     * 配置一个SqlSessionFactoryBean
     * 可借助 mybatis-spring:SqlSessionFactoryBean解决
     * @return
     * @throws IOException
     */
    @Bean
    public SqlSessionFactory sqlSessionFactory() throws IOException {

        InputStream resourceAsStream = Resources.getResourceAsStream("mybatisconfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        return sqlSessionFactory;
    }

    public static void springbeantest() {

        // AnnotationConfigApplicationContext实现了 BeanDefinitionRegistry
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        annotationConfigApplicationContext.register(Test4_SimpleSpringApplicationIncludeScanAnnotation.class); // 注册配置类之后


        // 1.注册配置类之后

//        引入mybatis-springjar扩展点。
//        jar执行包扫描。
//        生成mybatis的代理对象。

        // 2.启动之前

        annotationConfigApplicationContext.refresh();  // 启动之前

        MyUserService myUserService = annotationConfigApplicationContext.getBean("myUserService", MyUserService.class);
        List<JSONObject> userList = myUserService.queryUser();
        userList.forEach(currentRow -> {
            System.out.println(currentRow.getString("name"));
        });
    }

    public static void main(String[] args) {
        springbeantest();
    }


}

3.9配置一个SqlSessionFactoryBean,自动注入SqlSession

实现FactoryBean接口

package mock.org.mybatis.spring.solution5;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * @author kikop
 * @version 1.0
 * @project Name: mybatisspringdemo
 * @file Name: MyCommonFactoryBean2
 * @desc 创建代理对象(类或接口)
 * 注入sqlSession 根据扫描 beanDefinition.setAutowireMode
 * @date 2019/5/19
 * @time 10:50
 * @by IDE: IntelliJ IDEA
 */
public class MyCommonMapperClazzAutoInjectSqlSessionFactoryBean5 implements FactoryBean {

    private Class<?> mapperClazz;

    private SqlSession sqlSession;


    /**
     * 构造注入
     * @param mapperClazz
     */
    public MyCommonMapperClazzAutoInjectSqlSessionFactoryBean5(Class<?> mapperClazz) {
        System.out.println("构造注入");
        this.mapperClazz = mapperClazz;
    }

//    /**
//     * set注入注解--->todo
//     * @param sqlSessionFactory
//     */
//    @Autowired
//    public void setSqlSession(SqlSessionFactory sqlSessionFactory) {
//
//        // 加到 knownMappers
//        //         去掉,就要手动加入-->
//        //    <mappers>-->
//        //        <package name="com.kikop.mapper"></package>-->
//        //    </mappers>-->
//
//        sqlSessionFactory.getConfiguration().addMapper(mapperClazz);
//        this.sqlSession = sqlSessionFactory.openSession();
//    }

    /**
     * set注入注解--->todo
     * @param sqlSessionFactory
     */
//    @Autowired
    public void setSqlSession(SqlSessionFactory sqlSessionFactory) {

        // 加到 knownMappers
        //         去掉,就要手动加入-->
        //    <mappers>-->
        //        <package name="com.kikop.mapper"></package>-->
        //    </mappers>-->

        sqlSessionFactory.getConfiguration().addMapper(mapperClazz);
        this.sqlSession = sqlSessionFactory.openSession();
    }

    /**
     * set注入
     * @param clazz
     */
    public void setClazz(Class<?> clazz) {
        System.out.println("set注入");
        this.mapperClazz = clazz;
    }

    @Override
    public Object getObject() throws Exception {
        // 创建mapper接口的代理对象
        Object mapper = sqlSession.getMapper(mapperClazz);
        return mapper;
    }

    @Override
    public Class<?> getObjectType() {
        return mapperClazz;
    }
}

定义scan注解

package mock.org.mybatis.spring.solution5;

import mock.org.mybatis.spring.solution4.MyImportBeanDefinitionRegistrar4;
import org.springframework.context.annotation.Import;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author kikop
 * @version 1.0
 * @project Name: mybatisspringdemo
 * @file Name: MyImportBeanDefinitionRegistrar
 * @desc 注册BeanDefinition
 * @date 2019/5/19
 * @time 10:50
 * @by IDE: IntelliJ IDEA
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(MyImportBeanDefinitionRegistrar5.class)
public @interface MyScanner5 {
    String value();
}

继承ClassPathBeanDefinitionScanner

package mock.org.mybatis.spring.solution5;

import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;

import java.util.Set;

/**
 * @author kikop
 * @version 1.0
 * @project Name: mybatisspringdemo
 * @file Name: MyBeanDefinitionScanner
 * @desc 利用Spring的扫描器进行包扫描
 * @date 2019/5/19
 * @time 10:50
 * @by IDE: IntelliJ IDEA
 */
public class MyBeanDefinitionScanner5 extends ClassPathBeanDefinitionScanner {

    public MyBeanDefinitionScanner5(BeanDefinitionRegistry registry) {
        super(registry);
    }


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

    @Override
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Set<BeanDefinitionHolder> beanDefinitionHolders = super.doScan(basePackages);// spring扫描,忽略接口


        // 修改 beanDefinitionHolders进行代理
        for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
            // 得到 beandefinition
            GenericBeanDefinition beanDefinition = (GenericBeanDefinition)beanDefinitionHolder.getBeanDefinition();
            System.out.println(beanDefinition.getBeanClassName()); //-->com.kikop.mapper.MyUserMapper

            // 1.先设置构造参数
            beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(beanDefinition.getBeanClassName());

            // 2.后修改 BeanClsName
            beanDefinition.setBeanClassName(MyCommonMapperClazzAutoInjectSqlSessionFactoryBean5.class.getName());

            // 3.依赖的bean自动set注入,否则 setSqlSession:null
            beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); // 默认 no
        }
        return beanDefinitionHolders;
    }
}

实现ImportBeanDefinitionRegistrar接口

package mock.org.mybatis.spring.solution5;

import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;

import java.io.IOException;
import java.util.Map;


/**
 * @author kikop
 * @version 1.0
 * @project Name: mybatisspringdemo
 * @file Name: MyImportBeanDefinitionRegistrar
 * @desc 注册BeanDefinition
 * @date 2019/5/19
 * @time 10:50
 * @by IDE: IntelliJ IDEA
 */
public class MyImportBeanDefinitionRegistrar5 implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {

        // 1.扫描mapper接口,得到bean class
        // spring默认不扫描接口
//        String path = "com.kikop.mapper";

        Map<String, Object> annotationAttributes = annotationMetadata.getAnnotationAttributes(MyScanner5.class.getName());
        String path = (String) annotationAttributes.get("value");


        MyBeanDefinitionScanner5 myBeanDefinitionScanner = new MyBeanDefinitionScanner5(beanDefinitionRegistry);

        myBeanDefinitionScanner.addIncludeFilter(new TypeFilter() {
            @Override
            public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
//                return false;
                return true;
            }
        });
        int scan = myBeanDefinitionScanner.scan(path);
        System.out.println(scan);

    }
}

测试类

package com.kikop;


import com.alibaba.fastjson.JSONObject;
import com.kikop.service.MyUserService;
import mock.org.mybatis.spring.solution5.MyScanner5;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;


/**
 * @author kikop
 * @version 1.0
 * @project Name: mybatisspringdemo
 * @file Name: AppConfig
 * @desc SimpleSpringApplication启动类(配置类)
 * Spring与Mybatis底层源码深度分析
 * 配置一个SqlSessionFactoryBean,自动注入SqlSession
 * @date 2019/5/19
 * @time 10:50
 * @by IDE: IntelliJ IDEA
 */
@ComponentScan("com.kikop")
//@MyScanner5() // 也可不写,借用 ComponentScan
@MyScanner5("com.kikop.mapper")
public class Test5_SimpleSpringApplicationAutoSetInject {

    /**
     * 配置一个SqlSessionFactoryBean
     * 可借助 mybatis-spring:SqlSessionFactoryBean解决
     *
     * @return
     * @throws IOException
     */
    @Bean
    public SqlSessionFactory sqlSessionFactory() throws IOException {

        InputStream resourceAsStream = Resources.getResourceAsStream("mybatisconfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        return sqlSessionFactory;
    }

    public static void springbeantest() {

        // AnnotationConfigApplicationContext实现了 BeanDefinitionRegistry
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        annotationConfigApplicationContext.register(Test5_SimpleSpringApplicationAutoSetInject.class); // 注册配置类之后


        // 1.注册配置类之后

//        引入mybatis-springjar扩展点。
//        jar执行包扫描。
//        生成mybatis的代理对象。

        // 2.启动之前

        annotationConfigApplicationContext.refresh();  // 启动之前

        MyUserService myUserService = annotationConfigApplicationContext.getBean("myUserServiceXXX", MyUserService.class);
        List<JSONObject> userList = myUserService.queryUser();
        userList.forEach(currentRow -> {
            System.out.println(currentRow.getString("name"));
        });
    }

    public static void main(String[] args) {
        springbeantest();
    }
}

4面试相关

4.1 BeanFactory与ApplicationContext

参考

1 mybatis官网

https://mybatis.org/mybatis-3/getting-started.html
http://mybatis.org/spring/getting-started.html

相关文章

网友评论

      本文标题:2020-12-15_Spring与Mybatis底层facto

      本文链接:https://www.haomeiwen.com/subject/dsxwgktx.html