Spring-mybatis结合的底层原理

news2024/11/16 7:22:39

1.项目前期准备

1.1 导入maven jar包

 <dependencies>
    <!-- spring依赖 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <!-- spring事务依赖 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <!-- mybatis依赖 -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.1</version>
    </dependency>
    <!-- mybatis和spring集成依赖 -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>1.3.1</version>
    </dependency>
    <!-- mysql驱动 -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.9</version>
    </dependency>
    <!-- 阿里的连接池 -->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.12</version>
    </dependency>
    <!-- 单元测试 -->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

1.2项目相关的文件夹

在这里插入图片描述

说明:

  1. mapper文件夹:存所有的sql语句的接口
  2. service文件夹:存所有具体的实现的方法
  3. spring-mybatis文件夹:存所有整合spring和mybatis的文件
  4. resources文件夹存所有的资源文件

1.2.1 UserMapper.java文件

package com.nq.mapper;


import org.apache.ibatis.annotations.Select;

/**
 * @author Nickel
 * @version 1.0
 * @date 2023/7/28 0:24
 */
public interface UserMapper {

    @Select("select 'user'")
    String selectById();
}

1.2.2 AppConfig.java文件

package com.nq.service;

import org.springframework.context.annotation.ComponentScan;

/**
 * @author Nickel
 * @version 1.0
 * @date 2023/7/28 14:59
 */
@ComponentScan("com.nq")
public class AppConfig {
}

1.2.3 UserService.java文件

package com.nq.service;
import com.nq.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @author Nickel
 * @version 1.0
 * @date 2023/7/28 14:45
 */
@Component
public class UserService {

    @Autowired
    private UserMapper userMapper;

    public void test(){
       System.out.println(userMapper.selectById());
    }

}

1.2.4 mybatis.xml文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
  <environments default="development">
    <environment id="development">
      <!-- 使用jdbc事务管理 -->
      <transactionManager type="JDBC"/>
      <!-- 数据库连接池 -->
      <dataSource type="POOLED">
        <property name="driver" value="com.mysql.jdbc.Driver"/>
        <property name="url"
                  value="jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf-8&amp;useSSL=false"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
      </dataSource>
    </environment>
  </environments>
</configuration>

1.2.5 Test.java文件

package com.nq.service;


import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.io.IOException;

/**
 * @author Nickel
 * @version 1.0
 * @date 2023/7/27 23:48
 */
public class Test {
    public static void main(String[] args) throws IOException {
        AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext();
        context.register(AppConfig.class);
        context.refresh();

        UserService userService=(UserService)context.getBean("userService");
        userService.test();
    }
}

说明:由于UserMapper是接口类型,不能被spring加载,所以spring加载的时候这里就要解决接口不能够被加载的情况,其二;由于UserMapper是执行sql语句,所有需要Mybatis生成UserMapper代理对象注入到UserMapper类型当中。
在这里插入图片描述

2.手写spring-mybatis执行过程

2.1 NickelFactoryBean.java文件

package com.nq.mybatis.spring;

import com.nq.mapper.UserMapper;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @author Nickel
 * @version 1.0
 * @date 2023/7/28 16:00
 */
@Component
public class NickelFactoryBean implements FactoryBean {
    @Override
    public Object getObject() throws Exception {
        Object proxyInstance = Proxy.newProxyInstance(NickelFactoryBean.class.getClassLoader(), new Class[]{UserMapper.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                return null;
            }
        });
        return proxyInstance;
    }

    @Override
    public Class<?> getObjectType() {
        return UserMapper.class;
    }
}

说明:这里让UserMapper接口成为一个bean对象,这样程序就不会报错了
在这里插入图片描述
说明:这里确实让UserMapper成为一个bean对象了,但是这里会有一个问题,假如我们建立一个OrderMappe文件的话,这里不能识别OrderMapper对象

2.2建立OrderMapper对象和UserService对象

1.OrderMapper.java对象

package com.nq.mapper;


import org.apache.ibatis.annotations.Select;

/**
 * @author Nickel
 * @version 1.0
 * @date 2023/7/28 0:24
 */
public interface OrderMapper {

    @Select("select 'order'")
    String selectById();
}

2.UserService.java对象修改

package com.nq.service;
import com.nq.mapper.OrderMapper;
import com.nq.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @author Nickel
 * @version 1.0
 * @date 2023/7/28 14:45
 */
