前言:经过不蟹的努力,终于把Mybatis和Spring结合的代码也给整合进来啦!此处应有掌声,真的,感觉自己一下子进入了另一种天地。话不多说,代码奉上 。这三段代码,就是mybatis和spring整合的核心代码了。
1. 第一步,编写一个类似与MapperFactoryBean的类用来提供Fisher接口的代理类,代码如下:
public class FisherFactoryBean<T> implements FactoryBean<T> {
private Class<T> fishInterface;
private boolean addToConfig = true;
private FishingRod rod;
public FisherFactoryBean() {
}
public FisherFactoryBean(Class<T> fishInterface) {
this.fishInterface = fishInterface;
}
public T getObject() throws Exception {
return getFishingRod().getFishinger(this.fishInterface);
}
//注入FishingFactory,并设置FishingRod
private FishingRod getFishingRod() {
if (this.rod == null) {
FishingFactory factory = new DefaultFishingerFactory();
this.rod = factory.getFishingRod();
}
return this.rod;
}
public Class<T> getObjectType() {
return this.fishInterface;
}
public boolean isSingleton() {
return true;
}
public void setMapperInterface(Class<T> fishInterface) {
this.fishInterface = fishInterface;
}
public Class<T> getMapperInterface() {
return fishInterface;
}
public void setAddToConfig(boolean addToConfig) {
this.addToConfig = addToConfig;
}
public boolean isAddToConfig() {
return addToConfig;
}
}
2. 一个类似MapperScannerConfigurer的类,用来在Bean定义完,初始化前替换Spring容器中的Fisher接口的BeanDefinitions:
@Component
public class FishingConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware{
private String basePackage = "com.demo.fisher";
private Class<? extends Annotation> annotationClass = Fisher.class;
private ResourceLoader applicationContext;
private BeanNameGenerator nameGenerator;
private Class<?> markerInterface;
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
public void setBeanName(String name) {
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public void afterPropertiesSet() throws Exception {
System.out.println("");
}
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
ClassPathFisherScanner scanner = new ClassPathFisherScanner(registry);
scanner.setMarkerInterface(this.markerInterface);
scanner.setAnnotationClass(this.annotationClass );
scanner.setResourceLoader(this.applicationContext);
scanner.setBeanNameGenerator(this.nameGenerator);
scanner.registerFilters();
scanner.scan(new String[]{this.basePackage});
}
}
注意此处用@Component来声明了,不然Spring不会扫描到这个类。
3.一个仿ClassPathMapperScanner的类,用来扫描和将Fisher接口的BeanDefinition替换为代理类
public class ClassPathFisherScanner extends ClassPathBeanDefinitionScanner {
private boolean addToConfig = true;
private Class<? extends Annotation> annotationClass;
private Class<?> markerInterface;
private FisherFactoryBean<?> fisherFactoryBean = new FisherFactoryBean<Object>();
public ClassPathFisherScanner(BeanDefinitionRegistry registry) {
super(registry, false);
}
public void setAddToConfig(boolean addToConfig) {
this.addToConfig = addToConfig;
}
public void setAnnotationClass(Class<? extends Annotation> annotationClass) {
this.annotationClass = annotationClass;
}
public void setMarkerInterface(Class<?> markerInterface) {
this.markerInterface = markerInterface;
}
public void setfisherFactoryBean(FisherFactoryBean<?> fisherFactoryBean) {
this.fisherFactoryBean = fisherFactoryBean != null ? fisherFactoryBean : new FisherFactoryBean<Object>();
}
public void registerFilters() {
boolean acceptAllInterfaces = true;
if (this.annotationClass != null) {
addIncludeFilter(new AnnotationTypeFilter(this.annotationClass));
acceptAllInterfaces = false;
}
if (this.markerInterface != null) {
addIncludeFilter(new AssignableTypeFilter(this.markerInterface) {
@Override
protected boolean matchClassName(String className) {
return false;
}
});
acceptAllInterfaces = false;
}
if (acceptAllInterfaces) {
// default include filter that accepts all classes
addIncludeFilter(new TypeFilter() {
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
return true;
}
});
}
addExcludeFilter(new TypeFilter() {
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
String className = metadataReader.getClassMetadata().getClassName();
return className.endsWith("package-info");
}
});
}
@Override
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
if (beanDefinitions.isEmpty()) {
logger.warn("No MyBatis fisher was found in '" + Arrays.toString(basePackages)
+ "' package. Please check your configuration.");
} else {
processBeanDefinitions(beanDefinitions);
}
return beanDefinitions;
}
private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
GenericBeanDefinition definition;
for (BeanDefinitionHolder holder : beanDefinitions) {
definition = (GenericBeanDefinition) holder.getBeanDefinition();
if (logger.isDebugEnabled()) {
logger.debug("Creating fisherFactoryBean with name '" + holder.getBeanName() + "' and '"
+ definition.getBeanClassName() + "' fisherInterface");
}
definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName()); // issue
// #59
definition.setBeanClass(this.fisherFactoryBean.getClass());
definition.getPropertyValues().add("addToConfig", this.addToConfig);
}
}
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
}
@Override
protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) {
if (super.checkCandidate(beanName, beanDefinition)) {
return true;
} else {
logger.warn(
"Skipping fisherFactoryBean with name '" + beanName + "' and '" + beanDefinition.getBeanClassName()
+ "' fisherInterface" + ". Bean already defined with the same name!");
return false;
}
}
}
此刻,老泪纵横啊!终于成功了!开始读Mybatis源码到现在也小半年了,一直想做这样一件事,写一套自己的Mybatis,可是技术水平不够,或者说差点什么。但今天,算是完成了第一步了啊!以后,会慢慢把我编写的Mybatis增强模块写进去。相信终有一天,我会写出和Mybatis一样牛逼的架构!