最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

mybatis-spring:@MapperScan注解的使用

 更新時間:2021年09月14日 09:50:39   作者:NetWhite  
這篇文章主要介紹了mybatis-spring:@MapperScan注解的使用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

mybatis-spring:@MapperScan注解

demo: springboot+mybatis的示例中,dao層接口使用了注解@MapperScan:指定掃描com.xuxd.demo.dao.UserDao所在包路徑下的所有接口類。

本文分析下@MapperScan注解做了哪些動作。

@MapperScan源碼

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
public @interface MapperScan { 
  /**
   *缺省屬性(==basePackages),basePackages的別名
   */
  String[] value() default {};
 
  /**
   * 哪些包路徑下的接口被掃描注冊(接口至少有一個方法),具體實現(xiàn)類(非接口)忽略
   */
  String[] basePackages() default {};
 
  /**
   * 指定類所在包下所有接口被掃描注冊(接口至少有一個方法),具體實現(xiàn)類(非接口)忽略
   */
  Class<?>[] basePackageClasses() default {};
 
  /**
   * 掃描到的滿足條件的接口,首先要把它們相關(guān)bean定義注冊到spring容器中吧,注冊bean定義
   * 的時候,需要定義bean名稱,這個是用來自定方生成bean名稱的策略組件,個人覺得很少用
   */
  Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
 
  /**
   * 這個注解指定的接口也要被掃描
   */
  Class<? extends Annotation> annotationClass() default Annotation.class;
 
  /**
   * 繼承這個接口的接口也要被掃描
   */
  Class<?> markerInterface() default Class.class;
 
  /**
   * 多數(shù)據(jù)源的時候可能用到這個,后面單獨說明這個
   */
  String sqlSessionTemplateRef() default "";
 
  /**
   * 多數(shù)據(jù)源的時候可能用到這個,后面單獨說明這個
   */
  String sqlSessionFactoryRef() default "";
 
  /**
   * 多數(shù)據(jù)源的時候可能用到這個,后面單獨說明這個
   */
  Class<? extends MapperFactoryBean> factoryBean() default MapperFactoryBean.class; 
}

這個注解的重點是@Import(MapperScannerRegistrar.class)

使用這個注解導(dǎo)入MapperScannerRegistrar主要完成兩件事:

1. 掃描指定接口

2. 注冊這些接口的bean定義到spring容器

接下來進入MapperScannerRegistrar類看下是如何完成這兩動作:

MapperScannerRegistrar.class

public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {}

這個類實現(xiàn)了ImportBeanDefinitionRegistrar接口:

public interface ImportBeanDefinitionRegistrar { 
 public void registerBeanDefinitions(
   AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry); 
}

@MapperScan注解類上使用了@Import注解導(dǎo)入了這個接口的實現(xiàn)類(MapperScannerRegistrar.class),因此spring解析MybatisConfig(源碼:demo: springboot+mybatis)這個類的時候,解析到這個類上使用了注解@MapperScan,從MapperScan注解類上(注解都是一個接口,java會創(chuàng)建代理類)發(fā)現(xiàn)了@Import注解及MapperScannerRegistrar類(因為Import注解是導(dǎo)入配置類的)。

在加載MybatisConfig配置類的bean定義時候,找到了ImportBeanDefinitionRegistrar 的實現(xiàn)類MapperScannerRegistrar,便會回調(diào)這個MapperScannerRegistrar的registerBeanDefinitions方法。

總之一句話:

在加載配置類MybatisConfig的bean定義的時候,會調(diào)用與之看起來有點關(guān)系的MapperScannerRegistrar的registerBeanDefinitions方法。

MapperScannerRegistrar的registerBeanDefinitions方法第一個參數(shù)importingClassMetadata指的是MybatisConfig這個類的。

可以debug,看這個參數(shù)的信息。

  @Override
  public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
 
    AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
    ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
 
    // this check is needed in Spring 3.1
    if (resourceLoader != null) {
      scanner.setResourceLoader(resourceLoader);
    }
 
    Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
    if (!Annotation.class.equals(annotationClass)) {
      scanner.setAnnotationClass(annotationClass);
    }
 
    Class<?> markerInterface = annoAttrs.getClass("markerInterface");
    if (!Class.class.equals(markerInterface)) {
      scanner.setMarkerInterface(markerInterface);
    }
 
    Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
    if (!BeanNameGenerator.class.equals(generatorClass)) {
      scanner.setBeanNameGenerator(BeanUtils.instantiateClass(generatorClass));
    }
 
    Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
    if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
      scanner.setMapperFactoryBean(BeanUtils.instantiateClass(mapperFactoryBeanClass));
    }
 
    scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef"));
    scanner.setSqlSessionFactoryBeanName(annoAttrs.getString("sqlSessionFactoryRef"));
 
    List<String> basePackages = new ArrayList<String>();
    for (String pkg : annoAttrs.getStringArray("value")) {
      if (StringUtils.hasText(pkg)) {
        basePackages.add(pkg);
      }
    }
    for (String pkg : annoAttrs.getStringArray("basePackages")) {
      if (StringUtils.hasText(pkg)) {
        basePackages.add(pkg);
      }
    }
    for (Class<?> clazz : annoAttrs.getClassArray("basePackageClasses")) {
      basePackages.add(ClassUtils.getPackageName(clazz));
    }
    scanner.registerFilters();
    scanner.doScan(StringUtils.toStringArray(basePackages));
  }

