天天看点

mybatis整合spring的整合代码源码(第一次体会到读源码的作用)

写一下mybati是如何整合spring的关键代码

这是在b站看一个大佬分析源码后相当于对看后的一个总结,以前总搞不懂读spring源码有什么,以前就以为是单纯的学习他的设计模式,设计思想当然这些也很重要,但是对于现在的我来说。看了总是忘记,但是今天看了哪个大佬讲以后发现 看了spring源码以后我们必须得从设计者的角度取思考当初为什么这么设计,以及当前spring的源码对于我有什么用,哪些其他框架用了这些spring的留下的特性。像mybatis整合spring 如果mybatis开发人员没有对于spring源码非常熟悉,我觉得应该是不可能写出那样优美的代码的。

所以希望从今天开始,在未来能够对很多框架,甚至操作系统的底层非常了解,能够知其然并且知其所以然。废话不多说 开始分析。

我们都知道Mybatis只需要写一个接口就可以帮我们写成代理对象帮我们完成操作。

先简单的写一个实现

public interface userDao {
    @Select("select * from test")
    public  void test();
}

           
public class MyInvocationHandler implements InvocationHandler{
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("连接数据库");
        System.out.println("query db:"+method.getAnnotation(Select.class).value()[0]);
        //Object invoke = method.invoke(proxy, args);
        System.out.println("断开数据库");
        return null;
    }
}
           
@Component
public class MyService {
    @Autowired
    userDao userDao;

    public  void  test(){
        userDao.test();
    }
}

           

到了这里动态代理基本完成 剩下的就是生成代理对象即可,我们通过自动注入userDao然后调用代理对象增强后的方法,但是我们要自动注入必须要注入容器吧。那么我们如何将一个对象注入容器了?

加@ComPonent?这里是要生成代理对象啊 ,对象需要我们自己new 出来 于是我们想到用facotryBean

于是有了这样的代码 ,实现FactoryBean 接口 我们就可以将我们想要的对象 放入spring容器

@Component
public class MyFactoryBean implements FactoryBean {


    public MyFactoryBean() {
    }

    public Object getObject() throws Exception {
        Class [] clazz=new Class[]{userDao.class};
        userDao o = (userDao) Proxy.newProxyInstance(Main.class.getClassLoader(), clazz, new MyInvocationHandler());
        return o;
    }

    public Class<?> getObjectType() {
        return userDao.class;
    }


}

           

然后我们在Main方法来调用一下这时候发现spring容器里面有了代理对象

public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ac=new AnnotationConfigApplicationContext(AppConfig.class);
         MyService bean = ac.getBean(MyService.class);
         bean.test();
    }
}

           

但是这样有一个问题就是我们生成代理对象都是固定的 于是我们把class当作传说传入写成动态的

但是这样又产生一个问题我们不能直接用@Component注解了因为我们要传参数,如果用了@Component 所有创建过程交给spring spring怎么知道我们要传入哪个class

public class MyFactoryBean implements FactoryBean {

    Class MapperInterface;

    public MyFactoryBean() {
    }

    public MyFactoryBean(Class mapperInterface) {
        MapperInterface = mapperInterface;
    }

    public Object getObject() throws Exception {
        Class [] clazz=new Class[]{MapperInterface};
        Object o =  Proxy.newProxyInstance(MyFactoryBean.class.getClassLoader(), clazz, new MyInvocationHandler());
        return o;
    }

    public Class<?> getObjectType() {
        return userDao.class;
    }


}

           

于是我们采用

@Bean

MyFactoryBean getMyFactoryBean(){

return new MyFactoryBean(userDao.class);

}

自己配置一个bean 这里下面官网给出的xml配置是异曲同工把,

大家第一次用spring整合mybatis的时候应该都写过这样的代码吧

mybatis整合spring的整合代码源码(第一次体会到读源码的作用)

我们只需要有几个Mapper配置几个Mapper就行了

但是这样也很麻烦我们有100个Mapper岂不是要写100个配置bean或者一个xml配置bean

我们想一想mybatis怎么来实现的 我们用mybatis的时候是不是用了一个MapperScan的注解 于是我们自己定义一个注解

@Retention(RetentionPolicy.RUNTIME)
@Import(MyRegistery.class)
public @interface MyMapperScanner {
}

而spring为我们提供了一个外部接口ImportBeanDefinitionRegistrar 实现这个接口我们可以自己往容器自己注入一个对象。

不知道大家对BeanDefinition有没有了解 看名字就知道bean定义,存储了一些bean的信息,例如bean是不是单例,是不是懒加载等等,初始化bean的时候需要用的这些信息,而所有的BeanDefinition放到一个Map中叫做
BeanDefinitionMap


实现了ImportBeanDefinitionRegistrar接口我们就可以通过我们定义的MyMapperScan扫描到对应路径下所有的类得到全限定类名 然后通过循环一个一个传入一个一个的注册到容器中
```java

public class MyRegistery implements ImportBeanDefinitionRegistrar{
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {


            //for 循环 遍历 mapeerscan下的所有类
            String className="cn.cdut.dao.userDao";
            BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MyFactoryBean.class);
            GenericBeanDefinition beanDefinition = (GenericBeanDefinition) builder.getBeanDefinition();
            beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(className);
            //修改注入模型  为3(也可以不修改)
            beanDefinition.setAutowireMode(3);
            beanDefinitionRegistry.registerBeanDefinition("dove", beanDefinition);

        //}
    }
}

           

最后为了确认我们的代码没问题展示下运行结果

mybatis整合spring的整合代码源码(第一次体会到读源码的作用)
到此基本的mybatis整合spring的流程就是这样,这是我第一次体会到体会到学源码的作用,
希望自己有能力,有机会参与到一个框架的开发。