@Component
public class UserService {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private OrderMapper orderMapper;

    public void test(){
       System.out.println(userMapper.selectById());
        System.out.println(orderMapper.selectById());
    }

}

3.测试结果

在这里插入图片描述
说明:无法读取到OrderMapper对象

2.3让每一个mapper文件都成为bean对象

1.修改NickelFactoryBean.java文件,这里可以建立一个外部对象的形式,对所有的接口进行赋值

package com.nq.mybatis.spring;

import com.nq.mapper.UserMapper;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @author Nickel
 * @version 1.0
 * @date 2023/7/28 16:00
 */
public class NickelFactoryBean implements FactoryBean {

    private Class mapperInterface;

    public NickelFactoryBean(Class mapperInterface) {
        this.mapperInterface = mapperInterface;
    }

    @Override
    public Object getObject() throws Exception {
        Object proxyInstance = Proxy.newProxyInstance(NickelFactoryBean.class.getClassLoader(), new Class[]{mapperInterface}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println(method.getName());
                return null;
            }
        });
        return proxyInstance;
    }

    @Override
    public Class<?> getObjectType() {
        return mapperInterface;
    }
}

注意:这里需要去掉@Component注解,不然有这个注解spring将会加载一次,这和多个mapper去使用相违背。

2.Test方法中指定对对象成为bean对象

package com.nq.service;


import com.nq.mapper.OrderMapper;
import com.nq.mapper.UserMapper;
import com.nq.mybatis.spring.NickelFactoryBean;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.io.IOException;

/**
 * @author Nickel
 * @version 1.0
 * @date 2023/7/27 23:48
 */
public class Test {
    public static void main(String[] args) throws IOException {
        AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext();
        context.register(AppConfig.class);

        AbstractBeanDefinition beanDefinition= BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition.setBeanClass(NickelFactoryBean.class);
        beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(UserMapper.class);//userMapper  UserMapper代理对象
        context.registerBeanDefinition("userMapper",beanDefinition);

        AbstractBeanDefinition beanDefinition1= BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition1.setBeanClass(NickelFactoryBean.class);
        beanDefinition1.getConstructorArgumentValues().addGenericArgumentValue(OrderMapper.class);//orderMapper  OrderMapper代理对象
        context.registerBeanDefinition("orderMapper",beanDefinition1);


        context.refresh();

        UserService userService=(UserService)context.getBean("userService");
        userService.test();
    }
}

在这里插入图片描述

3.Test结果显示

在这里插入图片描述
说明;这里我们把每一个mapper接口创建为bean的形式,但是这里有一个问题,假如出现第三mapper文件,我们在这里需要又去添加一个,思考这里有什么方式去注册bean呢

2.4NickelBeanDefinitionRegistryPostProcess.java文件通过继承BeanDefinitionRegistryPostProcessor去注册对应的接口

package com.nq.mybatis.spring;

import com.nq.mapper.OrderMapper;
import com.nq.mapper.UserMapper;
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.stereotype.Component;

/**
 * @author Nickel
 * @version 1.0
 * @date 2023/7/28 17:17
 */
@Component
public class NickelBeanDefinitionRegistryPostProcess implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        AbstractBeanDefinition beanDefinition= BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition.setBeanClass(NickelFactoryBean.class);
        beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(UserMapper.class);//userMapper  UserMapper代理对象
        registry.registerBeanDefinition("userMapper",beanDefinition);

        AbstractBeanDefinition beanDefinition1= BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition1.setBeanClass(NickelFactoryBean.class);
        beanDefinition1.getConstructorArgumentValues().addGenericArgumentValue(OrderMapper.class);//orderMapper  OrderMapper代理对象
        registry.registerBeanDefinition("orderMapper",beanDefinition1);

    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }
}

说明;通过这种获取方式,依然没有解决新加mapper文件的时候,需要增加修改代码的形式,所以这里我们需要通过spring扫描的方式去修改mapper文件的动态获取

2.5我们通过提供注解的形式,得到需要扫描的路径,提供NickelMapperScan注解

package com.nq.mybatis.spring;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author Nickel
 * @version 1.0
 * @date 2023/7/28 17:24
 */
@Retention(RetentionPolicy.RUNTIME)//运行时
@Target(ElementType.TYPE)//注解只能写在类上面
public @interface NickelMapperScan {
    String value();
}

