spring(二)-----------如何注入bean

我们从第三方框架mybatis为引,看看如何往spring中注入一个bean

1、纯mybatis开发生成一个mapper对象

如果不使用spring的情况下,mybatis想生成一个mapper对象大概需要做下面的操作:

假设我们有了一个TMapper接口,此时获取该mapper对象

SqlSessionFactory sqlSessionFactory =new SqlSessionFactoryBuilder().build(configuration);
SqlSession sqlSession = sqlSessionFactory.openSession();
TMapper mapper = sqlSession.getMapper(TMapper.class);

通过sqlsession.getMapper()即可获取mapper对象,但我们知道TMapper是一个接口,接口是不能进行实例化的,那这个对象是怎么来的?

如果翻阅mybatis源码会看到,底层对该接口进行了jdk动态代理完成了对象的实例化,最后返回了代理对象。

 好了,到这里我们大概知道mybatis生成一个mapper对象了,下面我们需要考虑的是如何将这个mapper对象注入到spring容器中。

2、如何将mapper对象注入到spring容器中

我们先不看mybatis如何将mapper对象注入到spring中去的,我们先来看看我们已知的可以往spring注入对象的方式。

注意:往spring中注入类和注入对象是不同的概念,注入类是spring会接管类对象实例化、初始化等过程,而注入对象则是将对象的实例化初始化交由自己掌控。

1)、@Component注解方式——这种方式是把类给spring管理

2)、xml方式,<bean id="" class="" ——同理这种方式也是把类给spring管理

3)、动态注册beanDefifinition——这种方式是把beanDefifinition对象给spring,并不是自己产的真实对 象 。

        以上三种方式会被很多人误解可以把一个对象给到spring容器;当然这三种方式最后也是产生了一个对 象,并且存到了容器当中;但是问题的关键是这个对象的产生过程是我们无法去控制的;是由spring容 器去实例化的对象;比如上面我们的tMapper对象,是需要我们用动态代理这种特定方式来产生, spring肯定不会帮你完成。所以再来看下下面的三种方式:

4)、@Bean方式——通过在方法当中编码,可以自己产生对象;返回后即存在容器,符合要求。

5)、FactoryBean方式——通过实现FactoryBean接口也可以自己编码产生对象,符合要求。(只是能实现对mapper对象进行实例化,但注入spring需要借助xml配置、其他注解等其他方式注入到spring中)

6)、使用spring提供的api,beanFactory.registerSingleton(String name,Object object)——直接传自己的对象 符合要求

那么mybatis中是如何去选择的?(下面以xml的方式去解析整体流程)

我们可以看看mybatisxml怎么去配一个mapper的:

<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
  <property name="mapperInterface" value="org.mybatis.spring.sample.mapper.UserMapper" />
  <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
mybatis 开发了一个 MapperFactoryBean ,在他的 getObject 方法当中产生了代理对象;代理对象实现 接口通过属性注入进去,即上面代码中的org.mybatis.spring.sample.mapper.UserMapper
精简后的 MapperFactoryBean 源码:
public class MapperFactoryBean implements FactoryBean{
    
    private Class mapperInterface; //接收不同类型的mapper

    //返回代理对象
    public T getObject() throws Exception {
        return getSqlSession().getMapper(this.mapperInterface);
    }

    //实现代理(set方式进行依赖注入)
    public void setMapperInterface(Class<T> mapperInterface) {
        this.mapperInterface = mapperInterface;
    }
}

mybatis选择的是FactoryBean的方式。

特别注意:这里的mapperInterface是需要进行依赖注入的,就是我们要将各种类型的mapper注入给他。(下一篇写ImportBeanDefinitionPostProcess注入多个mapper的时候会将怎么进行不同类型的mapper注入给mapperInterface)

FactoryBean 是一个特殊接口,实现了 factoryBean 的接口通常会产生两个 bean ,第一个实现类本身的 对象,第二个是getObject方法当中返回的对象; 此时就会往spring注入一个 MapperFactoryBean  (注入类方式)、一个mapper(注入对象方式,xml配置的时候会进行注入)。

        但是这个时候问题又来了,如果我要注入多个mapper对象,此时需要去xml配置多次?这会不会显得太麻烦了?此时基于FactoryBean的基础上(为了使得接口能被实例化、Mapper所有方法基本执行相同的操作——找到对应的SQL,绑定参数,执行SQL然后返回结果),我们需要解决多个mapper对象注入简易化的需求。

此时mybatis就抛弃了xml注入bean的配置化方式,提供了两个注解@MapperScan、@Mapper

@Mapper是队单个接口类的注解,单个操作,然后接口在编译之后都会生成相应的实现类。(接口少的时候适合使用,所以我们暂时不说他)

@MapperScan是对整个包之下的所有的接口类的注解,是批量的操作。使用@MapperScan之后,接口类就不需要再使用@Mapper注解了(正解决了注入多个mapper的简易化需求)

所以我们下面就得去看看@MapperScan是如何实现这么个过程的。

注意:FactoryBean+@Component并不能注入mapper对象,因为@Component只能将类交给spring生成bean,不能将对象交给spring。所以就不需要讨论这种情况了。而@Bean、beanFactory.registerSingleton()每配一个mapper就要编写一次,显然也不合适,所以就只剩下动态注册beanDefifinition。我们暂且不下定论,先看看mybatis是怎么做的。

3、@MapperScan如何进行多个mapper的注入

        在说明@MapperScan注解的原理前,需要明白的一点,就是要满足接口能被实例化、接口方法能执行相应逻辑的前提,保证这一前提的是使用了FactoryBean方式在getObject()方法中返回了一个jdk动态代理实例化好的的mapper代理对象。有了这一前提我们才需要解决多mapper注入的问题。

        由上面可知FactoryBean+xml配置可以将对象注入到spring中,不过这种情况在需要注入多个mapper的时候显得太麻烦了,所以mybatis就提供了一个扫描mapper的注解@MapperScan

Mybatis的mapper对象注入到Spring容器中的过程_DanceDonkey的博客-CSDN博客_mybatis mapper注入

我们可以点进@MapperScan注解中:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({MapperScannerRegistrar.class})
@Repeatable(MapperScans.class) //在一个类、方法、属性上标注多个相同注解
public @interface MapperScan {}

 可以看到一个@Import({MapperScannerRegistrar.class}),@Import注解是用来导入配置类或者一些需要前置加载的类。

对于@MapperScan注解的原理可以看下面文章:

通过@MapperScan源码了解Spring自定义注解扫描器[通俗易懂] - 腾讯云开发者社区-腾讯云

看过这篇文章,可以知道,mybatis确实是使用了动态注册beanDefifinition的方式将FactoryBean方式产生的mapper代理对象注入到了spring中。

那么我们下面需要看看什么是beanDefifinition、如何动态注册beanDefifinition?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值