Spring--FactoryBean 以你之姓@ 2022-12-26 07:29 139阅读 0赞 原文网址:[Spring--FactoryBean\_IT利刃出鞘的博客-CSDN博客][Spring--FactoryBean_IT_-CSDN] # 其他网址 # > [Spring高级--BeanFactory\_feiying0canglang的博客-CSDN博客][Spring_--BeanFactory_feiying0canglang_-CSDN] > [FactoryBean简介以及Mybatis-Spring应用][FactoryBean_Mybatis-Spring] > [Spring中FactoryBean的使用\_goodluckwj的博客-CSDN博客][Spring_FactoryBean_goodluckwj_-CSDN] > [spring之手写mybatis-spring\_yangyanping20108的博客-CSDN博客][spring_mybatis-spring_yangyanping20108_-CSDN] # 简介 # **FactoryBean是干什么的?** > 可以通过一个FactoryBean来生产一个对象,可以获取这个对象的类型以及这个对象是不是单例。 > > 在某些情况下,实例化Bean过程比较复杂,若按照传统的方式,则需要在中提供大量的配置信息,不够灵活,这时采用编码的方式能得到一个简单的方案。Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑。FactoryBean接口在Spring中占重要地位,Spring自身就提供了70多个FactoryBean的实现。它们隐藏了实例化一些复杂Bean的细节,给上层应用带来了便利。 > > 从Spring 3.0 开始, FactoryBean开始支持泛型,即接口声明改为FactoryBean 的形式。 > > 源码: > > public interface FactoryBean<T> { > String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType"; > > @Nullable > T getObject() throws Exception; > > @Nullable > Class<?> getObjectType(); > > default boolean isSingleton() { > return true; > } > } **普通bean与FactoryBean** > Spring 容器中有两种bean:普通bean和工厂bean。 > > **普通bean:**通过反射实例化被标记为bean的类。例:@Component指定的类,的class属性指定的实现类。 > > **FactoryBean:**其返回的对象不是指定类的一个实例,而是FactoryBean\#getObject方法返回的对象。若想获取FactoryBean本身,要在bean的名称添加前缀&来获取FactoryBean对象本身(applicationContext.getBean("&" + beanName))。 **FactoryBean不遵循Spring的生命周期** > 作者的想法是,正是因为Spring的作者想要放权给使用者,让使用者自己实现创建一个bean的逻辑,所以Spring并不会过多的插手该Bean的实例化过程,使得一个Bean的实例化完全由使用者本人去实现。 > > 这个类并不会像普通bean那样在Spring容器初始化时进行实例化,而是类似于**懒加载**,在获取时才进行创建和返回。至于是不是单例,要取决于isSingleton()方法的返回值。 > > 当然,这个创建出来的bean也会被缓存,AOP等逻辑也会对该类生效,当然这都是后话。 # 简单示例 # **公共部分** > **FactoryBean实现类** > > package com.example.tmp; > > import lombok.AllArgsConstructor; > import org.springframework.beans.factory.FactoryBean; > > @AllArgsConstructor > public class MyFactoryBean implements FactoryBean { > private String myBeanName; > > @Override > public Object getObject() throws Exception { > MyBean myBean = new MyBean(); > myBean.setName(myBeanName); > return myBean; > } > > @Override > public Class<?> getObjectType() { > return MyBean.class; > } > } > **bean实体类** > > package com.example.tmp; > > import lombok.Data; > > @Data > public class MyBean { > private Integer id; > private String name; > } **注册多个FactoryBean** > **配置类** > > package com.example.tmp; > > import org.springframework.context.annotation.Bean; > import org.springframework.context.annotation.Configuration; > > @Configuration > public class MyConfig { > @Bean > public MyFactoryBean getMyBean() { > return new MyFactoryBean("Tony"); > } > } > **controller** > > package com.example.controller; > > import com.example.tmp.MyBean; > import org.springframework.beans.factory.annotation.Autowired; > import org.springframework.web.bind.annotation.GetMapping; > import org.springframework.web.bind.annotation.RestController; > > @RestController > public class HelloController { > @Autowired > MyBean myBean; > > @GetMapping("/test1") > public String test1() { > System.out.println(myBean.getName()); > return "test1 success"; > } > > } > **测试** > > 访问:[http://localhost:8080/test1][http_localhost_8080_test1] > > 后台结果: > > Tony **注册多个FactoryBean** > **配置类** > > package com.example.tmp; > > import org.springframework.context.annotation.Bean; > import org.springframework.context.annotation.Configuration; > > @Configuration > public class MyConfig { > @Bean("bean1") > public MyFactoryBean getMyBean1() { > return new MyFactoryBean("Tony"); > } > > @Bean("bean2") > public MyFactoryBean getMyBean2() { > return new MyFactoryBean("Pepper"); > } > } > **controller** > > package com.example.controller; > > import com.example.tmp.MyBean; > import org.springframework.beans.factory.annotation.Autowired; > import org.springframework.beans.factory.annotation.Qualifier; > import org.springframework.web.bind.annotation.GetMapping; > import org.springframework.web.bind.annotation.RestController; > > @RestController > public class HelloController { > @Autowired > @Qualifier("bean2") > MyBean myBean; > > @GetMapping("/test1") > public String test1() { > System.out.println(myBean.getName()); > return "test1 success"; > } > > } > **测试** > > 访问:[http://localhost:8080/test1][http_localhost_8080_test1] > > 后台结果: > > Pepper # 实例分析(Mybatis) # **其他网址** > [【Mybatis源码】Mybatis如何为mapper接口生成代理对象--CSDN博客][Mybatis_Mybatis_mapper_--CSDN] > > [二、MyBatis Mapper Bean初始化深度解析 - 奋斗人生 - OSCHINA - 中文开源技术交流社区][MyBatis Mapper Bean_ - _ - OSCHINA -] > [FactoryBean简介以及Mybatis-Spring应用][FactoryBean_Mybatis-Spring] > [带你跳出源码地狱,从原理上理解MyBatis对Spring源码的扩展实现 - 知乎][MyBatis_Spring_ -] **简介** > 本文分析的版本:mybatis-spring-2.0.4.jar、spring-framework-5.2.7.RELEASE ## 总体流程 ## **初始化** > 1. 在配置类标注@MapperScan("Mapper接口所在包路径") > > 1. @MapperScan上边有:@Import(MapperScannerRegistrar.class)。向Spring注入此类。 > 2. 创建Mapper扫描器的配置器(MapperScannerConfigurer) > > 1. MapperScannerRegistrar类实现了ImportBeanDefinitionRegistrar,会被Spring自动回调此接口的**registerBeanDefinitions**方法。 > > 1. MapperScannerRegistrar\#registerBeanDefinitions方法 > > 1. 构建MapperScannerConfigurer并注册进Spring容器。 > 3. 创建扫描器,调用其scan方法。 > > 1. MapperScannerConfigurer实现了BeanDefinitionRegistryPostProcessor接口,会被Spring自动回调此接口的**postProcessBeanDefinitionRegistry**方法。 > > 1. postProcessBeanDefinitionRegistry方法: > > 1. 创建一个自定义的扫描器:ClassPathMapperScanner(继承自Spring的ClassPathBeanDefinitionScanner),调用其scan方法,即:ClassPathMapperScanner\#scan > 2. ClassPathMapperScanner\#scan > > 1. 此方法未覆写,是调用父类(ClassPathBeanDefinitionScanner)的实现 > > 1. 即:**ClassPathBeanDefinitionScanner\#scan** > 2. 调用到:ClassPathBeanDefinitionScanner\#doScan > > 1. 此方法被ClassPathMapperScanner覆写,所以调用到:ClassPathMapperScanner\#doScan > 4. **扫描你指定的包路径下的所有Mapper接口,并转换为BeanDefinition** > > 1. ClassPathMapperScanner\#doScan > > 1. ClassPathMapperScanner\#processBeanDefinitions > > 1. **扫描你指定的包路径下的所有Mapper接口,并转换为BeanDefinition**。 > 2. 设置每一个BeanDefinition的BeanClass为:**MapperFactoryBean.class**(实现FactoryBean接口) > > 1. 之后实例化时会调用这个FactoryBean的getObject()方法来构建一个代理Mapper对象。这就是将map接口转变成一个对象交给Spring管理的关键。 > 3. 通过definition.getPropertyValues().add()方法,传入该BeanDefinition代表的接口。 > 4. 将所有的BeanDefinition通过上边步骤设置之后,全部注册到BeanFactory中,由BeanFactory对这些FactoryBean进行管理。 > 5. 注入时,实例化Mapper的代理类(refresh时,完成对注入对象的实例化) > > 1. MapperFactoryBean\#getObject返回Mapper的代理类:MapperProxy.class。 > 2. MapperProxy.class里有invoke方法,使用时会走这个方法。 **实例化步骤** > 1. 在使用或者获取这些bean的时候,Spring首先获取你要使用的接口类型。 > 2. 遍历当前容器内所有的bean逐个对比,当有匹配的直接返回。但是,因为Mapper接口还并没有被实例化,所以没有找到,所以在遍历到FactoryBean的时候,会调用getObjectType方法,将返回值与你要使用的接口类型作比对。 > 3. 当 FactoryBean的返回类型匹配的时候,Spring会调用FactoryBean的getObject方法将对象创建出来。 > 4. 创建过程中,通过之前传入的接口,做jdk动态代理,完成MyBatis的代理逻辑。 > 5. 对象创建完成后,通过isSingleton方法的返回值判断,如果是单例对象,就将该对象缓存起来。并返回。 ## 1.配置类标注@MapperScan("XXX") ## ## 2.创建MapperScannerConfigurer ## 对应方法:MapperScannerRegistrar\#registerBeanDefinitions **概述** > 构建类型为MapperScannerConfigurer的BeanDefinition并注册进Spring容器。 **流程** > refresh() //AbstractApplicationContext > invokeBeanFactoryPostProcessors(beanFactory); //AbstractApplicationContext > invokeBeanFactoryPostProcessors(beanFactory, this.getBeanFactoryPostProcessors()); //PostProcessorRegistrationDelegate > invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); //PostProcessorRegistrationDelegate > postProcessor.postProcessBeanDefinitionRegistry(registry); //PostProcessorRegistrationDelegate > processConfigBeanDefinitions(registry); //ConfigurationClassPostProcessor.class > ...... > registerBeanDefinitions //MapperScannerRegistrar > > void registerBeanDefinitions(AnnotationMetadata annoMeta, AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry, String beanName) { > BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class); > builder.addPropertyValue("processPropertyPlaceHolders", true); > Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass"); > if (!Annotation.class.equals(annotationClass)) { > builder.addPropertyValue("annotationClass", annotationClass); > } > > Class<?> markerInterface = annoAttrs.getClass("markerInterface"); > if (!Class.class.equals(markerInterface)) { > builder.addPropertyValue("markerInterface", markerInterface); > } > > Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator"); > if (!BeanNameGenerator.class.equals(generatorClass)) { > builder.addPropertyValue("nameGenerator", BeanUtils.instantiateClass(generatorClass)); > } > > Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean"); > if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) { > builder.addPropertyValue("mapperFactoryBeanClass", mapperFactoryBeanClass); > } > > String sqlSessionTemplateRef = annoAttrs.getString("sqlSessionTemplateRef"); > if (StringUtils.hasText(sqlSessionTemplateRef)) { > builder.addPropertyValue("sqlSessionTemplateBeanName", annoAttrs.getString("sqlSessionTemplateRef")); > } > > String sqlSessionFactoryRef = annoAttrs.getString("sqlSessionFactoryRef"); > if (StringUtils.hasText(sqlSessionFactoryRef)) { > builder.addPropertyValue("sqlSessionFactoryBeanName", annoAttrs.getString("sqlSessionFactoryRef")); > } > > List<String> basePackages = new ArrayList(); > basePackages.addAll((Collection)Arrays.stream(annoAttrs.getStringArray("value")).filter(StringUtils::hasText).collect(Collectors.toList())); > basePackages.addAll((Collection)Arrays.stream(annoAttrs.getStringArray("basePackages")).filter(StringUtils::hasText).collect(Collectors.toList())); > basePackages.addAll((Collection)Arrays.stream(annoAttrs.getClassArray("basePackageClasses")).map(ClassUtils::getPackageName).collect(Collectors.toList())); > if (basePackages.isEmpty()) { > basePackages.add(getDefaultBasePackage(annoMeta)); > } > > String lazyInitialization = annoAttrs.getString("lazyInitialization"); > if (StringUtils.hasText(lazyInitialization)) { > builder.addPropertyValue("lazyInitialization", lazyInitialization); > } > > builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(basePackages)); > registry.registerBeanDefinition(beanName, builder.getBeanDefinition()); > } ## 3.**扫描Mapper接口,转为BeanDefinition** ## 对应方法:MapperScannerConfigurer\#postProcessBeanDefinitionRegistry **概述** > 1. 创建一个自定义的扫描器ClassPathMapperScanner(继承自Spring的ClassPathBeanDefinitionScanner),它扫描你传入的包路径下的所有的接口,并转换为BeanDefinition > 2. 遍历上一步转化的BeanDefinition,修改他们的BeanClass为MapperFactoryBean类(实现FactoryBean接口),为后面的设置动态代理打下基础。 **流程** > **调用到本方法的流程** > > refresh() //AbstractApplicationContext > invokeBeanFactoryPostProcessors(beanFactory); //AbstractApplicationContext > //PostProcessorRegistrationDelegate > invokeBeanFactoryPostProcessors(beanFactory, this.getBeanFactoryPostProcessors()); > invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); //PostProcessorRegistrationDelegate > postProcessor.postProcessBeanDefinitionRegistry(registry); //PostProcessorRegistrationDelegate > postProcessBeanDefinitionRegistry //MapperScannerConfigurer.class > postProcessBeanDefinitionRegistry //MapperScannerConfigurer > scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ",; \\t\\n")); //MapperScannerConfigurer > scan(String... basePackages) //ClassPathBeanDefinitionScanner > doScan(basePackages); //ClassPathBeanDefinitionScanner > postProcessBeanDefinition((AbstractBeanDefinition)candidate, beanName); //ClassPathBeanDefinitionScanner > definition.setBeanClass(this.mapperFactoryBeanClass); //ClassPathBeanDefinitionScanner > > 这里的this.mapperFactoryBeanClass就是:MapperFactoryBean。 ## 4.注入时:创建Mapper的代理类 ## **概述** > 一般情况下,我们Controller会使用@Autowired注入Service,而Service会默认注入Mapper,此时就会 > > MapperFactoryBean\#getObject返回Mapper的代理类:MapperProxy.class。 > > MapperProxy.class里有invoke方法,使用时会走这个方法。 **流程** > refresh() //AbstractApplicationContext > finishBeanFactoryInitialization(beanFactory); //AbstractApplicationContext > beanFactory.preInstantiateSingletons(); //DefaultListableBeanFactory > getBean() //DefaultListableBeanFactory > ...... > getObject() //MapperFactoryBean.class > this.getSqlSession().getMapper(this.mapperInterface); //MapperFactoryBean.class > ...... > getMapper(Class type, SqlSession sqlSession) //MapperRegistry.class > getConfiguration().getMapper(type, this) //SqlSessionTemplate.class > // mybatisMapperRegistry为MybatisMapperRegistry类型 > mybatisMapperRegistry.getMapper(type, sqlSession); // MybatisConfiguration.class > getMapper(Class type, SqlSession sqlSession) //MybatisMapperRegistry.class > MybatisMapperRegistry继承MapperRegistry > > MybatisMapperRegistry\#getMapper具体如下: > > getMapper(Class type, SqlSession sqlSession) //MybatisMapperRegistry.class > mapperProxyFactory.newInstance(sqlSession) //MybatisMapperRegistry.class > newInstance(SqlSession sqlSession) // MybatisMapperProxyFactory.class > // MybatisMapperProxyFactory.class(下边所有代码都在这里) > MapperProxy mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache); > newInstance(mapperProxy); > Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class\[\]\{this.mapperInterface\}, mapperProxy); > MapperProxy > > public class MapperProxy<T> implements InvocationHandler, Serializable { > private static final long serialVersionUID = -4724728412955527868L; > private static final int ALLOWED_MODES = 15; > private static final Constructor<Lookup> lookupConstructor; > private static final Method privateLookupInMethod; > private final SqlSession sqlSession; > private final Class<T> mapperInterface; > private final Map<Method, MapperProxy.MapperMethodInvoker> methodCache; > > public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperProxy.MapperMethodInvoker> methodCache) { > this.sqlSession = sqlSession; > this.mapperInterface = mapperInterface; > this.methodCache = methodCache; > } > > public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { > try { > return Object.class.equals(method.getDeclaringClass()) > ? method.invoke(this, args) > : this.cachedInvoker(method).invoke(proxy, method, args, this.sqlSession); > } catch (Throwable var5) { > throw ExceptionUtil.unwrapThrowable(var5); > } > } > // 省略其他代码 > } ## 5.调用 ## **概述** > 我们一般在使用时,直接@Autowired注入一个Mapper接口,然后调用方法即可。 > > **注入Mapper:** > > 上边“注入时:创建Mapper的代理类”,已经说明了,注入时会返回包含MapperProxy的代理。 > > **调用Mapper方法:** > > 会调用到MapperProxy\#invoke > > 1. 创建实例来执行方法。(有DefaultMethodInvoker、PlainMethodInvoker两种类) > > 1. 调用MapperMethod\#execute方法 **流程** > invoke //MapperProxy > Object.class.equals(method.getDeclaringClass()) ? method.invoke(this, args) : this.cachedInvoker(method).invoke(proxy, method, args, this.sqlSession); > > **追踪后者** > > cachedInvoker(Method method) //MapperProxy > new MapperProxy.PlainMethodInvoker(new MapperMethod(this.mapperInterface, method, this.sqlSession.getConfiguration())); > > 它再调用invoke(proxy, method, args, this.sqlSession) > > invoke(Object proxy, Method method, Object\[\] args, SqlSession sqlSession) //MapperProxy.PlainMethodInvoker > mapperMethod.execute(sqlSession, args); //MapperProxy.PlainMethodInvoker > execute(SqlSession sqlSession, Object\[\] args) //MapperMethod > > public Object execute(SqlSession sqlSession, Object[] args) { > Object result; > Object param; > switch(this.command.getType()) { > case INSERT: > param = this.method.convertArgsToSqlCommandParam(args); > result = this.rowCountResult(sqlSession.insert(this.command.getName(), param)); > break; > case UPDATE: > param = this.method.convertArgsToSqlCommandParam(args); > result = this.rowCountResult(sqlSession.update(this.command.getName(), param)); > break; > case DELETE: > param = this.method.convertArgsToSqlCommandParam(args); > result = this.rowCountResult(sqlSession.delete(this.command.getName(), param)); > break; > case SELECT: > if (this.method.returnsVoid() && this.method.hasResultHandler()) { > this.executeWithResultHandler(sqlSession, args); > result = null; > } else if (this.method.returnsMany()) { > result = this.executeForMany(sqlSession, args); > } else if (this.method.returnsMap()) { > result = this.executeForMap(sqlSession, args); > } else if (this.method.returnsCursor()) { > result = this.executeForCursor(sqlSession, args); > } else { > param = this.method.convertArgsToSqlCommandParam(args); > result = sqlSession.selectOne(this.command.getName(), param); > if (this.method.returnsOptional() && (result == null || !this.method.getReturnType().equals(result.getClass()))) { > result = Optional.ofNullable(result); > } > } > break; > case FLUSH: > result = sqlSession.flushStatements(); > break; > default: > throw new BindingException("Unknown execution method for: " + this.command.getName()); > } > > if (result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) { > throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ")."); > } else { > return result; > } > } [Spring--FactoryBean_IT_-CSDN]: https://knife.blog.csdn.net/article/details/110549188 [Spring_--BeanFactory_feiying0canglang_-CSDN]: https://blog.csdn.net/feiying0canglang/article/details/114884439 [FactoryBean_Mybatis-Spring]: https://juejin.cn/post/6844903878949863431 [Spring_FactoryBean_goodluckwj_-CSDN]: https://blog.csdn.net/qq_35634181/article/details/104499791 [spring_mybatis-spring_yangyanping20108_-CSDN]: https://blog.csdn.net/yangyanping20108/article/details/108719338 [http_localhost_8080_test1]: http://localhost:8080/test1 [Mybatis_Mybatis_mapper_--CSDN]: https://blog.csdn.net/a1036645146/article/details/112359624 [MyBatis Mapper Bean_ - _ - OSCHINA -]: https://my.oschina.net/yangjianzhou/blog/3023505 [MyBatis_Spring_ -]: https://zhuanlan.zhihu.com/p/250073545
还没有评论,来说两句吧...