Spring与Mybatis底层factoryBean源码深度分析笔记
1概述
本系列知识要点如下,主要是借助FacoryBean不断演化Bean的注入过程:
- BeanDefinition定义的几种方式概述
- 快速开始
- 借助 factoryBean接口把普通pojo类生成 bean
- 借助 factoryBean接口把mapper接口生成 bean
- 借助 factoryBean接口把mapper接口生成 bean应用1之refresh之前
- 借助 factoryBean接口把mapper接口生成 bean应用2之实现MyImportBeanDefinitionRegistrar1接口
- 借助 factoryBean接口把mapper接口生成 bean之实现MyImportBeanDefinitionRegistrar2接口硬编码扫描包
- 配置一个SqlSessionFactoryBean,手动注入SqlSession
- 引入扫描注解,配置包扫描路径
- 配置一个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里面写&时,需要转义 &-->
<!--2.需要开启多行执行功能, allowMultiQueries=true-->
<!--<property name="url" value="jdbc:mysql://localhost:3306/mybatis?userUnicode=true&characterEncoding=UTF-8&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&characterEncoding=UTF-8&allowMultiQueries=true&autoReconnect=true&failOverReadOnly=false"
#jdbc:mysql://localhost:3306/mybatis?userUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC&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
网友评论