zoukankan      html  css  js  c++  java
  • spring boot starter开发

    作为公司的技术保障部,一直承担着技术方向的把控,最近公司准备全面转入spring boot的开发。所以我们部门也一直在调研相关的技术知识点;

    使用springboot开发应用已经有一段时间了,我们都沉醉于它简洁的配置和平滑的上手曲线。

    在springboot的开发中,starter是一个核心的配置,只需要引入对应模块的starter,然后在application.properties中引入对应的配置项,就可以开发业务逻辑了。

    这一切都归功于springboot的自动配置的能力。

    本文会从一个mybatis与spring boot结合的starter开始学习,该框架是我们提供出来,需要使用mybatis的团队只需要引入这个starter的jar包即可使用

    新建原型项目

    完整的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>
    
        <parent>
            <groupId>cn.caijiajia</groupId>
            <artifactId>springboot-parent</artifactId>
            <version>1.0.0.RELEASE</version>
        </parent>
    
        <groupId>cn.caijiajia</groupId>
        <artifactId>mybatis-starter</artifactId>
        <version>${project.release.version}</version>
        <packaging>jar</packaging>
    
        <dependencies>
            <dependency>
                <groupId>cn.caijiajia</groupId>
                <artifactId>framework-starter</artifactId>
                <version>${project.release.version}</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-jdbc</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
            </dependency>
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis-spring</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.apache.tomcat</groupId>
                <artifactId>tomcat-jdbc</artifactId>
            </dependency>
    
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
            </dependency>
    
            <dependency>
                <groupId>com.github.pagehelper</groupId>
                <artifactId>pagehelper</artifactId>
            </dependency>
    
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <scope>runtime</scope>
            </dependency>
        </dependencies>
    
    </project>
    

    开发阶段

    1.配置类 DatabaseAutoConfiguration DbProperties

    @EnableConfigurationProperties({DbProperties.class})
    public class DatabaseAutoConfiguration
            implements BeanDefinitionRegistryPostProcessor, EnvironmentAware {
    
        private static Logger log = LoggerFactory.getLogger(DatabaseAutoConfiguration.class);
    
        private Environment environment;
    
        @Override
        public void setEnvironment(Environment environment) {
            this.environment = environment;
        }
    
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        }
    
        @Override
        public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
            DbProperties dbProperties = ConfigUtil.getDbConfig(environment, DbProperties.PROPERTY_PREFIX,
                    DbProperties.class);
            // TODO 检查参数
            if (dbProperties.getDatabase() == null && dbProperties.getDatabases() != null && dbProperties
                    .getDatabases().size() == 1) {
                dbProperties.setDatabase(dbProperties.getDatabases().get(0));
            }
            initAllDataAccessBean(dbProperties, registry);
        }
    
        protected void initAllDataAccessBean(DbProperties dbProperties, BeanDefinitionRegistry registry) {
            // 单数据源
            if (dbProperties.getDatabase() != null) {
                initDataAccessBean(dbProperties.getDatabase(), null, registry);
            }
            // 多数据源
            else if (dbProperties.getDatabases() != null && dbProperties.getDatabases().size() > 0) {
                for (int i = 0; i < dbProperties.getDatabases().size(); i++) {
                    initDataAccessBean(dbProperties.getDatabases().get(i), i, registry);
                }
            }
        }
    
        /**
         * 注册一个datasource的所有bean 信息
         *
         * @param databaseConfig
         * @param index
         * @param registry
         */
        protected void initDataAccessBean(DatabaseConfig databaseConfig, Integer index, BeanDefinitionRegistry registry) {
            DataSourceConfig dataSourceConfig = databaseConfig.getDataSource();
            TransactionConfig transactionConfig = databaseConfig.getTransaction();
            MyBatisConfig myBatisConfig = databaseConfig.getMybatis();
            LogConfig logConfig = databaseConfig.getLog();
    
            // 给与默认 dataSource bean id: dataSource${index}
            if (StringUtils.isEmpty(dataSourceConfig.getName())) {
                if (index == null) {
                    dataSourceConfig.setName("dataSource");
                } else {
                    dataSourceConfig.setName("dataSource" + index);
                }
            }
    
            // 注册datasource
            registry.registerBeanDefinition(dataSourceConfig
                    .getName(), getTomcatJdbcDataSourceBeanDefinition(dataSourceConfig, logConfig));
    
            // 注册事务
            if (transactionConfig != null && transactionConfig.isEnable()) {
                if (index == null) {
                    registry.registerBeanDefinition("transactionManager", getTransactionManagerBeanDefinition(dataSourceConfig));
                } else {
                    registry.registerBeanDefinition("transactionManager" + index, getTransactionManagerBeanDefinition(dataSourceConfig));
                }
            }
    
            // 注册mybatis
            if (myBatisConfig != null) {
                final String sqlSessionFactoryBeanName = "sqlSessionFactory" + dataSourceConfig.getName();
                registry.registerBeanDefinition(sqlSessionFactoryBeanName, getSqlSessionFactoryBeanDefinition(myBatisConfig, dataSourceConfig));
                registry.registerBeanDefinition("mapperScannerConfigurer" + dataSourceConfig
                        .getName(), getMapperScannerConfigurerBeanDefinition(myBatisConfig, sqlSessionFactoryBeanName));
    
                // 给与默认 dataSource bean id: sqlSession${index}
                if (StringUtils.isEmpty(myBatisConfig.getSqlSessionBeanName())) {
                    if (index == null) {
                        myBatisConfig.setSqlSessionBeanName("sqlSession");
                    } else {
                        myBatisConfig.setSqlSessionBeanName("sqlSession" + index);
                    }
                }
                registry.registerBeanDefinition(myBatisConfig
                        .getSqlSessionBeanName(), getSqlSessionBeanDefinition(sqlSessionFactoryBeanName));
            }
        }
    
    
        /**
         * 获取 tomcat jdbc datasource bean 定义
         *
         * @param dataSourceConfig
         * @return
         */
        protected AbstractBeanDefinition getTomcatJdbcDataSourceBeanDefinition(DataSourceConfig dataSourceConfig, LogConfig logConfig) {
            if (dataSourceConfig.getMinIdle() == null) {
                dataSourceConfig.setMinIdle(dataSourceConfig.getInitialSize());
            }
            if (dataSourceConfig.getMaxIdle() == null) {
                dataSourceConfig.setMaxIdle(dataSourceConfig.getMaxActive());
            }
    
            BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder
                    .rootBeanDefinition("org.apache.tomcat.jdbc.pool.DataSource");
            definitionBuilder.setDestroyMethodName("close");
    
            // add filter
            definitionBuilder
                    .addPropertyValue("jdbcInterceptors", "cn.caijiajia.framework.db.log.TomcatJdbcLogFilter(slowLogOn=" + logConfig
                            .isSlowSqlOn() + ",slowSqlThreshold=" + logConfig.getSlowSqlThreshold() + ")");
    
            // if not set, use default value in jdbc driver
            if (dataSourceConfig.getDefaultAutoCommit() != null) {
                definitionBuilder
                        .addPropertyValue("defaultAutoCommit", dataSourceConfig.getDefaultAutoCommit());
            }
            if (dataSourceConfig.getDefaultReadOnly() != null) {
                definitionBuilder
                        .addPropertyValue("defaultReadOnly", dataSourceConfig.getDefaultReadOnly());
            }
            if (dataSourceConfig.getDefaultTransactionIsolation() != null) {
                definitionBuilder
                        .addPropertyValue("defaultTransactionIsolation", dataSourceConfig.getDefaultTransactionIsolation());
            }
    
            definitionBuilder.addPropertyValue("url", dataSourceConfig.getUrl());
            definitionBuilder.addPropertyValue("username", dataSourceConfig.getUsername());
            definitionBuilder.addPropertyValue("password", dataSourceConfig.getPassword());
            definitionBuilder.addPropertyValue("driverClassName", dataSourceConfig.getDriverClassName());
    
            // 配置初始化大小、最小、最大
            definitionBuilder.addPropertyValue("initialSize", dataSourceConfig.getInitialSize());
            definitionBuilder.addPropertyValue("minIdle", dataSourceConfig.getMinIdle());
            definitionBuilder.addPropertyValue("maxActive", dataSourceConfig.getMaxActive());
            definitionBuilder.addPropertyValue("maxIdle", dataSourceConfig.getMaxIdle());
    
            // 配置获取连接等待超时的时间
            definitionBuilder.addPropertyValue("maxWait", dataSourceConfig.getMaxWait());
            // 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫
            definitionBuilder
                    .addPropertyValue("timeBetweenEvictionRunsMillis", dataSourceConfig.getTimeBetweenEvictionRunsMillis());
            // 配置一个连接在池中最小生存的时间,单位是毫秒
            definitionBuilder
                    .addPropertyValue("minEvictableIdleTimeMillis", dataSourceConfig.getMinEvictableIdleTimeMillis());
    
            definitionBuilder.addPropertyValue("validationQuery", "select 1");
            definitionBuilder.addPropertyValue("testOnConnect", dataSourceConfig.isTestOnConnect());
            definitionBuilder.addPropertyValue("testWhileIdle", dataSourceConfig.isTestWhileIdle());
            definitionBuilder.addPropertyValue("testOnBorrow", dataSourceConfig.isTestOnBorrow());
            definitionBuilder.addPropertyValue("testOnReturn", dataSourceConfig.isTestOnReturn());
    
            definitionBuilder.addPropertyValue("removeAbandoned", dataSourceConfig.isRemoveAbandoned());
            definitionBuilder.addPropertyValue("removeAbandonedTimeout", dataSourceConfig.getRemoveAbandonedTimeout());
    
            AbstractBeanDefinition bd = definitionBuilder.getRawBeanDefinition();
            bd.setScope(BeanDefinition.SCOPE_SINGLETON);
    
            return bd;
        }
    
        /**
         * 获取mybaits SqlSessionFactory bean 定义
         *
         * @param dataSourceConfig
         * @return
         */
        protected AbstractBeanDefinition getSqlSessionFactoryBeanDefinition(MyBatisConfig myBatisConfig, DataSourceConfig dataSourceConfig) {
            BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder
                    .rootBeanDefinition(org.mybatis.spring.SqlSessionFactoryBean.class);
            definitionBuilder.addPropertyReference("dataSource", dataSourceConfig.getName());
    
            PageInterceptor pageInterceptor = new PageInterceptor();
            if (myBatisConfig.getPage().isSupportMethodsArguments()) {
                Properties pageInterceptorProperties = new Properties();
                pageInterceptorProperties.setProperty("supportMethodsArguments", "true");
                pageInterceptorProperties.setProperty("params", "pageNum=pageNum;pageSize=pageSize");
                pageInterceptor.setProperties(pageInterceptorProperties);
            }
    
            definitionBuilder
                    .addPropertyValue("plugins", new Interceptor[]{new LogInfoInterceptor(), pageInterceptor});
    
            AbstractBeanDefinition bd = definitionBuilder.getRawBeanDefinition();
            bd.setScope(BeanDefinition.SCOPE_SINGLETON);
    
            return bd;
        }
    
        /**
         * 获取mybaits MapperScannerConfigurer bean 定义
         *
         * @param myBatisConfig
         * @param sqlSessionFactoryBeanName
         * @return
         */
        protected AbstractBeanDefinition getMapperScannerConfigurerBeanDefinition(MyBatisConfig myBatisConfig, String sqlSessionFactoryBeanName) {
            BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder
                    .rootBeanDefinition(org.mybatis.spring.mapper.MapperScannerConfigurer.class);
            definitionBuilder
                    .addPropertyValue("sqlSessionFactoryBeanName", sqlSessionFactoryBeanName);
            definitionBuilder.addPropertyValue("basePackage", myBatisConfig.getBasePackage());
    
            AbstractBeanDefinition bd = definitionBuilder.getRawBeanDefinition();
            bd.setScope(BeanDefinition.SCOPE_SINGLETON);
    
            return bd;
        }
    
        /**
         * 获取mybaits SqlSessionTemplate bean 定义
         *
         * @param sqlSessionFactoryBeanName
         * @return
         */
        protected AbstractBeanDefinition getSqlSessionBeanDefinition(String sqlSessionFactoryBeanName) {
            BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder
                    .rootBeanDefinition(org.mybatis.spring.SqlSessionTemplate.class);
            definitionBuilder.addConstructorArgReference(sqlSessionFactoryBeanName);
            AbstractBeanDefinition bd = definitionBuilder.getRawBeanDefinition();
            bd.setScope(BeanDefinition.SCOPE_SINGLETON);
    
            return bd;
        }
    
        /**
         * 获取 DataSourceTransactionManager bean定义
         *
         * @param dataSourceConfig
         * @return
         */
        protected AbstractBeanDefinition getTransactionManagerBeanDefinition(DataSourceConfig dataSourceConfig) {
            BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder
                    .genericBeanDefinition(DataSourceTransactionManager.class);
            definitionBuilder.addConstructorArgReference(dataSourceConfig.getName());
            AbstractBeanDefinition bd = definitionBuilder.getRawBeanDefinition();
            bd.setScope(BeanDefinition.SCOPE_SINGLETON);
    
            return bd;
        }
    }
    

      

    @ConfigurationProperties(prefix = DbProperties.PROPERTY_PREFIX)
    public class DbProperties {
    
        public final static String PROPERTY_PREFIX = "caijiajia.db";
    
        private DatabaseConfig database;
    
        private List<DatabaseConfig> databases = new ArrayList();
    
        public DatabaseConfig getDatabase() {
            return database;
        }
    
        public void setDatabase(DatabaseConfig database) {
            this.database = database;
        }
    
        public List<DatabaseConfig> getDatabases() {
            return databases;
        }
    
        public void setDatabases(List<DatabaseConfig> databases) {
            this.databases = databases;
        }
    }
    

      

    这是两段核心配置类,其它还有一些pojo类,这里就不写出来了

    自定义spring.factories

    自定义spring.factories的步骤很简单,只需要在src/main/resource目录下创建META-INF目录,并在该目录下添加文件spring.factories,文件内容为:

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=
    cn.caijiajia.framework.db.autoconfigure.DatabaseAutoConfiguration  

    到这里通过spring boot的自动装配原理实现了配置类的自动装配

    一个简单的starter创造就完成了

      

  • 相关阅读:
    前端开发资料、实用小工具
    冒泡排序法,二分查找法
    数组练习
    一维数组练习题
    for循环输出菱形
    练习题
    课堂练习
    gO语言的安装和环境变量的配置
    PO BO VO DTO POJO DAO 概念及其作用
    BaseServlet
  • 原文地址:https://www.cnblogs.com/clovejava/p/10428063.html
Copyright © 2011-2022 走看看