在这里插入图片描述

2.6ImportBeanDefinitionRegistrar实现接口的方式我们也能够进行注册

2.6.1修改NickelBeanDefinitionRegistryPostProcess文件

package com.nq.mybatis.spring;

import com.nq.mapper.OrderMapper;
import com.nq.mapper.UserMapper;
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.stereotype.Component;

/**
 * @author Nickel
 * @version 1.0
 * @date 2023/7/28 17:17
 */
//@Component
public class NickelBeanDefinitionRegistryPostProcess implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
//        AbstractBeanDefinition beanDefinition= BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
//        beanDefinition.setBeanClass(NickelFactoryBean.class);
//        beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(UserMapper.class);//userMapper  UserMapper代理对象
//        registry.registerBeanDefinition("userMapper",beanDefinition);
//
//        AbstractBeanDefinition beanDefinition1= BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
//        beanDefinition1.setBeanClass(NickelFactoryBean.class);
//        beanDefinition1.getConstructorArgumentValues().addGenericArgumentValue(OrderMapper.class);//orderMapper  OrderMapper代理对象
//        registry.registerBeanDefinition("orderMapper",beanDefinition1);

    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }
}

2.6.2创建NickelImportBeanDefinitionRegisty.java实现接口ImportBeanDefinitionRegistrar

package com.nq.mybatis.spring;

import com.nq.mapper.OrderMapper;
import com.nq.mapper.UserMapper;
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.BeanNameGenerator;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.stereotype.Component;

/**
 * @author Nickel
 * @version 1.0
 * @date 2023/7/28 17:32
 */
public class NickelImportBeanDefinitionRegisty implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
        AbstractBeanDefinition beanDefinition= BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition.setBeanClass(NickelFactoryBean.class);
        beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(UserMapper.class);//userMapper  UserMapper代理对象
        registry.registerBeanDefinition("userMapper",beanDefinition);

        AbstractBeanDefinition beanDefinition1= BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition1.setBeanClass(NickelFactoryBean.class);
        beanDefinition1.getConstructorArgumentValues().addGenericArgumentValue(OrderMapper.class);//orderMapper  OrderMapper代理对象
        registry.registerBeanDefinition("orderMapper",beanDefinition1);
     }
}

2.6.3这里我们需要NickelImportBeanDefinitionRegisty生效,需要在AppConfig中导入

package com.nq.service;

import com.nq.mybatis.spring.NickelImportBeanDefinitionRegisty;
import com.nq.mybatis.spring.NickelMapperScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;

/**
 * @author Nickel
 * @version 1.0
 * @date 2023/7/28 14:59
 */
@ComponentScan("com.nq")
@NickelMapperScan("com.nq.mapper")
@Import(NickelImportBeanDefinitionRegisty.class)
public class AppConfig {
}

2.6.4测试运行效果

在这里插入图片描述

2.7获取扫描路径

2.7.1把注解移动到扫描类上

1.修改AppConfig文件

package com.nq.service;

import com.nq.mybatis.spring.NickelImportBeanDefinitionRegisty;
import com.nq.mybatis.spring.NickelMapperScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;

/**
 * @author Nickel
 * @version 1.0
 * @date 2023/7/28 14:59
 */
@ComponentScan("com.nq")
@NickelMapperScan("com.nq.mapper")
public class AppConfig {
}

2.修改NickelMapperScan文件

package com.nq.mybatis.spring;

import org.springframework.context.annotation.Import;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author Nickel
 * @version 1.0
 * @date 2023/7/28 17:24
 */
@Retention(RetentionPolicy.RUNTIME)//运行时
@Target(ElementType.TYPE)//注解只能写在类上面
@Import(NickelImportBeanDefinitionRegisty.class)
public @interface NickelMapperScan {
    String value();
}

3在NickelImportBeanDefinitionRegisty获取扫描的路径

package com.nq.mybatis.spring;

import com.nq.mapper.OrderMapper;
import com.nq.mapper.UserMapper;
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.BeanNameGenerator;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
 * @author Nickel
 * @version 1.0
 * @date 2023/7/28 17:32
 */
