《Java Spring框架》模拟Mybatis整合Spring
前言
为了更好的了解Spring的扩展,于是便去研究了MyBatis整合Spring的Jar代码。通过代码模拟写一个Mybatis整合Spring作为笔记留念。
代码
目录结构:
MapScan
import com.my.postprocessor.MyImportBeanDefinitionRegistrar; import org.springframework.context.annotation.Import; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) @Import(MyImportBeanDefinitionRegistrar.class) public @interface MapScan { String value() default ""; }
MyFactoryBean
import com.my.mybatis.MySqlSession; import org.springframework.beans.factory.FactoryBean; import org.springframework.stereotype.Component; /** * 猜想MyBatis为什么要通过FactoryBean来注入Spring, * 而不是直接扫描DAO接口生成Definition的时候直接将代理类也set进Definition中。 */ @Component public class MyFactoryBean implements FactoryBean { Class mapperInterface; @Override public Object getObject() throws Exception { MySqlSession mySqlSession = new MySqlSession(); Object mapper = mySqlSession.getMapper(mapperInterface); return mapper; } @Override public Class<?> getObjectType() { return mapperInterface; } public void setMapperInterface(Class mapperInterface) { this.mapperInterface = mapperInterface; } }
ClassPathMapperScanner
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.context.annotation.ClassPathBeanDefinitionScanner; import org.springframework.core.type.filter.TypeFilter; import java.util.Set; public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner { public ClassPathMapperScanner(BeanDefinitionRegistry registry) { super(registry,false); } @Override public void addIncludeFilter(TypeFilter includeFilter) { super.addIncludeFilter(includeFilter); } @Override public Set<BeanDefinitionHolder> doScan(String... basePackages) { return super.doScan(basePackages); } protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) { return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent(); } }
AccountInfoDao
import org.apache.ibatis.annotations.Select; public interface AccountInfoDao { @Select("select * from taccount") public String getAccount(); }
AccountInfoDao1
import org.apache.ibatis.annotations.Select; public interface AccountInfoDao1 { @Select("select * from taccount1") public String getAccount(); }
MySqlSession
import org.apache.ibatis.annotations.Select; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class MySqlSession { class MyInvocationHandler implements InvocationHandler { @Override public Object invoke(Object o, Method method, Object[] objects) throws Throwable { // 获取方法上的注解 Select annotation = method.getAnnotation(Select.class); System.out.println("打开数据库连接"); System.out.println("执行SQL:" + annotation.value()[0]); System.out.println("关闭数据库连接"); if(method.getName().equals("toString")){ return "toString"; } return "动态代理反馈"; } } public Object getMapper(Class clazz){ MyInvocationHandler myInvocationHandler = new MyInvocationHandler(); Object object = Proxy.newProxyInstance(MySqlSession.class.getClassLoader(), new Class[]{clazz}, myInvocationHandler); return object; } }
MyImportBeanDefinitionRegistrar
import com.my.annotation.MapScan; import com.my.bean.MyFactoryBean; import com.my.config.ClassPathMapperScanner; import com.my.dao.AccountInfoDao; import com.my.dao.AccountInfoDao1; import org.mybatis.spring.annotation.MapperScan; import org.springframework.beans.factory.config.BeanDefinitionHolder; 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.GenericBeanDefinition; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.annotation.MergedAnnotations; 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.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Set; public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { AnnotationAttributes annotations = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapScan.class.getName())); ClassPathMapperScanner classPathMapperScanner = new ClassPathMapperScanner(registry); classPathMapperScanner.addIncludeFilter((metadataReader,metadataReaderFactory) -> { return true; }); Set<BeanDefinitionHolder> beanDefinitionHolders = classPathMapperScanner.doScan((String)annotations.get("value")); Iterator<BeanDefinitionHolder> it = beanDefinitionHolders.iterator(); while (it.hasNext()) { BeanDefinitionHolder beanDefinitionHolder = it.next(); GenericBeanDefinition definition = (GenericBeanDefinition)beanDefinitionHolder.getBeanDefinition(); definition.getPropertyValues().addPropertyValue("mapperInterface",definition.getBeanClassName()); definition.setBeanClass(MyFactoryBean.class); } } }
IndexService
import com.my.dao.AccountInfoDao; import com.my.dao.AccountInfoDao1; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class IndexService { @Autowired AccountInfoDao accountInfoDao; @Autowired AccountInfoDao1 accountInfoDao1; public void test(){ System.out.println(accountInfoDao.getAccount()); System.out.println("==============================="); System.out.println(accountInfoDao1.getAccount()); } }
MyTest
import com.my.AppConfig; import com.my.service.IndexService; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class MyTest { public static void main(String[] args) { AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class); IndexService indexService = ac.getBean(IndexService.class); indexService.test(); } }
AppConfig
import com.my.annotation.MapScan; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan("com.my") @MapScan("com.my.dao") public class AppConfig { }
依赖包只需要一个即可:spring-context
运行结果:
总结
从别人的代码里面学习如何写优美的代码。
This moment will nap, you will have a dream; But this moment study,you will interpret a dream.