build.gradle需要进入的依赖
// testImplementation(platform("org.junit:junit-bom:5.9.1"))
// testImplementation("org.junit.jupiter:junit-jupiter")
implementation("org.aspectj:aspectjweaver:1.9.7")
annotationProcessor("org.aspectj:aspectjweaver:1.9.7")
implementation("javax.annotation:javax.annotation-api:1.3.2")
annotationProcessor("javax.annotation:javax.annotation-api:1.3.2")
implementation("javax.inject:javax.inject:1")
annotationProcessor("javax.inject:javax.inject:1")
implementation(project(":spring-context"))
implementation(project(":spring-jdbc"))
implementation(project(":spring-tx"))
implementation(project(":spring-webmvc")) // mvc
implementation(project(":spring-context-support")) // freemarker
implementation("mysql:mysql-connector-java:5.1.40")
implementation("org.mybatis:mybatis:3.5.7")
implementation("org.mybatis:mybatis-spring:1.3.2")
自定义注解XiaogeScan
package com.xiaoge.springmybatis.annotation;
import com.xiaoge.springmybatis.springintegrationmybatis.XiaogeBeanDefinitionRegister;
import org.springframework.context.annotation.Import;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* TODO
*
* @author Zhang Xiao
* @since
*/
@Retention(RetentionPolicy.RUNTIME)
@Import(XiaogeBeanDefinitionRegister.class) // import注解是可以这样用的
public @interface XiaogeScan {
String value() default "";
}
定义三个mapper
package com.xiaoge.springmybatis.mapper;
import org.apache.ibatis.annotations.Select;
/**
* TODO
*
* @author Zhang Xiao
* @since
*/
public interface UserMapper {
@Select("select user")
String selectById(Integer id);
}
package com.xiaoge.springmybatis.mapper;
import org.apache.ibatis.annotations.Select;
/**
* TODO
*
* @author Zhang Xiao
* @since
*/
public interface MemberMapper {
@Select("select member")
String selectById(Integer id);
}
package com.xiaoge.springmybatis.mapper;
import org.apache.ibatis.annotations.Select;
/**
* TODO
*
* @author Zhang Xiao
* @since
*/
public interface OrderMapper {
@Select("select order")
String selectById(Integer id);
}
定义一个service
package com.xiaoge.springmybatis.service;
import com.xiaoge.springmybatis.mapper.MemberMapper;
import com.xiaoge.springmybatis.mapper.OrderMapper;
import com.xiaoge.springmybatis.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* TODO
*
* @author Zhang Xiao
* @since
*/
@Component
public class UserService {
@Autowired
private UserMapper userMapper; // 代理对象赋值给这个属性, spring属性注入, 对象
@Autowired
private OrderMapper orderMapper;
@Autowired
private MemberMapper memberMapper;
public void test() {
System.out.println(userMapper);
System.out.println(userMapper.getClass().getSimpleName());
System.out.println(orderMapper);
System.out.println(orderMapper.getClass().getSimpleName());
System.out.println(memberMapper);
System.out.println(memberMapper.getClass().getSimpleName());
userMapper.selectById(1);
orderMapper.selectById(1);
memberMapper.selectById(1);
}
}
重点整合mybatis
package com.xiaoge.springmybatis.springintegrationmybatis;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.stereotype.Component;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* TODO spring 整合 mybatis
*
* @author Zhang Xiao
* @since
*/
public class SpringIntegrationMybatis implements FactoryBean {
// todo FactoryBean 本身就是一个特殊bean
private Class mapper; // 灵活设置属性
public SpringIntegrationMybatis(Class mapper) {
this.mapper = mapper;
}
@Override
public Object getObject() throws Exception {
// mybatis 代理对象
Object o = Proxy.newProxyInstance(SpringIntegrationMybatisTwo.class.getClassLoader(), new Class[]{mapper}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (Object.class.equals(method.getDeclaringClass())) {
System.out.println(method.getName());
return method.invoke(this, args);
}
System.out.println(method.getName());
return null;
}
});
return o; // bean
}
@Override
public Class<?> getObjectType() {
return mapper;
}
}
重点怎么把扫描到的mapper生成BeanDefinition的
package com.xiaoge.springmybatis.springintegrationmybatis;
import com.xiaoge.springmybatis.annotation.XiaogeScan;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import java.beans.Introspector;
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* TODO 该类通过 import 注解导入, 它会去执行 该类下面的方法, 原因可以去看@Import注解源码
*
* @author Zhang Xiao
* @since
*/
public class XiaogeBeanDefinitionRegister implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
// 获取我们扫描注解上面的路径
Map<String, Object> annotationAttributes = importingClassMetadata.getAnnotationAttributes(XiaogeScan.class.getName());
String path = (String) annotationAttributes.get("value");
// 扫描
List<Class> mappers = new ArrayList<>();
doScan(path, mappers);
mappers.forEach(mapper -> {
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition();
AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
// 给构造方法添加参数
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(mapper); // new SpringIntegrationMybatisTwo(mapper)
// 设置类型
beanDefinition.setBeanClass(SpringIntegrationMybatis.class);
// 注册BeanDefinition (beanName是根据spring源码用到的方法生成的)
registry.registerBeanDefinition(Introspector.decapitalize(mapper.getSimpleName()), beanDefinition);
});
}
/**
* 扫描当前包下所有带@Mapper注解的接口
*/
private void doScan(String path, List<Class> mappers) {
// 获取路径
path = path.replace(".", "/");
// 获取资源路径
ClassLoader classLoader = XiaogeBeanDefinitionRegister.class.getClassLoader();
URL resource = classLoader.getResource(path);
// 拿到当前目录下面所有的文件
File files = new File(resource.getFile());
// 当前文件是不是目录
if (files.isDirectory()) {
// 获取目录下所有文件
for (File file : files.listFiles()) {
// 获取文件绝对路径
String fileName = file.getAbsolutePath();
// 获取com->.class结尾的名称
String className = fileName.substring(fileName.indexOf("com"), fileName.indexOf(".class"));
// 获取权限定类名
className = className.replace("\\", ".");
try {
// 加载class
Class<?> clazz = classLoader.loadClass(className);
mappers.add(clazz);
} catch (ClassNotFoundException e) {
}
}
}
}
}
配置类
package com.xiaoge.springmybatis;
import com.xiaoge.springmybatis.annotation.XiaogeScan;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.ComponentScan;
/**
* TODO
*
* @author Zhang Xiao
* @since
*/
@ComponentScan
@XiaogeScan("com.xiaoge.springmybatis.mapper")
public class AppConfig {
}
启动类
package com.xiaoge.springmybatis;
import com.xiaoge.springmybatis.mapper.UserMapper;
import com.xiaoge.springmybatis.service.UserService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* TODO
*
* @author Zhang Xiao
* @since
*/
public class SpringIntegrationMybatisMain {
public static void main(String[] args) {
// 创建 ApplicationContext 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = applicationContext.getBean(UserService.class);
userService.test();
System.out.println(applicationContext.getBean("userMapper"));
}
}
// 执行结果
toString
com.xiaoge.springmybatis.springintegrationmybatis.SpringIntegrationMybatisTwo$1@2aa5fe93
$Proxy11
toString
com.xiaoge.springmybatis.springintegrationmybatis.SpringIntegrationMybatisTwo$1@5c1a8622
$Proxy12
toString
com.xiaoge.springmybatis.springintegrationmybatis.SpringIntegrationMybatisTwo$1@5ad851c9
$Proxy13
selectById
selectById
selectById
toString
com.xiaoge.springmybatis.springintegrationmybatis.SpringIntegrationMybatisTwo$1@2aa5fe93
先通过MapperScan找到对应的MapperScannerRegistrar
主要看这个类的这个方法registerBeanDefinitions
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 获取MapperScan注解相关信息, 就是MapperScan里面我们会配置路径什么啊等
AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
// 获取spring扫描器
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
// this check is needed in Spring 3.1
if (resourceLoader != null) {
scanner.setResourceLoader(resourceLoader);
}
// 解析MapperScan annotationClass 属性
Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
if (!Annotation.class.equals(annotationClass)) {
scanner.setAnnotationClass(annotationClass);
}
// 解析MapperScan markerInterface 属性
Class<?> markerInterface = annoAttrs.getClass("markerInterface");
if (!Class.class.equals(markerInterface)) {
scanner.setMarkerInterface(markerInterface);
}
// 解析MapperScan nameGenerator 属性
Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
if (!BeanNameGenerator.class.equals(generatorClass)) {
scanner.setBeanNameGenerator(BeanUtils.instantiateClass(generatorClass));
}
// 解析MapperScan factoryBean 属性
Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
scanner.setMapperFactoryBean(BeanUtils.instantiateClass(mapperFactoryBeanClass));
}
// 解析MapperScan sqlSessionTemplateRef 属性
scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef"));
// 解析MapperScan sqlSessionFactoryRef 属性
scanner.setSqlSessionFactoryBeanName(annoAttrs.getString("sqlSessionFactoryRef"));
// 添加扫描包路径
List<String> basePackages = new ArrayList<String>();
for (String pkg : annoAttrs.getStringArray("value")) {
if (StringUtils.hasText(pkg)) {
basePackages.add(pkg);
}
}
// 添加扫描包路径
for (String pkg : annoAttrs.getStringArray("basePackages")) {
if (StringUtils.hasText(pkg)) {
basePackages.add(pkg);
}
}
// 添加class权限定类名
for (Class<?> clazz : annoAttrs.getClassArray("basePackageClasses")) {
basePackages.add(ClassUtils.getPackageName(clazz));
}
// 添加一些过滤器, 因为spring扫描到了也不一定注册到BeanDefinitionMap中它还需要通过过滤器条件
scanner.registerFilters();
scanner.doScan(StringUtils.toStringArray(basePackages));
}
@Override
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
// 扫描该包, 拿到是所有的BeanDefinition
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
if (beanDefinitions.isEmpty()) {
logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.");
} else {
processBeanDefinitions(beanDefinitions);
}
return beanDefinitions;
}
private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
GenericBeanDefinition definition;
// 循环beanDefinitions
for (BeanDefinitionHolder holder : beanDefinitions) {
// 拿到对应的beanDefinitions
definition = (GenericBeanDefinition) holder.getBeanDefinition();
if (logger.isDebugEnabled()) {
logger.debug("Creating MapperFactoryBean with name '" + holder.getBeanName()
+ "' and '" + definition.getBeanClassName() + "' mapperInterface");
}
// 给beanDefinition设置相关属性
definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName());
// 设置bean类型
definition.setBeanClass(this.mapperFactoryBean.getClass());
definition.getPropertyValues().add("addToConfig", this.addToConfig);
boolean explicitFactoryUsed = false;
if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {
definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
explicitFactoryUsed = true;
} else if (this.sqlSessionFactory != null) {
definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);
explicitFactoryUsed = true;
}
if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {
if (explicitFactoryUsed) {
logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
}
definition.getPropertyValues().add("sqlSessionTemplate", new RuntimeBeanReference(this.sqlSessionTemplateBeanName));
explicitFactoryUsed = true;
} else if (this.sqlSessionTemplate != null) {
if (explicitFactoryUsed) {
logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
}
definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
explicitFactoryUsed = true;
}
if (!explicitFactoryUsed) {
if (logger.isDebugEnabled()) {
logger.debug("Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
}
// 设置它的依赖注入类型
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
}
}
}
package org.mybatis.spring.mapper;
import static org.springframework.util.Assert.notNull;
import org.apache.ibatis.executor.ErrorContext;
import org.apache.ibatis.session.Configuration;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import org.springframework.beans.factory.FactoryBean;
/**
* 可以看到它跟我们写的那个差不多, 都是实现了FactoryBean
* mapper都是class类型 private Class mapperInterface;
* 看getObject方法getMapper它是怎么代理mapper的
*/
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
private Class<T> mapperInterface;
private boolean addToConfig = true;
public MapperFactoryBean() {
//intentionally empty
}
public MapperFactoryBean(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
/**
* {@inheritDoc}
*/
@Override
protected void checkDaoConfig() {
super.checkDaoConfig();
notNull(this.mapperInterface, "Property 'mapperInterface' is required");
Configuration configuration = getSqlSession().getConfiguration();
if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
try {
configuration.addMapper(this.mapperInterface);
} catch (Exception e) {
logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", e);
throw new IllegalArgumentException(e);
} finally {
ErrorContext.instance().reset();
}
}
}
/**
* {@inheritDoc}
*/
@Override
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}
/**
* {@inheritDoc}
*/
@Override
public Class<T> getObjectType() {
return this.mapperInterface;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isSingleton() {
return true;
}
//------------- mutators --------------
/**
* Sets the mapper interface of the MyBatis mapper
*
* @param mapperInterface class of the interface
*/
public void setMapperInterface(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
/**
* Return the mapper interface of the MyBatis mapper
*
* @return class of the interface
*/
public Class<T> getMapperInterface() {
return mapperInterface;
}
/**
* If addToConfig is false the mapper will not be added to MyBatis. This means
* it must have been included in mybatis-config.xml.
*
* If it is true, the mapper will be added to MyBatis in the case it is not already
* registered.
*
* By default addToCofig is true.
*
* @param addToConfig
*/
public void setAddToConfig(boolean addToConfig) {
this.addToConfig = addToConfig;
}
/**
* Return the flag for addition into MyBatis config.
*
* @return true if the mapper will be added to MyBatis in the case it is not already
* registered.
*/
public boolean isAddToConfig() {
return addToConfig;
}
}
@Override
public <T> T getMapper(Class<T> type) {
return configuration.getMapper(type, this);
}
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return mapperRegistry.getMapper(type, sqlSession);
}
这里就用了动态代理
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}