public class NickelImportBeanDefinitionRegisty implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
        //获取扫描路径
        Map<String, Object> annotationAttributes = importingClassMetadata.getAnnotationAttributes(NickelMapperScan.class.getName());
        String path = (String)annotationAttributes.get("value");
        System.out.println(path);

        AbstractBeanDefinition beanDefinition= BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition.setBeanClass(NickelFactoryBean.class);
        beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(UserMapper.class);//userMapper  UserMapper代理对象
        registry.registerBeanDefinition("userMapper",beanDefinition);

        AbstractBeanDefinition beanDefinition1= BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition1.setBeanClass(NickelFactoryBean.class);
        beanDefinition1.getConstructorArgumentValues().addGenericArgumentValue(OrderMapper.class);//orderMapper  OrderMapper代理对象
        registry.registerBeanDefinition("orderMapper",beanDefinition1);
     }
}

在这里插入图片描述
说明:打印结果如下

4.通过spring的扫描逻辑获取扫描路径

1.创建类NickelClassPathBeanDefinitionScan继承spring扫描类ClassPathBeanDefinitionScanner
package com.nq.mybatis.spring;

import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;

/**
 * @author Nickel
 * @version 1.0
 * @date 2023/7/29 14:31
 */
public class NickelClassPathBeanDefinitionScan extends ClassPathBeanDefinitionScanner {

    public NickelClassPathBeanDefinitionScan(BeanDefinitionRegistry registry) {
        super(registry);
    }
}

2.NickelImportBeanDefinitionRegisty获取NickelClassPathBeanDefinitionScan得到扫描类
package com.nq.mybatis.spring;

import com.nq.mapper.OrderMapper;
import com.nq.mapper.UserMapper;
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.BeanNameGenerator;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
 * @author Nickel
 * @version 1.0
 * @date 2023/7/28 17:32
 */
public class NickelImportBeanDefinitionRegisty implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
        //获取扫描路径
        Map<String, Object> annotationAttributes = importingClassMetadata.getAnnotationAttributes(NickelMapperScan.class.getName());
        String path = (String)annotationAttributes.get("value");
        System.out.println(path);

        NickelClassPathBeanDefinitionScan nickelClassPathBeanDefinitionScan=new NickelClassPathBeanDefinitionScan(registry);
        nickelClassPathBeanDefinitionScan.scan(path);

        AbstractBeanDefinition beanDefinition= BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition.setBeanClass(NickelFactoryBean.class);
        beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(UserMapper.class);//userMapper  UserMapper代理对象
        registry.registerBeanDefinition("userMapper",beanDefinition);

        AbstractBeanDefinition beanDefinition1= BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition1.setBeanClass(NickelFactoryBean.class);
        beanDefinition1.getConstructorArgumentValues().addGenericArgumentValue(OrderMapper.class);//orderMapper  OrderMapper代理对象
        registry.registerBeanDefinition("orderMapper",beanDefinition1);
     }
}

在这里插入图片描述
说明:由于spring扫描方法只能获取扫描类,而不能获取扫描接口。

5.NickelClassPathBeanDefinitionScan通过重写isCandidateComponent方法修饰,实现只能扫描接口

package com.nq.mybatis.spring;

import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.core.type.classreading.MetadataReader;

import java.io.IOException;
import java.util.Set;

/**
 * @author Nickel
 * @version 1.0
 * @date 2023/7/29 14:31
 */
public class NickelClassPathBeanDefinitionScan extends ClassPathBeanDefinitionScanner {

    //注册对象
    public NickelClassPathBeanDefinitionScan(BeanDefinitionRegistry registry) {
        super(registry);
    }

    /**
     * 获取扫描类是否有值
     * @param basePackages
     * @return
     */
    @Override
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Set<BeanDefinitionHolder> beanDefinitionHolders = super.doScan(basePackages);
        return beanDefinitionHolders;
    }

    /**
     * 判断是否是接口
     * @param beanDefinition
     * @return
     */
    @Override
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
       return beanDefinition.getMetadata().isInterface();
    }
}

在这里插入图片描述
说明:由于spring扫描只会扫描includeFilters里面的类,这里的类指的是类上面加了@Component类才会被扫描到。

6.在NickelClassPathBeanDefinitionScan时候,重写isCandidateComponent(MetadataReader metadataReader)方法,让方法都返回true

1.重写isCandidateComponent方法
package com.nq.mybatis.spring;

import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.core.type.classreading.MetadataReader;

import java.io.IOException;
import java.util.Set;

/**
 * @author Nickel
 * @version 1.0
 * @date 2023/7/29 14:31
 */