看這個方法的源碼,主要完成2件事:

1. 解析MapperScan注解的各個字段的值 ,用以初始化類路徑掃描器

2. 確定掃描類路徑下哪些接口,如指定的包路徑、指定的類所在包路徑。上面倒數(shù)第2行代碼,注冊過濾器,用來指定包含哪些注解或接口的掃描(@MapperScan的annotationClass的markerInterface屬性,如果設(shè)置的話)

因此,重點是最后一行代碼doScan的調(diào)用。

這里不貼源碼了,前文提到,MapperScannerRegistrar主要完成兩件事,都會在這里完成,解析包路徑,掃描指定接口并注冊bean定義到spring容器。

definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName()); // issue #59
definition.setBeanClass(this.mapperFactoryBean.getClass());
definition.getPropertyValues().add("addToConfig", this.addToConfig);

在ClassPathMapperScanner類的processBeanDefinitions方法內(nèi)看到這里注冊的一個spring的工廠bean:

public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> { 
  ...
  @Override
  public T getObject() throws Exception {
    return getSqlSession().getMapper(this.mapperInterface);
  }
 
  @Override
  public Class<T> getObjectType() {
    return this.mapperInterface;
  }
 
  @Override
  public boolean isSingleton() {
    return true;
  }
...
}

大部分代碼刪除了, 只留下這幾個說明。

不了解 spring的FactoryBean的建議查看下相關(guān)文檔。

這里用直白的話說,就是:

我在service層需要注入這個Dao層接口的bean(比如demo: springboot+mybatis中UserServiceImpl類的UserDao字段的自動注入),依據(jù)類型注入。

spring在自己的容器里翻呀翻,如果是普通bean,一看和這個接口類型(UserDao)都不匹配就換一個,找到了這個工廠bean,一看是工廠bean,就不能直接做類型匹配了,而是調(diào)用getObjectType方法,把返回的類型和需要被注入字段的類型一比較,正好匹配(都是UserDao類型),就調(diào)用這個工廠bean的getObject方法返回這個對象,然后通過反射等操作,把這個值注入到這個字段中。而調(diào)用getObject方法,其實就是我們平常直接用mybatis的接口返回的一個MapperProxy的代理對象的操作了。

demo: springboot+mybatis

最近因工作原因,需要研究下spring的事務(wù)部分和mybatis的多數(shù)據(jù)源的源碼實現(xiàn),這樣才能更容易的在代碼層面通過擴展/重寫等方式去定制自己的實現(xiàn)。

以前雖然用過幾次mybatis,但是卻一直沒抽出時間認真翻看下源碼,趁這次機會,花點時間研究下,順便做個筆記。

關(guān)于看源碼,我向來是覺得只有一步步去debug整個流程,查看每一步的數(shù)據(jù)流向和數(shù)據(jù)狀態(tài),才會有個更清晰的深知。如果只是看的話,有些源碼中各種繼承、適配、代理、裝飾等,會分不清當前使用的到底是哪個類。

于是乎,所謂工欲善其事,必先利其器。先搭建個極簡單的mybatis的工程環(huán)境,用來調(diào)試源碼。

這個工程用了spring boot+mybatis。mybatis采用java config的形式(是真心不喜歡xml配置,所以源碼研究上也會避開xml的加載)

后面博文關(guān)于分析描述就會針對這個工程的配置來說了。

另外,代碼中關(guān)于spring事務(wù)的注解先注釋了。

說了這么多,是希望緩解自己又寫了篇這么沒技術(shù)含量的博客的尷尬,哎,最近這段時間寫的博客確實有些湊數(shù)了。

工程代碼

數(shù)據(jù)庫腳本:

CREATE DATABASE `testdb` /*!40100 DEFAULT CHARACTER SET utf8 */
 
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `age` int(11) NOT NULL,
  `username` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;

