如果看过我上一篇的人都知道我虽然实现了自己手写Mybatis底层源码,并且注入到了Spring的ioc容器中也是可以用的,Spring底层默认调用的是我们自己手写的Mybatis底层代码,但是这里是由一个问题的就是我们只能一个一个dao层接口注入,如果一旦多了就比较麻烦了,下面我将手写一种批量导入dao层接口的方法
具体代码如下
dao层接口
主入口
public class SpringDome {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(SZConfiguration.class);
ServiceImpl bean = applicationContext.getBean(ServiceImpl.class);
bean.query();
}
}
service
@Service
public class ServiceImpl {
@Autowired
UserMapper mapper;
@Autowired
Adminmapper adminmapper;
public void query(){
mapper.selectAllUser();
adminmapper.selectAllUser();
}
}
spring主配置类
@Configuration
@ComponentScan("com.ssm.proxy")
@SZScan(value = "com.ssm.dao")
public class SZConfiguration {
}
在这里我自己写了一个注解,就相当一@MapperScan注解作用是一样的
@Retention(RetentionPolicy.RUNTIME)
@Import(SZBeanDefinitionRegistry.class)
public @interface SZScan {
String[] value() default {};
}
FactoryBean 需要注意的是在这里SZFactoryBean就相当于MapperFactoryBean。作用就是生成一个dao层接口的代理类并注入到Sprig容器中,在这里如果想要生成的代理类生效就必须让SZFactoryBean生效,你或许会问我为什么不加spring的注解让他生效,如果加上注解的话那么这时候mapperinterface这个属性的参数你怎么传呢?
public class SZFactoryBean implements FactoryBean {
private Class mapperinterface;
public void setMapperinterface(Class mapperinterface) {
this.mapperinterface = mapperinterface;
}
@Override
public Object getObject() throws Exception {
Object mapper = SZSession.getMapper(mapperinterface);
return mapper;
}
@Override
public Class<?> getObjectType() {
return mapperinterface;
}
}
解决办法
public class SZBeanDefinitionRegistry implements ImportBeanDefinitionRegistrar {
private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
try {
AnnotationAttributes metadata=AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(SZScan.class.getName()));
List<String> list=new ArrayList<>();
for (String value : metadata.getStringArray("value")) {
if(StringUtils.hasText(value)){
list.add(value);
}
}
//我上面获取list中的数据是 com.ssm.dao 也就是我在Spring主配置类中加的@SZScan中
//的value值
//下面通过反射获取包中所有的接口也就是com.ssm.dao中的所有接口
Set<Class> set=null;
for (String em : list) {
set=this.doScan(em);
}
for (Class aClass : set) {
//循环获取到的包中所有的接口,使用spring的扩展对bean进行初始化
//在这里需要注意的是spring在初始化的时候不是根据你的类初始化的
//而是根据你的每个类对应的每一个BeanDefinition来进行初始化的
BeanDefinitionBuilder beanDefinitionBuilder=BeanDefinitionBuilder.genericBeanDefinition(SZFactoryBean.class);
AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
propertyValues.add("mapperinterface",aClass.getName());
registry.registerBeanDefinition(aClass.getSimpleName(),beanDefinition);
}
}
catch (Exception e){
}
}
public Set<Class> doScan(String basePackage) {
Set<Class> classes = new HashSet<Class>();
try {
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
+ org.springframework.util.ClassUtils
.convertClassNameToResourcePath(SystemPropertyUtils
.resolvePlaceholders(basePackage))
+ "/**/*.class";
Resource[] resources = this.resourcePatternResolver
.getResources(packageSearchPath);
for (int i = 0; i < resources.length; i++) {
Resource resource = resources[i];
if (resource.isReadable()) {
MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
try {
classes.add(Class.forName(metadataReader
.getClassMetadata().getClassName()));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
} catch (IOException ex) {
throw new BeanDefinitionStoreException(
"I/O failure during classpath scanning", ex);
}
return classes;
}
}
JDk动态代理生成dao层接口代理类
public class SZSession {
public static Object getMapper(Class clazz){
Class[] classz=new Class[]{clazz};
Object object=Proxy.newProxyInstance(clazz.getClassLoader(),classz,new SZInvocationHandler());
return object;
}
}
public class SZInvocationHandler implements InvocationHandler
{
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("proxy============="+proxy.getClass().getName());
Select annotation = method.getAnnotation(Select.class);
String sql = annotation.value()[0];
System.out.println(sql);
/* Class.forName("com.mysql.jdbc.Driver");
Connection root = DriverManager.getConnection("jdbc:mysql://localhost:3306/stu", "root", "123");
PreparedStatement preparedStatement = root.prepareStatement(sql);
ResultSet resultSet = preparedStatement.executeQuery();
List<User> list=new ArrayList<>();
while (resultSet.next()){
User user=new User();
user.setId(resultSet.getString("id"));
user.setUsername(resultSet.getString("username"));
user.setPassword(resultSet.getString("password"));
list.add(user);
}
System.out.println(list);*/
return null;
}
}
执行结果 可以看到我全部获取到了dao层接口的sql语句,实现的
proxy=============com.sun.proxy.$Proxy14
select * from user
proxy=============com.sun.proxy.$Proxy15
select * from tem
总结 : 上述代码给大家展示了spring和mybatis底层是如何进行整合的还有就是@MapperScan大概的工作流程以及mybatis底层是如何生成接口的代理类的,希望对大家理解mybatis和Spring整合有一定帮助