public class NickelClassPathBeanDefinitionScan extends ClassPathBeanDefinitionScanner {

    //注册对象
    public NickelClassPathBeanDefinitionScan(BeanDefinitionRegistry registry) {
        super(registry);
    }

    /**
     * 获取扫描类是否有值
     * @param basePackages
     * @return
     */
    @Override
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Set<BeanDefinitionHolder> beanDefinitionHolders = super.doScan(basePackages);
        return beanDefinitionHolders;
    }

    /**
     * 判断是否是接口
     * @param beanDefinition
     * @return
     */
    @Override
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
       return beanDefinition.getMetadata().isInterface();
    }

    /**
     * 重新是否包含的接口
     * @param metadataReader
     * @return
     * @throws IOException
     */
    @Override
    protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
        return true;
    }
}

在这里插入图片描述

2.修改NickelImportBeanDefinitionRegisty方法
package com.nq.mybatis.spring;

import com.nq.mapper.OrderMapper;
import com.nq.mapper.UserMapper;
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.BeanNameGenerator;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Map;

/**
 * @author Nickel
 * @version 1.0
 * @date 2023/7/28 17:32
 */
public class NickelImportBeanDefinitionRegisty implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
        //获取扫描路径
        Map<String, Object> annotationAttributes = importingClassMetadata.getAnnotationAttributes(NickelMapperScan.class.getName());
        String path = (String)annotationAttributes.get("value");
        System.out.println(path);

        NickelClassPathBeanDefinitionScan scanner=new NickelClassPathBeanDefinitionScan(registry);
        scanner.scan(path);
     }
}
3.修改NickelClassPathBeanDefinitionScan让方法的类都属于NickelFactoryBean对象
package com.nq.mybatis.spring;

import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.core.type.classreading.MetadataReader;

import java.io.IOException;
import java.util.Set;

/**
 * @author Nickel
 * @version 1.0
 * @date 2023/7/29 14:31
 */
public class NickelClassPathBeanDefinitionScan extends ClassPathBeanDefinitionScanner {

    //注册对象
    public NickelClassPathBeanDefinitionScan(BeanDefinitionRegistry registry) {
        super(registry);
    }

    /**
     * 获取扫描类是否有值
     * @param basePackages
     * @return
     */
    @Override
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Set<BeanDefinitionHolder> beanDefinitionHolders = super.doScan(basePackages);
        for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
            BeanDefinition beanDefinition = beanDefinitionHolder.getBeanDefinition();
            beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(beanDefinition.getBeanClassName());
            beanDefinition.setBeanClassName(NickelFactoryBean.class.getName());
        }
        return beanDefinitionHolders;
    }

    /**
     * 判断是否是接口
     * @param beanDefinition
     * @return
     */
    @Override
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
       return beanDefinition.getMetadata().isInterface();
    }

    /**
     * 重新是否包含的接口
     * @param metadataReader
     * @return
     * @throws IOException
     */
    @Override
    protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
        return true;
    }
}

在这里插入图片描述

4.增加MemberMapper.java接口
package com.nq.mapper;


import org.apache.ibatis.annotations.Select;

/**
 * @author Nickel
 * @version 1.0
 * @date 2023/7/28 0:24
 */
public interface MemberMapper {

    @Select("select 'user'")
    String selectById();
}

5.修改UserService.java
package com.nq.service;
import com.nq.mapper.MemberMapper;
import com.nq.mapper.OrderMapper;
import com.nq.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @author Nickel
 * @version 1.0
 * @date 2023/7/28 14:45
 */
@Component
public class UserService {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private MemberMapper memberMapper;

    public void test(){
        System.out.println(userMapper.selectById());
        System.out.println(orderMapper.selectById());
        System.out.println(memberMapper.selectById());
    }

}

6.打印结果显示

结果显示
在这里插入图片描述

7.修改NickelFactoryBean代理,使得代理对象为mybatis

1.修改NickelFactoryBean对象
package com.nq.mybatis.spring;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @author Nickel
 * @version 1.0
 * @date 2023/7/28 16:00
 */
public class NickelFactoryBean implements FactoryBean {

    private Class mapperInterface;

    private SqlSession sqlSession;

    public NickelFactoryBean(Class mapperInterface) {
        this.mapperInterface = mapperInterface;
    }

