简介
- 使用ImportBeanDefinitionRegistrar、JDK代理、FactoryBean模拟mybatis原理
知识点
- ImportBeanDefinitionRegistrar
- JDK代理
- FactoryBean
- @interface
- mybatis的极简单的知识
代码如下 :
- UserDao.java : 使用mybatis的mapper
- ProxyTest.java : 测试类
- MyImportBeanDefinition.java : 使用 ImportBeanDefinitionRegistrar 注册bean
- MyFactoryBean.java : 实现 FactoryBean ,自定义对象的创建并交由spring管理
- MySession.java : 代理类,模拟mybatis的sqlSession
- MyMapperInvocationHandler.java : 代理实现类,使用JDK代理,实现接口的代理操作
- MyMapperScan.java : 自定义配置类,启动类增加注解,模拟mybatis的@MapperScan()
- AppConfig.java : 项目配置类
调用链
- ProxyTest(启动引用配置类)
- AppConfig(增加注解)
- MyMapperScan(注解方式被调用)
- MyImportBeanDefinition(注册beandefinition)
- MyFactoryBean(创建对象并交给spring管理)
- MySession(创建对象)
- MyMapperInvocationHandler(通过JDK代理创建代理类)
- UserDao(对此接口进行JDK代理)
UserDao
package com.proxy;
import org.apache.ibatis.annotations.Select;
import java.util.List;
import java.util.Map;
/**
* 模拟Mybatis的接口
*/
public interface UserDao {
/**
* 仅有接口,无实现类
* 此处仅以@Select做为案例
*/
@Select("select * from user")
List<Map<Object, Object>> query();
}
MySession
package com.proxy;
import java.lang.reflect.Proxy;
/**
* 代理类,模拟mybatis的sqlSession
* sqlSession.getMapper(),其实是返回了代理类
*/
public class MySession {
/**
* 调用此方法,可以实现代理类,使用JDK代理
*/
public static Object queryMapper(Class clazz) {
return Proxy.newProxyInstance(MySession.class.getClassLoader(), new Class[]{clazz}, new MyMapperInvocationHandler());
}
}
MyMapperInvocationHandler
package com.proxy;
import org.apache.ibatis.annotations.Select;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 代理实现类,使用JDK代理,实现接口的代理操作
*/
public class MyMapperInvocationHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/**
* 获取注解,此处仅以select做案例
*/
Select selectAnnotation = method.getAnnotation(Select.class);
if (selectAnnotation != null) {
/**
* 获取注解里面的值,此处不做实际连库操作
*/
String sql = selectAnnotation.value()[0];
System.err.println(" exec sql : " + sql);
}
if ("toString".equals(method.getName())) {
return proxy;
}
/**
* 此处直接返回null,实际应返回具体值
*/
return null;
}
}
MyImportBeanDefinition
package com.proxy;
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;
/**
* 使用 ImportBeanDefinitionRegistrar 注册bean
*/
public class MyImportBeanDefinition implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 生成 BeanDefinitionBuilder
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(MyFactoryBean.class);
// 获取 AbstractBeanDefinition
AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
// 给 MyFactoryBean 设置类,这里可以做成扫描包,方便起见,这里暂将类写死
// 可以参考 我另一篇博客 https://blog.youkuaiyun.com/qq_17522211/article/details/116748646
// spring[1]-使用ImportBeanDefinitionRegistrar自定义注册bean(基于源码)
beanDefinition.getPropertyValues().addPropertyValue("mapperInterface", "com.proxy.UserDao");
// 获取 beanClassName
String beanClassName = beanDefinition.getBeanClassName();
// 注册 BeanDefinition,让spring来管理
registry.registerBeanDefinition(beanClassName, beanDefinition);
}
}
MyFactoryBean
package com.proxy;
import org.springframework.beans.factory.FactoryBean;
/**
* 实现 FactoryBean ,自定义对象的创建,并交由spring管理
*/
public class MyFactoryBean implements FactoryBean {
Class mapperInterface;
/**
* 返回类的对象 : 对接口做代理后的对象
*/
@Override
public Object getObject() throws Exception {
return MySession.queryMapper(mapperInterface);
}
/**
* 返回类型
*/
@Override
public Class<?> getObjectType() {
return mapperInterface;
}
/**
* 设置类,ImportBeanDefinitionRegistrar 注册时
* 通过FactoryBean生成代理,需要将代理的接口类传过来
*/
public void setMapperInterface(Class mapperInterface) {
this.mapperInterface = mapperInterface;
}
}
MyMapperScan
package com.proxy;
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
/**
* 自定义配置类,启动类增加注解,模拟mybatis的@MapperScan()
* MyMapperScan(basePackages = "com.proxy") 即可扫描包下的类
*/
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Import(MyImportBeanDefinition.class)
public @interface MyMapperScan {
/**
* 需要扫描的包
*/
String[] basePackages() default {};
}
AppConfig
package com;
import com.beandefinition.MyMapperAutoConfig;
import com.proxy.MyMapperScan;
import org.springframework.context.annotation.ComponentScan;
/**
* 模拟mybatis的@MapperScan()
*/
@MyMapperScan(basePackages = "com.proxy")
public class AppConfig {
}
ProxyTest
package com.proxy;
import com.AppConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class ProxyTest {
public static void main(String[] args) {
/**
* JDK动态代理测试
*/
UserDao userDao = (UserDao) MySession.queryMapper(UserDao.class);
userDao.query();
/**
* spring测试,可以将类通过spring来管理
* AppConfig 添加注解 @Import(MyImportBeanDefinition.class)
*/
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
ac.getBean(UserDao.class).query();
}
}