<small id='FknizsbT'></small> <noframes id='U2l3'>

  • <tfoot id='yezPcYjS'></tfoot>

      <legend id='9XiRy8rQJ7'><style id='wVJhLQtH'><dir id='1XzUK'><q id='ARL3ivI'></q></dir></style></legend>
      <i id='EDazi'><tr id='EBePtLkou'><dt id='7DPU6gkZ'><q id='3UZWVjJ'><span id='jKVA'><b id='nToP'><form id='k9IU7ES0'><ins id='bmQ9Ek'></ins><ul id='rwFmc'></ul><sub id='tnJLd'></sub></form><legend id='BZgHcLu8'></legend><bdo id='WzVT'><pre id='CG4Am2D'><center id='Tq6HmueIZL'></center></pre></bdo></b><th id='0HFB'></th></span></q></dt></tr></i><div id='RO1x6G'><tfoot id='R6PwsBYS5'></tfoot><dl id='JPQC'><fieldset id='yAXG'></fieldset></dl></div>

          <bdo id='h2xXna9'></bdo><ul id='rvCbuP287'></ul>

          1. <li id='KDOko2u9'></li>
            登陆

            章鱼彩票入不了-从SpringBoot整合Mybatis剖析主动装备

            admin 2020-02-14 288人围观 ,发现0个评论

            前语

            SpringBoot凭仗"约好大于装备"的理念,已经成为最盛行的web开发结构,所以有有必要对其进行深化的了解;本文经过整合Mybatis类来剖析SpringBoot供给的主动装备(AutoConfigure)功用,在此之前首要看一个整合Mybatis的实例。

            SpringBoot整合Mybatis

            供给SpringBoot整合Mybatis的实例,经过Mybatis完结简略的增修改查功用;

            1.表数据

            CREATE TABLE `role` (
            `note` varchar(255) CHARACTER SET utf8 DEFAULT NULL,
            `role_name` varchar(255) DEFAULT NULL,
            `id` bigint(20) DEFAULT NULL
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8

            供给创立role表相关的sql,对表进行增修改查操作;

            2.整合Mybatis的依靠

            首要是mybatis-spring-boot-starter和运用的mysql驱动:


            org.mybatis.spring.boot
            mybatis-spring-boot-starter
            2.0.1


            mysql
            mysql-connector-java
            5.1.29

            3.装备application.properties

            供给衔接mysql相关的信息:url,驱动,用户名,暗码;

            spring.dat章鱼彩票入不了-从SpringBoot整合Mybatis剖析主动装备asource.url=jdbc:mysql://localhost/mybatis
            spring.datasource.username=root
            spring.datasource.password=root
            spring.datasource.driver-class-name=com.mysql.jdbc.Driver

            4.供给bean和Dao

            别离供给表对应的bean类和操作数据库的dao类;

            public class Role {
            private long id;
            private String roleName;
            private String note;
            //省掉get/set办法
            }
            @Mapper
            public interface RoleDao {
            @Select("SELECT id,role_name as roleName,note FROM role WHERE id = #{id}")
            Role findRoleById(@Param("id") long id);
            }

            5.供给Service和Controller

            public interface RoleService {
            public Role findRoleById(long roleId);
            }
            @Service
            public class RoleServiceImpl implements RoleService {
            @Autowired
            private RoleDao roleDao;
            @Override
            public Role findRoleById(long roleId) {
            return roleDao.findRoleById(roleId);
            }
            }
            @RestController
            public class RoleController {
            @Autowired
            private RoleService roleService;
            @RequestMapping("/role")
            public String getRole(long id) {
            return roleService.findRoleById(id).toString();
            }
            }

            发动服务,进行简略的测验:http://localhost:8888/role?id=111

            成果如下:

            Role [id=111, roleName=zhaohui, note=hello]

            6.提出问题

            如上实例中,咱们运用了很少的装备,就经过mybatis完结了操作数据库;正常运用mybatis需求的SqlSessionFactory和SqlSession没有看到被实例化,一起mybatis依靠的数据源也没有看到被引证,那SpringBoot是怎么帮咱们主动装备的,下面要点剖析一下;

            SpringBoot主动装备

            1.主动装备注解

            要想运用主动装备功用,SpringBoot供给了注解@EnableAutoConfiguration,当然不需求咱们装备由于在@SpringBootApplication注解中默许以及启用了;

            @Target(ElementType.TYPE)
            @Retention(RetentionPolicy.RUNTIME)
            @Documented
            @Inherited
            @SpringBootConfiguration
            @EnableAutoConfiguration
            @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
            @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
            public @interface SpringBootApplication {
            //...省掉...
            }

            能够看到@SpringBootApplication注解自身也有注解@EnableAutoConfiguration:

            @Target(ElementType.TYPE)
            @Retention(RetentionPolicy.RUNTIME)
            @Documented
            @Inherited
            @AutoConfigurationPackage
            @Import(AutoConfigurationImportSelector.class)
            public @interface EnableAutoConfiguration {
            //...省掉...
            }

            在注解@EnableAutoConfiguration中要点看一下@Import注解中运用的AutoConfigurationImportSelector类,此类是主动注解的中心类,会有条件的加载咱们默许指定的装备类;这儿有两个概念一个是有条件,一个是装备类,别离简略介绍一下:装备类能够简略了解便是相关组件对接SpringBoot的对接类,此类能够做一些初始化的作业;有条件表明并不是有装备类就能被对接上,是有条件的,SpringBoot默许供给了许多装备类,但并不是一切装备类都能被加载初始化的,是有条件的,比方mybatis在没有数据源的情况下,没有mybatis根底包的情况下是不能被对接的;下面首要看一下SpringBoot供给的哪些条件类;

            2.条件类

            SpringBoot供给了许多条件类,能够在装备中上装备注解条件类,相关条件类能够在spring-boot-autoconfigure包下的org.springframework.boot.autoconfigure.condition下找到,首要包含如下:

            • ConditionalOnBean:当时容器有指定Bean的条件下;
            • ConditionalOnClass:当时类途径下有指定类的条件下;
            • ConditionalOnCloudPlatform:当指定了云渠道的时分;
            • ConditionalOnExpression:SpEL表达式作为判别条件;
            • ConditionalOnJava:JVM版别作为判别条件;
            • ConditionalOnJndi:在JNDI存在的条件下查找指定的方位;
            • ConditionalOnMissingBean:当容器里没有指定Bean的情况下;
            • ConditionalOnMissingClass:当类途径下没有指定的类的条件下;
            • ConditionalOnNotWebApplication:当时项目不是WEB项目的条件下;
            • ConditionalOnProperty:当时运用是否装备了指定特点指定的值;
            • ConditionalOnResource:只要当指定的资源坐落类途径下;
            • ConditionalOnSingleCandidate:bean工厂中只要一个或许有多个情况下是首要的候选bean;
            • ConditionalOnWebApplication:当时项目是WEB项目的条件下。

            以上是注解类,注解自身没有功用,仅仅供给符号的功用,详细功用在@Conditional中指定的,比方ConditionalOnBean注解如下所示:

            @Target({ ElementType.TYPE, ElementType.METHOD })
            @Retention(RetentionPolicy.RUNTIME)
            @Documented
            @Conditional(OnBeanCondition.class)
            public @interface ConditionalOnBean {
            //...省掉...
            }

            相关功用的完结就在OnBeanCondition类中,相同其他注解类的完结类也在包org.springframework.boot.autoconfigure.condition下找到;

            3.主动装备进程

            Springboot运用发动进程中运用ConfigurationClassParser剖析装备类,此类中有一个processImports办法,此办法用来处理@Import注解,在@EnableAutoConfiguration注解存在@Import注解,这时分会实例化注解中的AutoConfigurationImportSelector,在其内部有一个AutoConfigurationGroup内部类,内部类有两个中心办法别离是:process和selectImports;

             @Override
            public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
            Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
            () -> String.format("Only %s implementations are supported, got %s",
            AutoConfigurationImportSelector.class.getSimpleName(),
            deferredImportSelector.getClass().getName()));
            AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
            .getAutoConfigurationEntry(getAutoConfigurationMetadata(),章鱼彩票入不了-从SpringBoot整合Mybatis剖析主动装备 annotationMetadata);
            this.autoConfigurationEntries.add(autoConfigurationEntry);
            for (String importClassName : autoConfigurationEntry.getConfigurations()) {
            this.entries.putIfAbsent(importClassName, annotationMetadata);
            }
            }

            此办法首要获取经过条件过滤之后可用的主动装备类,首要调用AutoConfigurationImportSelector中的getAutoConfigurationEntry完结的:

             protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
            AnnotationMetadata annotationMetadata) {
            if (!isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
            }
            AnnotationAttributes attributes = getAttributes(annotationMetadata);
            List configurations = getCandidateConfigurations(annotationMetadata, attributes);
            configurations = removeDuplicates(configurations);
            Set exclusions = getExclusions(annotationMetadata, attributes);
            checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = filter(configurations, autoConfigurationMetadata);
            fireAutoConfigurationImportEvents(configurations, exclusions);
            return new AutoConfigurationEntry(configurations, exclusions);
            }

            首要获取了一切备选的主动装备类,然后删除了重复和被扫除的类,最终经过条件进行筛选出可用的装备类,下面别离看一下,首要看一下怎么获取一切备选的装备类:

             protected List getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
            List configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
            getBeanClassLoader());
            Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
            + "are using a custom packaging, make sure that file is correct.");
            return configurations;
            }

            经过SpringFactoriesLoader获取类途径下META-INF/spring.factories文件中key为org.springframework.boot.autoconfigure.EnableAutoConfiguration的装备类,能够看一下spring-boot-autoconfigure.jar中的spring.factories内容:

            # Auto Configure
            org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
            org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
            org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
            org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
            org.springframework.boot.autoconfigure.batch.Batc章鱼彩票入不了-从SpringBoot整合Mybatis剖析主动装备hAutoConfiguration,\
            org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
            org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
            org.springframework.boot.autoconfigure.cloud.CloudServiceConnectorsAutoConfiguration,\
            //...以下省掉...

            当然这儿仅仅截取了其间一个类途径jar下的部分装备,获取一切装备类之后进行去重,去被扫除的类,然后进行条件过滤,下面要点看一下:

            private List filter(List configurations, AutoConfigurationMetadata autoConfigurationMetadata) {
            long startTime = System.nanoTime();
            String[] candidates = StringUtils.toStringArray(configurations);
            boolean[] skip = new boolean[candidates.length];
            boolean skipped = false;
            for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
            invokeAwareMethods(filter);
            boolean[] match = filter.match(candidates, autoConfigurationMetadata);
            for (int i = 0; i < match.length; i++) {
            if (!match[i]) {
            skip[i] = true;
            candidates[i] = null;
            skipped = true;
            }
            }
            }
            if (!skipped) {
            return configurations;
            }
            List result = new ArrayList<>(candidates.length);
            for (int i = 0; i < candidates.length; i++) {
            if (!skip[i]) {
            result.add(candidates[i]);
            }
            }
            if (logger.isTraceEnabled()) {
            int numberFiltered = configurations.size() - result.size();
            logger.trace("Filtered " + numberFiltered + " auto configuration class in "
            + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms");
            }
            return new ArrayList<>(result);
            }

            此办法大致便是首要获取装备的AutoConfigurationImportFilter ,然后对之前获取的一切装备类进行过滤,最终回来过滤之后的装备类;AutoConfigurationImportFilter相同也是经过SpringFactoriesLoader类进行加载类途径下META-INF/spring.factories,只不过当时的key是:org.springframework.boot.autoconfigure.AutoConfigurationImportFilter,能够看一下SpringBoot默许装备的filter:

            # Auto Configuration Import Filters
            org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
            org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
            org.springframework.boot.autoconfigure.condition.OnClassCondition,\
            org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition

            能够看到Filter其实便是上文介绍的条件类,这儿默许了OnBeanCondition,OnClassCondition以及OnWebApplicationCondition,已这儿运用的Mybatis为例看一下MybatisAutoConfiguration的注解:

            @org.springframework.context.annotation.Configuration
            @ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })
            @ConditionalOnSingleCandidate(DataSource.class)
            @EnableConfigurationProperties(MybatisProperties.class)
            @AutoConfigureAfter(DataSourceAutoConfig章鱼彩票入不了-从SpringBoot整合Mybatis剖析主动装备uration.class)
            public class MybatisAutoConfiguration implements InitializingBean {
            //...以下省掉...
            }

            能够看到其间有用到@ConditionalOnClass,表明有必要供给SqlSessionFactory和SqlSessionFactoryBean类的情况下才加载此装备类,而整两个是正式Mybatis根底包中供给的;有了根底包还不可,还需求DataSource,并且DataSource有必要在MybatisAutoConfiguration实例化之前初始化好,SpringBoot是怎么完结,持续看别的一个中心办法selectImports():

             @Override
            public Iterable selectImports() {
            if (this.autoConfigurationEntries.isEmpty()) {
            return Collections.emptyList();
            }
            Set allExclusions = this.autoConfigurationEntries.stream()
            .map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet());
            Set processedConfigurations = this.autoConfigurationEntries.stream()
            .map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream)
            .collect(Collectors.toCollection(LinkedHashSet::new));
            processedConfigurations.removeAll(allExclusions);
            return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream()
            .map((importClassName) -> new Entry(this.entries.get(importClassName), importClassName))
            .collect(Collectors.toList());
            }
            private List sortAutoConfigurations(Set configurations,
            AutoConfigurationMetadata autoConfigurationMetadata) {
            return new AutoConfigurationSorter(getMetadataReaderFactory(), autoConfigurationMetadata)
            .getInPriorityOrder(configurations);
            }

            首要是对被扫除类的一个过滤,然后接下来要点看一下对装备类进行排序的一个办法,详细操作在类AutoConfigurationSorter中进行的,详细办法为getInPriorityOrder():

             public List getInPriorityOrder(Collection classNames) {
            AutoConfigurationClasses classes = new AutoConfigurationClasses(this.metadataReaderFactory,
            this.autoConfigurationMetadata, classNames);
            List orderedClassNames = ne章鱼彩票入不了-从SpringBoot整合Mybatis剖析主动装备w ArrayL章鱼彩票入不了-从SpringBoot整合Mybatis剖析主动装备ist<>(classNames);
            // Initially sort alphabetically
            Collections.sort(orderedClassNames);
            // Then sort by order
            orderedClassNames.sort((o1, o2) -> {
            int i1 = classes.get(o1).getOrder();
            int i2 = classes.get(o2).getOrder();
            return Integer.compare(i1, i2);
            });
            // Then respect @AutoConfigureBefore @AutoConfigureAfter
            orderedClassNames = sortByAnnotation(classes, orderedClassNames);
            return orderedClassNames;
            }

            首要运用order进行排序,然后运用@AutoConfigureBefore和@AutoConfigureAfter就行排序;order其实便是经过注解@AutoConfigureOrder进行排序的,值是一个整数,结构相似如下:

            @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)

            @AutoConfigureBefore和@AutoConfigureAfter字面意思也很好了解,指定在其他装备类之前和之后,所以能够看到在MybatisAutoConfiguration中有如下装备:

            @AutoConfigureAfter(DataSourceAutoConfiguration.class)

            表明在DataSourceAutoConfiguration装备类加载之后才会加载Mybatis装备类,这样就处理了依靠联系;还有上文说到的Mybatis操作数据库依靠的SqlSessionFactory和SqlSession,都在MybatisAutoConfiguration进行了初始化操作;SpringBoot自身其实以及供给了许多常用组件的主动装备类,咱们只需求供给满意的特定条件,SpringBoot主动会帮我加载初始化等操作,可是必定也有自定义装备类的需求,下面用一个简略的实例来看看怎么自定义一个主动装备类;

            自定义装备类

            接下来咱们用很简略的实例来看一下自定义的流程,一个格局化大写音讯的实例;

            1.pom文件引进依靠

            com.format
            format-spring-boot-starter
            0.0.1-SNAPSHOT
            jar
            format-spring-boot-starter
            http://maven.apache.org

            1.8
            UTF-8



            org.springframework.boot
            spring-boot-autoconfigure






            org.springframework.boot
            spring-boot-dependencies
            1.5.2.RELEASE
            pom
            import



            Spring 官方 Starter一般命名为spring-boot-starter-{name}如 spring-boot-starter-web,Spring官方主张非官方Starter命名应遵从{name}-spring-boot-starter的格局;

            2.服务类和特点装备类

            @ConfigurationProperties("format.service")
            public class FormatServiceProperties {
            private String type;
            //...get/set省掉...
            }
            public class FormatService {
            private String type;
            public FormatService(String type) {
            this.type = type;
            }
            public String wrap(String word) {
            if(type.equalsIgnoreCase("Upper")){//大写
            return word.toUpperCase();
            }else if(type.equalsIgnoreCase("Lower")){//小写
            return word.toLowerCase();
            }
            return word;
            }
            }

            特点类供给了type参数能够在application.properties中装备,可装备值包含:upper,lower;

            3.主动装备类和创立spring.factories文件

            @Configuration
            @ConditionalOnClass(FormatService.class)
            @EnableConfigurationProperties(FormatServiceProperties.class)
            public class FormatAutoConfigure {
            @Autowired
            private FormatServiceProperties properties;
            @Bean
            @ConditionalOnMissingBean
            FormatService formatService() {
            return new FormatService(properties.getType());
            }
            }

            这个便是自定义的主动装备类,SpringBoot发动的时分会依据条件主动初始天山化;最终在resources/META-INF/下创立spring.factories文件:

            org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.format.FormatAutoConfigure

            4.测验

            在其他SpringBoot中能够引进上面创立的项目,引进方法也很简略:


            com.format
            format-spring-boot-starter
            0.0.1-SNAPSHOT

            一起在application.properties装备格局化类型:

            format.service.type=upper

            发动运用,浏览器拜访http://localhost:8888/format?word=hello,成果为:HELLO

            总结

            本文从运用SpringBoot整合Mybatis开端,然后提出运用中发生的疑问,从而经过剖析源码的方法来了解SpringBoot的主动装备机制,最终自定义了一个主动装备类来看看详细怎么运用;SpringBoot经过主动装备的方法协助开发者减少了很大的作业量,到达开箱即用的作用;可是另一方面假如出现问题需求调试或许不是那么好定位。

            示例代码地址

            https://github.com/ksfzhaohui/blog.git

            请关注微信公众号
            微信二维码
            不容错过
            Powered By Z-BlogPHP