    @Autowired
    public void setSqlSession(SqlSessionFactory sqlSessionFactory) {
        sqlSessionFactory.getConfiguration().addMapper(mapperInterface);
        this.sqlSession = sqlSessionFactory.openSession();
    }

    @Override
    public Object getObject() throws Exception {
        return sqlSession.getMapper(mapperInterface);
    }

    @Override
    public Class<?> getObjectType() {
        return mapperInterface;
    }
}
2.修改AppConfig配置启动类
package com.nq.service;

import com.nq.mybatis.spring.NickelImportBeanDefinitionRegisty;
import com.nq.mybatis.spring.NickelMapperScan;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;

import java.io.IOException;
import java.io.InputStream;

/**
 * @author Nickel
 * @version 1.0
 * @date 2023/7/28 14:59
 */
@ComponentScan("com.nq")
@NickelMapperScan("com.nq.mapper")
public class AppConfig {

    @Bean
    public SqlSessionFactory  sqlSessionFactory() throws IOException {
          InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
          SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
          return sqlSessionFactory;
    }
}

在这里插入图片描述

代码路径:
https://gitee.com/nickel369369/spring-mybatis/mirrors#/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/807838.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CK-00靶机详解

CK-00靶机详解 靶场下载地址&#xff1a;https://download.vulnhub.com/ck/CK-00.zip 这个靶场扫描到ip打开后发现主页面css是有问题的&#xff0c;一般这种情况就是没有配置域名解析。 我们网站主页右击查看源代码&#xff0c;发现一个域名。 把域名添加到我们hosts文件中。…

Meta “地平线世界”移动端应用即将上线,手机快乐元宇宙?

根据海外记者 Janko Roettgers 的报道&#xff0c;Meta 预计很快推出移动版的 VR 元宇宙服务 "地平线世界"&#xff0c;这是Meta 长期开发的产品。 根据最新报道&#xff0c;Meta宣布正在研发“地平线世界”的移动版&#xff0c;并表示这一服务已经可以在Quest VR设…

黑客成长技术清单 | 渗透测试详解(全网最全工具,最常用的工具)

在为做网络安全不知如何入手而迷茫 在为不知如何规划自己的技术学习路线而烦恼 在为不知该钻研了解互联网的哪个方向而犹豫 这份网络安全 的内部安全资料&#xff0c;解答你所有的学习疑惑。 给大家享一份全套的网络安全学习资料, 给那些想学习网络安全的小伙伴们一点帮助!…

线段树详解 原理解释 + 构建步骤 + 代码(带模板)

目录 介绍&#xff1a; 定义&#xff1a; 以具体一个题目为例&#xff1a;​编辑 树的表示方法&#xff1a; 实现步骤&#xff1a; 构建结点属性&#xff1a; pushup函数&#xff1a; build函数&#xff1a; pushdown函数&#xff1a; modify函数&#xff1a; q…

《零基础入门学习Python》第071讲:GUI的终极选择:Tkinter8

虽然我们能用 tkinter 设计不少东西了&#xff0c;但是不少同学还是感觉对这个界面编程掌控得还不够多&#xff0c;说白了&#xff0c;就是我们现在还没办法随心所欲的去绘制我们想要的界面&#xff0c;但是不瞒你说&#xff0c;今天的这一节课将会给你的人生乃至人生观带来翻天…

Linux下在终端输入密码隐藏方法

Linux系统中&#xff0c;如何将在终端输入密码时将密码隐藏&#xff1f; 最近做简单的登录界面时&#xff0c;不做任何操作的话&#xff0c;在终端输入密码的同时也会显示输入的密码是什么&#xff0c;这样对于隐蔽性和使用都有不好的体验。那么我就想到将密码用字符*隐藏起来…

Glow: Generative Flow with Invertible 1×1 Convolutions论文解析及实现(二)

Glow: Generative Flow with Invertible 11 Convolutions 代码github: https://github.com/rosinality/glow-pytorch添加链接描述 1 模型架构如下 1.1 左边图flow模型 Flow model ① ActNorm ② InvConv2dLU ③ AffineCoupling 1.2 右边模型结构Glow模型 Glow Model Block…

C++之poll与epoll总结(一百六十九)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

SpringCloudAlibaba之Ribbon