工程結(jié)構(gòu)

按工程結(jié)構(gòu),列一下文件代碼:

User.java

public class User {
    int id;
    int age;
    String username; 
    public User() {
    }
 
    public User(int id, int age, String username) {
        this.id = id;
        this.age = age;
        this.username = username;
    }
 
    public int getId() {
        return id;
    }
 
    public void setId(int id) {
        this.id = id;
    }
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
 
    public String getUsername() {
        return username;
    }
 
    public void setUsername(String username) {
        this.username = username;
    }
 
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", age=" + age +
                ", username='" + username + '\'' +
                '}';
    }
}

MybatisConfig.java

@Configuration
@MapperScan(basePackageClasses = {UserDao.class})
//@EnableTransactionManagement //啟用spring事務(wù)
public class MybatisConfig { 
    @Autowired
    private Environment environment;
 
    // 數(shù)據(jù)源配置
    @Bean
    public DataSource dataSource() {
        // mybatis自帶的一個簡易數(shù)據(jù)庫連接池,只是為了debug代碼,這個就不關(guān)心了
        PooledDataSource pooledDataSource = new PooledDataSource();
        pooledDataSource.setDriver(environment.getProperty("mysql.driver"));
        pooledDataSource.setUsername(environment.getProperty("mysql.username"));
        pooledDataSource.setPassword(environment.getProperty("mysql.passwd"));
        pooledDataSource.setUrl(environment.getProperty("mysql.url"));
        return pooledDataSource;
    }
 
    // spring事務(wù)管理的基礎(chǔ)bean,事務(wù)部分會用到
    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource) {
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource);
        return transactionManager;
    }
 
    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) throws IOException {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
        sqlSessionFactoryBean.setMapperLocations(resourcePatternResolver.getResources("classpath:/mapper/*.xml"));
        return sqlSessionFactoryBean;
    }
}

UserController.java

@RestController
@RequestMapping("/user")
public class UserController { 
    @Autowired
    IUserService userService; 
    @GetMapping("/save")
    public String saveUser() {
        User user = new User(10, 100, "test user");
        try {
            return userService.saveUser(user) ? "save success" : "save fail";
        } catch (Exception ignore) {
            ignore.printStackTrace();// 不打印日志了,堆棧信息直接打到控制臺看
            return "save error: " + ignore.getMessage();
        } 
    }
 
    @GetMapping("/list")
    public String getUsers() throws Exception {
        return userService.getUsers().toString();
    }
 
    @GetMapping("/delete")
    public String deleteUser() throws Exception {
        return userService.deleteUser() ? "delete success" : "delete fail";
    }
}

UserDao.java

@Repository
public interface UserDao { 
    boolean saveUser(User user); 
    List<User> getUsers(); 
    boolean deleteUser(); 
}

UserServiceImpl.java

@Service
public class UserServiceImpl implements IUserService { 
    @Autowired
    UserDao userDao; 
    //@Transactional //指定這個方法的事務(wù)屬性
    @Override
    public boolean saveUser(User user) throws Exception {
        boolean success = userDao.saveUser(user);
        // spring事務(wù)能力測試的時候,使用下面這段代碼
        /*if (true) {
            throw new RuntimeException();
        }*/
        return success;
    }
 
    @Override
    public List<User> getUsers() throws Exception {
        return userDao.getUsers();
    }
 
    @Override
    public boolean deleteUser() throws Exception {
        return userDao.deleteUser();
    }
}

IUserService.java

public interface IUserService { 
    boolean saveUser(User user) throws Exception; 
    List<User> getUsers() throws Exception; 
    boolean deleteUser() throws Exception; 
}

WebApplication.java

@SpringBootApplication
public class WebApplication { 
    public static void main(String[] args) {
        SpringApplication.run(WebApplication.class, args);
    }
}

UserMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org/DTD Mapper 3.0" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xuxd.demo.dao.UserDao">
 
    <sql id="user_column">
        id,age,username
    </sql>
 
    <select id="getUsers" resultType="com.xuxd.demo.beans.User">
        select * from user
    </select>
 
    <!--  增加用戶 -->
    <insert id="saveUser" parameterType="com.xuxd.demo.beans.User">
        insert into user
        (<include refid="user_column"/>)
        values
        (#{id},#{age},#{username})
    </insert>
 
    <delete id="deleteUser">
        DELETE from USER where id = 10
    </delete>
 
</mapper>

application.properties

#data source config
mysql.driver=com.mysql.jdbc.Driver
mysql.username=root
mysql.passwd=123456
mysql.url=jdbc:mysql://localhost:3306/testdb?useSSL=false

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
 
    <groupId>com.xuxd</groupId>
    <artifactId>spring-mybatis.demo</artifactId>
    <version>1.0-SNAPSHOT</version>
 
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.6.RELEASE</version>
    </parent>
 
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
 
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>4.3.1.RELEASE</version>
        </dependency>
 
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.3.1</version>
        </dependency>
 
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.2.5</version>
        </dependency>
 
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.43</version>
        </dependency>
    </dependencies>
</project>

后續(xù)就用這個工程debug源碼了。

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • idea中mapper如何快速跳轉(zhuǎn)到xml插件

    idea中mapper如何快速跳轉(zhuǎn)到xml插件

    這篇文章主要介紹了idea中mapper如何快速跳轉(zhuǎn)到xml插件問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • Java?并發(fā)編程之ForkJoin框架

    Java?并發(fā)編程之ForkJoin框架

    這篇文章主要為大家介紹了Java?ForkJoin框架,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助,希望能夠給你帶來幫助
    2021-11-11
  • java計算代碼段執(zhí)行時間的詳細代碼

    java計算代碼段執(zhí)行時間的詳細代碼

    java里計算代碼段執(zhí)行時間可以有兩種方法,一種是毫秒級別的計算,另一種是更精確的納秒級別的計算,這篇文章主要介紹了java計算代碼段執(zhí)行時間,需要的朋友可以參考下
    2022-08-08
  • java字符串求并集的方法

    java字符串求并集的方法

    這篇文章主要介紹了java字符串求并集的方法,涉及Java字符串操作中union方法的使用,是Java字符串操作中非常實用的基本技巧,需要的朋友可以參考下
    2014-11-11
  • MyBatis在注解上使用動態(tài)SQL方式(@select使用if)

    MyBatis在注解上使用動態(tài)SQL方式(@select使用if)

    這篇文章主要介紹了MyBatis在注解上使用動態(tài)SQL方式(@select使用if),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • Java使用StampedLock實現(xiàn)高效讀寫功能

    Java使用StampedLock實現(xiàn)高效讀寫功能

    StampedLock 是 Java 8 引入的高性能鎖,提供了三種鎖模式:寫鎖、悲觀讀鎖和樂觀讀鎖,與傳統(tǒng)的 ReentrantReadWriteLock 相比,StampedLock 更注重性能,特別適合讀多寫少的場景,所以本文給大家介紹了Java使用StampedLock實現(xiàn)高效讀寫功能,需要的朋友可以參考下
    2025-01-01
  • java 實現(xiàn)雙向鏈表實例詳解

    java 實現(xiàn)雙向鏈表實例詳解

    這篇文章主要介紹了java 實現(xiàn)雙向鏈表實例詳解的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • 快速解決 MyBatis-Plus 中 ID 自增問題(推薦)

    快速解決 MyBatis-Plus 中 ID 自增問題(推薦)

    本文介紹了MyBatis-Plus中自動生成ID過長導(dǎo)致的問題及解決方法,結(jié)合示例代碼給大家介紹的非常詳細,感興趣的朋友一起看看吧
    2025-02-02
  • 使用filter實現(xiàn)url級別內(nèi)存緩存示例

    使用filter實現(xiàn)url級別內(nèi)存緩存示例

    這篇文章主要介紹了使用filter實現(xiàn)url級別內(nèi)存緩存示例,只需要一個靜態(tài)類,在filter中調(diào)用,也可以全部寫到filt里面??梢愿鶕?jù)查詢參數(shù)分別緩存,需要的朋友可以參考下
    2014-03-03
  • Java入門基礎(chǔ)之抽象類與接口

    Java入門基礎(chǔ)之抽象類與接口

    對于面向?qū)ο缶幊虂碚f,抽象是它的一大特征之一,在 Java 中可以通過兩種形式來體現(xiàn)OOP的抽象:接口和抽象類,下面這篇文章主要給大家介紹了關(guān)于Java入門基礎(chǔ)之抽象類與接口的相關(guān)資料,需要的朋友可以參考下
    2022-02-02

最新評論

呈贡县| 越西县| 贡觉县| 西安市| 遵化市| 鹰潭市| 年辖:市辖区| 蓬莱市| 车致| 浑源县| 台东市| 平陆县| 河北省| 怀仁县| 景宁| 日土县| 金川县| 浦北县| 雷山县| 扬州市| 和田市| 桑日县| 茌平县| 土默特右旗| 赫章县| 泰州市| 两当县| 揭东县| 白山市| 五莲县| 金堂县| 棋牌| 宜宾市| 竹北市| 安阳市| 都江堰市| 安阳县| 威远县| 蓬溪县| 托里县| 梨树县|