2020-12-15_Spring与Mybatis底层factoryBean源码深度分析笔记

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,045评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,114评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,120评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,902评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,828评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,132评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,590评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,258评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,408评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,335评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,385评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,068评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,660评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,747评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,967评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,406评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,970评论 2 341

推荐阅读更多精彩内容