Ribbon是nacos自带的负载均衡器&#xff0c;属于客户端的负载均衡 但是在Spring高级版本中让LoadBalancer替代了 本人用的是2.1.0的nacos&#xff0c;ribbon还没有被替换。 使用&#xff1a; 在配置类中&#xff1a;LoadBalanced BeanLoadBalancedpublic RestTemplate restT…

ETHERNET/IP转RS485/RS232网关什么是EtherNet/IP?

网络数据传输遇到的协议不同、数据互通麻烦等问题&#xff0c;一直困扰着大家。然而&#xff0c;现在有一种神器——捷米JM-EIP-RS485/232&#xff0c;它将ETHERNET/IP网络和RS485/RS232总线连接在一起&#xff0c;让数据传输更加便捷高效。 那么&#xff0c;它是如何实现这一功…

Python Web开发技巧VIII

目录 ModelSerializer和Serializer区别是什么 从queryset中取出某个models的字段值 Q对象进行模糊匹配 HTTP方式-如何模糊搜索JSON字段中的某个KEY值呢&#xff1f; showmigrations 合并两个或多个queryset ModelSerializer和Serializer区别是什么 都是DRF中用于序列化和…

尚医通9:医院列表功能+GateWay网关

内容介绍 1、医院列表功能&#xff08;接口&#xff09; 4、医院列表功能&#xff08;前端&#xff09; 5、更新医院上线状态功能 6、医院详情 7、GateWay网关 8、医院排班管理需求分析 9、查看医院所有科室接口、前端 医院列表功能&#xff08;接口&#xff09; 接口…

代码随想录算法训练营day15 | 102. 二叉树的层序遍历,226. 翻转二叉树,101. 对称二叉树

目录 102. 二叉树的层序遍历 226. 翻转二叉树 101. 对称二叉树 100. 相同的树 100是101的衍生题目。572也为101的衍生题目。 102. 二叉树的层序遍历 思路&#xff1a; 以前的笔记 代码&#xff1a; class Solution {public List<List<Integer>> levelOrder(T…

web自动化测试-PageObject 设计模式

为 UI 页面写测试用例时&#xff08;比如 web 页面&#xff0c;移动端页面&#xff09;&#xff0c;测试用例会存在大量元素和操作细节。当 UI 变化时&#xff0c;测试用例也要跟着变化&#xff0c; PageObject 很好的解决了这个问题。 使用 UI 自动化测试工具时&#xff08;包…

Reinforcement Learning with Code 【Chapter 9. Policy Gradient Methods】

Reinforcement Learning with Code This note records how the author begin to learn RL. Both theoretical understanding and code practice are presented. Many material are referenced such as ZhaoShiyu’s Mathematical Foundation of Reinforcement Learning, . 文章…

C++之实例化对象总结(一百七十)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

13 亿美金买个寂寞?No!AI 时代的数据行业蓄势待发

6月底&#xff0c;全球数据分析领域彻底炸锅了。 两大数据分析企业Databricks和Snowflake纷纷将目光瞄准了AI大模型。要知道&#xff0c;这两位对手平时没少对台戏&#xff0c;为性能、产品和技术经常开撕。但在今年的自家大会上&#xff0c;两家企业却出奇的一致&#xff0c;…

opencv+ffmpeg环境(ubuntu)搭建全面详解

一.先讲讲opencv和ffmpeg之间的关系 1.1它们之间的联系 我们知道opencv主要是用来做图像处理的&#xff0c;但也包含视频解码的功能&#xff0c;而在视频解码部分的功能opencv是使用了ffmpeg。所以它们都是可以处理图像和视频的编解码&#xff0c;我个人感觉两个的侧重点不一…

【博客684】Multi-regional高可用模式部署VictoriaMetrics

Multi-regional模式部署VictoriaMetrics 整体架构图 每个工作负载区域&#xff08;地球、火星、金星&#xff09;都有一个 vmagent&#xff0c;通过监控设置将数据发送到多个区域。监控设置&#xff08;地面控制 1,2&#xff09;包含 VictoriaMetrics 时间序列数据库 (TSDB) 集…

四姑娘山三日游

趁着小孩放暑假&#xff0c;从昆明回来之后&#xff0c;直接自驾到四姑娘山。 第一天 成都-四川省阿坝藏族羌族自治州小金县日隆镇(20230711) 大概9:30从成都市郫都区出发&#xff0c;路线如下&#xff1a;郫都—都江堰–映秀—耿达—卧龙—四姑娘山&#xff0c;中途翻过巴朗…