Spring 高级 工厂后处理器模拟实现-Mapper
一、源方式自动注入
package com.mangoubiubiu.show.a05; import com.alibaba.druid.pool.DruidDataSource; import com.mangoubiubiu.show.a05.component.Bean2; import com.mangoubiubiu.show.a05.mapper.Mapper1; import com.mangoubiubiu.show.a05.mapper.Mapper2; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.mapper.MapperFactoryBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import javax.sql.DataSource; @Configuration @ComponentScan("com.mangoubiubiu.show.a05.component") public class Config { @Bean public Bean1 bean1(){ return new Bean1(); } public Bean2 bean2(){ return new Bean2(); } @Bean public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){ SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); sqlSessionFactoryBean.setDataSource(dataSource); return sqlSessionFactoryBean; } @Bean(initMethod = "init") public DruidDataSource druidDataSource(){ DruidDataSource dataSource = new DruidDataSource(); dataSource.setUrl("jdbc:mysql://localhost:3306/zeal_user"); dataSource.setUsername("root"); dataSource.setPassword("root"); return dataSource; } @Bean public MapperFactoryBean<Mapper2> mapper2(SqlSessionFactory sqlSessionFactory){ MapperFactoryBean<Mapper2> factory = new MapperFactoryBean<>(Mapper2.class); factory.setSqlSessionFactory(sqlSessionFactory); return factory; } @Bean public MapperFactoryBean<Mapper1> mapper1(SqlSessionFactory sqlSessionFactory){ MapperFactoryBean<Mapper1> factory = new MapperFactoryBean<>(Mapper1.class); factory.setSqlSessionFactory(sqlSessionFactory); return factory; } }
package com.mangoubiubiu.show.a05; import com.mangoubiubiu.show.a05.component.ComponentScanPostProcessor; import lombok.extern.slf4j.Slf4j; import org.apache.catalina.JmxEnabled; import org.mybatis.spring.mapper.MapperScannerConfigurer; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.context.annotation.AnnotationBeanNameGenerator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ConfigurationClassPostProcessor; import org.springframework.context.support.GenericApplicationContext; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.MethodMetadata; import org.springframework.core.type.classreading.CachingMetadataReaderFactory; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.stereotype.Component; import java.awt.*; import java.io.IOException; import java.util.List; import java.util.Set; @Slf4j public class A05Application { private MetadataReader reader; public static void main(String[] args) throws IOException { GenericApplicationContext context = new GenericApplicationContext(); //将config注册到容器里面 context.registerBean("config",Config.class); // context.registerBean(ComponentScanPostProcessor.class); // context.registerBean(MapperScannerConfigurer.class,beanDefinition -> { // beanDefinition.getPropertyValues().add("basePackage","com.mangoubiubiu.show.a05.mapper"); // }); context.registerBean(AtBeanPostProcessor.class); //初始化容器 context.refresh(); for (String name: context.getBeanDefinitionNames()) { System.out.println(name); } context.close(); } }
发现Mapper1 Mapper2 确实被注入进来了
二、自己定义Bean后处理器将Mapper注入到容器中
package com.mangoubiubiu.show.a05; import lombok.SneakyThrows; import org.mybatis.spring.mapper.MapperFactoryBean; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; 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.BeanDefinitionRegistryPostProcessor; import org.springframework.context.annotation.AnnotationBeanNameGenerator; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.type.ClassMetadata; import org.springframework.core.type.classreading.CachingMetadataReaderFactory; import org.springframework.core.type.classreading.MetadataReader; public class MyMapperPostProcessor implements BeanDefinitionRegistryPostProcessor { @SneakyThrows @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException { PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); Resource[] resources = resolver.getResources("classpath:com/mangoubiubiu/show/a05/mapper/**/*.class"); CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory(); AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator(); for (Resource resource : resources) { MetadataReader metadataReader = factory.getMetadataReader(resource); //得到类的源信息 ClassMetadata classMetadata = metadataReader.getClassMetadata(); //如果当前类是接口 if(classMetadata.isInterface()){ AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(MapperFactoryBean.class) //加进class 的类名 .addConstructorArgValue(classMetadata.getClassName()) //设置自动装配 .setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE) .getBeanDefinition(); String beanName = generator.generateBeanName(beanDefinition, beanFactory); generator.generateBeanName(beanDefinition, beanFactory); beanFactory.registerBeanDefinition(beanName,beanDefinition); } } } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException { } }
package com.mangoubiubiu.show.a05; import com.mangoubiubiu.show.a05.component.ComponentScanPostProcessor; import lombok.extern.slf4j.Slf4j; import org.apache.catalina.JmxEnabled; import org.mybatis.spring.mapper.MapperScannerConfigurer; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.context.annotation.AnnotationBeanNameGenerator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ConfigurationClassPostProcessor; import org.springframework.context.support.GenericApplicationContext; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.MethodMetadata; import org.springframework.core.type.classreading.CachingMetadataReaderFactory; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.stereotype.Component; import java.awt.*; import java.io.IOException; import java.util.List; import java.util.Set; @Slf4j public class A05Application { private MetadataReader reader; public static void main(String[] args) throws IOException { GenericApplicationContext context = new GenericApplicationContext(); //将config注册到容器里面 context.registerBean("config",Config.class); // context.registerBean(ComponentScanPostProcessor.class); // context.registerBean(MapperScannerConfigurer.class,beanDefinition -> { // beanDefinition.getPropertyValues().add("basePackage","com.mangoubiubiu.show.a05.mapper"); // }); // context.registerBean(AtBeanPostProcessor.class); //解析bean context.registerBean(MyMapperPostProcessor.class); //初始化容器 context.refresh(); for (String name: context.getBeanDefinitionNames()) { System.out.println(name); } context.close(); } }
运行发现报错了,为啥会报错了,因为此时
这个Bean组件并没有注入到IOC容器里面,所有我们自定义的Processor自动装配失败了。
解决方案:开启我们上次写的解析Bean的 Proceesor就行啦
但是发现Mapper1 和 Mapper2 并没有注入进来,
Bean的名称是根据bean定义里面的一些信息去生成名字 而我们要注入的Mapper有2个 第一个注入后Bean名字叫mapperFactoryBean,第二个Bean注入后由于BeanDefinition里面的信息相同,生成的Bean的名字也叫mapperFactoryBean,2个相同bean名的组件,后生成的bean会把前面的bean给覆盖掉 所以这里只生成一个叫mapperFactoryBean的Bean。
三、解决方案
根据接口生成BeanDefinition就行啦
package com.mangoubiubiu.show.a05; import lombok.SneakyThrows; import org.mybatis.spring.mapper.MapperFactoryBean; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; 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.BeanDefinitionRegistryPostProcessor; import org.springframework.context.annotation.AnnotationBeanNameGenerator; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.type.ClassMetadata; import org.springframework.core.type.classreading.CachingMetadataReaderFactory; import org.springframework.core.type.classreading.MetadataReader; public class MyMapperPostProcessor implements BeanDefinitionRegistryPostProcessor { @SneakyThrows @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException { PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); Resource[] resources = resolver.getResources("classpath:com/mangoubiubiu/show/a05/mapper/**/*.class"); CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory(); AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator(); for (Resource resource : resources) { MetadataReader metadataReader = factory.getMetadataReader(resource); //得到类的源信息 ClassMetadata classMetadata = metadataReader.getClassMetadata(); //如果当前类是接口 if(classMetadata.isInterface()){ AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(MapperFactoryBean.class) //加进class 的类名 .addConstructorArgValue(classMetadata.getClassName()) //设置自动装配 .setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE) .getBeanDefinition(); //根据Mapper接口生成 beanDefinition AbstractBeanDefinition bd = BeanDefinitionBuilder.genericBeanDefinition(classMetadata.getClassName()).getBeanDefinition(); String beanName = generator.generateBeanName(bd, beanFactory); generator.generateBeanName(beanDefinition, beanFactory); beanFactory.registerBeanDefinition(beanName,beanDefinition); } } } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException { } }