在前面使用SSM集成时,我们可以使用注解实现无配置化注入,但是这种依赖被进行“人工干预了的”,换句话就是说我们手动进行装配,那么此时还没有达到SpringBoot这种自动装配的效果,那么究竟SpringBoot如何进行自动装配的呢?下面我们就一探究竟

一。SpringBoot中创建对象的注解扩充

  其实说白了,SpringBoot并不属于一种新的技术,只不过Spring-Boot-Starter-xxxx的启动器帮我们配置了若干个被Spring管理的bean,当我们的项目依赖这些jar并启动Spring应用时,Spring的Container容器已经把jar包下的对象加以创建及管理了,我们请看下面的例子:

该例子是spring-boot-autoconfigure-2.0.0.M7.jar包的内容,我们找到如下类: DispatcherServletAutoConfiguration ,我贴出源代码:

  1. /*
  2. * Copyright 2012-2017 the original author or authors.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16.  
  17. package org.springframework.boot.autoconfigure.web.servlet;
  18.  
  19. import java.util.Arrays;
  20. import java.util.List;
  21.  
  22. import javax.servlet.MultipartConfigElement;
  23. import javax.servlet.ServletRegistration;
  24.  
  25. import org.springframework.beans.factory.ObjectProvider;
  26. import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
  27. import org.springframework.boot.autoconfigure.AutoConfigureAfter;
  28. import org.springframework.boot.autoconfigure.AutoConfigureOrder;
  29. import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
  30. import org.springframework.boot.autoconfigure.condition.ConditionMessage;
  31. import org.springframework.boot.autoconfigure.condition.ConditionMessage.Style;
  32. import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
  33. import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
  34. import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
  35. import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
  36. import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
  37. import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
  38. import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
  39. import org.springframework.boot.autoconfigure.web.ServerProperties;
  40. import org.springframework.boot.context.properties.EnableConfigurationProperties;
  41. import org.springframework.boot.web.servlet.ServletRegistrationBean;
  42. import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
  43. import org.springframework.context.annotation.Bean;
  44. import org.springframework.context.annotation.ConditionContext;
  45. import org.springframework.context.annotation.Conditional;
  46. import org.springframework.context.annotation.Configuration;
  47. import org.springframework.context.annotation.Import;
  48. import org.springframework.core.Ordered;
  49. import org.springframework.core.annotation.Order;
  50. import org.springframework.core.type.AnnotatedTypeMetadata;
  51. import org.springframework.web.multipart.MultipartResolver;
  52. import org.springframework.web.servlet.DispatcherServlet;
  53.  
  54. /**
  55. * {@link EnableAutoConfiguration Auto-configuration} for the Spring
  56. * {@link DispatcherServlet}. Should work for a standalone application where an embedded
  57. * web server is already present and also for a deployable application using
  58. * {@link SpringBootServletInitializer}.
  59. *
  60. * @author Phillip Webb
  61. * @author Dave Syer
  62. * @author Stephane Nicoll
  63. * @author Brian Clozel
  64. */
  65. @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
  66. @Configuration
  67. @ConditionalOnWebApplication(type = Type.SERVLET)
  68. @ConditionalOnClass(DispatcherServlet.class)
  69. @AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)
  70. @EnableConfigurationProperties(ServerProperties.class)
  71. public class DispatcherServletAutoConfiguration {
  72.  
  73. /*
  74. * The bean name for a DispatcherServlet that will be mapped to the root URL "/"
  75. */
  76. public static final String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = "dispatcherServlet";
  77.  
  78. /*
  79. * The bean name for a ServletRegistrationBean for the DispatcherServlet "/"
  80. */
  81. public static final String DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME = "dispatcherServletRegistration";
  82.  
  83. @Configuration
  84. @Conditional(DefaultDispatcherServletCondition.class)
  85. @ConditionalOnClass(ServletRegistration.class)
  86. @EnableConfigurationProperties(WebMvcProperties.class)
  87. protected static class DispatcherServletConfiguration {
  88.  
  89. private final WebMvcProperties webMvcProperties;
  90.  
  91. public DispatcherServletConfiguration(WebMvcProperties webMvcProperties) {
  92. this.webMvcProperties = webMvcProperties;
  93. }
  94.  
  95. @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
  96. public DispatcherServlet dispatcherServlet() {
  97. DispatcherServlet dispatcherServlet = new DispatcherServlet();
  98. dispatcherServlet.setDispatchOptionsRequest(
  99. this.webMvcProperties.isDispatchOptionsRequest());
  100. dispatcherServlet.setDispatchTraceRequest(
  101. this.webMvcProperties.isDispatchTraceRequest());
  102. dispatcherServlet.setThrowExceptionIfNoHandlerFound(
  103. this.webMvcProperties.isThrowExceptionIfNoHandlerFound());
  104. return dispatcherServlet;
  105. }
  106.  
  107. @Bean
  108. @ConditionalOnBean(MultipartResolver.class)
  109. @ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
  110. public MultipartResolver multipartResolver(MultipartResolver resolver) {
  111. // Detect if the user has created a MultipartResolver but named it incorrectly
  112. return resolver;
  113. }
  114.  
  115. }
  116.  
  117. @Configuration
  118. @Conditional(DispatcherServletRegistrationCondition.class)
  119. @ConditionalOnClass(ServletRegistration.class)
  120. @EnableConfigurationProperties(WebMvcProperties.class)
  121. @Import(DispatcherServletConfiguration.class)
  122. protected static class DispatcherServletRegistrationConfiguration {
  123.  
  124. private final ServerProperties serverProperties;
  125.  
  126. private final WebMvcProperties webMvcProperties;
  127.  
  128. private final MultipartConfigElement multipartConfig;
  129.  
  130. public DispatcherServletRegistrationConfiguration(
  131. ServerProperties serverProperties, WebMvcProperties webMvcProperties,
  132. ObjectProvider<MultipartConfigElement> multipartConfigProvider) {
  133. this.serverProperties = serverProperties;
  134. this.webMvcProperties = webMvcProperties;
  135. this.multipartConfig = multipartConfigProvider.getIfAvailable();
  136. }
  137.  
  138. @Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
  139. @ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
  140. public ServletRegistrationBean<DispatcherServlet> dispatcherServletRegistration(
  141. DispatcherServlet dispatcherServlet) {
  142. ServletRegistrationBean<DispatcherServlet> registration = new ServletRegistrationBean<>(
  143. dispatcherServlet,
  144. this.serverProperties.getServlet().getServletMapping());
  145. registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
  146. registration.setLoadOnStartup(
  147. this.webMvcProperties.getServlet().getLoadOnStartup());
  148. if (this.multipartConfig != null) {
  149. registration.setMultipartConfig(this.multipartConfig);
  150. }
  151. return registration;
  152. }
  153.  
  154. }
  155.  
  156. @Order(Ordered.LOWEST_PRECEDENCE - 10)
  157. private static class DefaultDispatcherServletCondition extends SpringBootCondition {
  158.  
  159. @Override
  160. public ConditionOutcome getMatchOutcome(ConditionContext context,
  161. AnnotatedTypeMetadata metadata) {
  162. ConditionMessage.Builder message = ConditionMessage
  163. .forCondition("Default DispatcherServlet");
  164. ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
  165. List<String> dispatchServletBeans = Arrays.asList(beanFactory
  166. .getBeanNamesForType(DispatcherServlet.class, false, false));
  167. if (dispatchServletBeans.contains(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)) {
  168. return ConditionOutcome.noMatch(message.found("dispatcher servlet bean")
  169. .items(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME));
  170. }
  171. if (beanFactory.containsBean(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)) {
  172. return ConditionOutcome
  173. .noMatch(message.found("non dispatcher servlet bean")
  174. .items(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME));
  175. }
  176. if (dispatchServletBeans.isEmpty()) {
  177. return ConditionOutcome
  178. .match(message.didNotFind("dispatcher servlet beans").atAll());
  179. }
  180. return ConditionOutcome.match(message
  181. .found("dispatcher servlet bean", "dispatcher servlet beans")
  182. .items(Style.QUOTE, dispatchServletBeans)
  183. .append("and none is named " + DEFAULT_DISPATCHER_SERVLET_BEAN_NAME));
  184. }
  185.  
  186. }
  187.  
  188. @Order(Ordered.LOWEST_PRECEDENCE - 10)
  189. private static class DispatcherServletRegistrationCondition
  190. extends SpringBootCondition {
  191.  
  192. @Override
  193. public ConditionOutcome getMatchOutcome(ConditionContext context,
  194. AnnotatedTypeMetadata metadata) {
  195. ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
  196. ConditionOutcome outcome = checkDefaultDispatcherName(beanFactory);
  197. if (!outcome.isMatch()) {
  198. return outcome;
  199. }
  200. return checkServletRegistration(beanFactory);
  201. }
  202.  
  203. private ConditionOutcome checkDefaultDispatcherName(
  204. ConfigurableListableBeanFactory beanFactory) {
  205. List<String> servlets = Arrays.asList(beanFactory
  206. .getBeanNamesForType(DispatcherServlet.class, false, false));
  207. boolean containsDispatcherBean = beanFactory
  208. .containsBean(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
  209. if (containsDispatcherBean
  210. && !servlets.contains(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)) {
  211. return ConditionOutcome
  212. .noMatch(startMessage().found("non dispatcher servlet")
  213. .items(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME));
  214. }
  215. return ConditionOutcome.match();
  216. }
  217.  
  218. private ConditionOutcome checkServletRegistration(
  219. ConfigurableListableBeanFactory beanFactory) {
  220. ConditionMessage.Builder message = startMessage();
  221. List<String> registrations = Arrays.asList(beanFactory
  222. .getBeanNamesForType(ServletRegistrationBean.class, false, false));
  223. boolean containsDispatcherRegistrationBean = beanFactory
  224. .containsBean(DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME);
  225. if (registrations.isEmpty()) {
  226. if (containsDispatcherRegistrationBean) {
  227. return ConditionOutcome
  228. .noMatch(message.found("non servlet registration bean").items(
  229. DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME));
  230. }
  231. return ConditionOutcome
  232. .match(message.didNotFind("servlet registration bean").atAll());
  233. }
  234. if (registrations
  235. .contains(DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)) {
  236. return ConditionOutcome.noMatch(message.found("servlet registration bean")
  237. .items(DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME));
  238. }
  239. if (containsDispatcherRegistrationBean) {
  240. return ConditionOutcome
  241. .noMatch(message.found("non servlet registration bean").items(
  242. DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME));
  243. }
  244. return ConditionOutcome.match(message.found("servlet registration beans")
  245. .items(Style.QUOTE, registrations).append("and none is named "
  246. + DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME));
  247. }
  248.  
  249. private ConditionMessage.Builder startMessage() {
  250. return ConditionMessage.forCondition("DispatcherServlet Registration");
  251. }
  252.  
  253. }
  254.  
  255. }

该代码是创建SpringMvc的典型示例  我想@Bean @Configuration 这个大家在熟悉不过了,下面我们来看几个比较陌生的注解,我简单解释一下:

1.spring-boot利用Conditional来确定是否创建Bean实例,这个注解我们可以理解为满足一定条件我们才创建Bean

2.这些注解我们可以在spring-boot-autoconfigure-2.0.0.M7.jar下 org.springframework.boot.autoconfigure.condition下找到

3.常见的注解解释:

  3.1 @ConditionalOnBean :匹配给定的class类型或者Bean的名字是否在SpringBeanFactory中存在

  3.2 @ConditionalOnClass:匹配给定的class类型是否在类路径(classpath)中存在

  3.3 @ConditionalOnExpression : 匹配给定springEL表达式的值返回true时

  3.4 @ConditionalOnJava :匹配JDK的版本,其中range属性是枚举类型有两个值可以选择

      3.4.1 EQUAL_OR_NEWER 不小于

      3.4.2 OLDER_THAN 小于

3.4.3 value属性用于设置jdk版本

  3.5 ConditionalOnMissingBean:spring上下文中不存在指定bean时

   3.6 ConditionalOnWebApplication:在web环境下创建

  1. @ConditionalOnBean is evaluated after all configuration classes have been processed, i.e you can't use it to make a whole configuration class conditional on the presence of another bean. You can, however, use it where you have to make all of the configuration's beans conditional on the presence of another bean.
  2.  
  3. 注意:Conditional 只有在所有配置类被加载完的时候被评估是否要创建,因此Conditional不能在配置类里根据其他创建的方法进行判断
  4.  
  1. @Bean
    @ConditionalOnBean({Teacher.class})
    public Student student(StudentProperties studentProperties) {
    Student student = new Student();
    student.setStuName(studentProperties.getName());
    return student;
    }
  2.  
  3. @Bean
    @ConditionalOnMissingBean
    public static Teacher teacher() {
    return new Teacher();
    }
  4.  
  5. @Bean
    @ConditionalOnMissingBean
    public static School school() {
    return new School();
    }
    比如上述代码 Student是不会被创建的,如果非要@Bean@Conditional使用,则可以借助于@Import方式实现
  1. @Configuration
    @EnableConfigurationProperties(StudentProperties.class)
    @Import(TeacherAutoConfiguration.class)
    public class MyTestAutoConfiguration {
  2.  
  3. @Bean
    @ConditionalOnBean(Teacher.class)
    public Student student(StudentProperties studentProperties) {
    Student student = new Student();
    student.setStuName(studentProperties.getName());
    return student;
    }
  4.  
  5. }
  1. @Configuration
    public class TeacherAutoConfiguration {
  2.  
  3. @Bean
    @ConditionalOnMissingBean
    public static Teacher teacher() {
    return new Teacher();
    }
    }

二。实现简单的SpringBoot示例

1.我们先创建两个类分别为 Teacher Student,项目结构图

注意图中标圈的文件:spring-configuration-metadata.json文件,我们配置这个文件后,可以在idea或者spring sts中配置application.yml得到相关智能提示

json数据如下

  1. {
  2. "hints":[],
  3. "groups":[],
  4. "properties": [
  5. {
  6. "sourceType": "com.bdqn.lyrk.springboot.study.configuration.MyProperties",
  7. "name": "my.loginName",
  8. "description": "登录名",
  9. "type": "java.lang.String"
  10. }
  11. ]
  12. }

2.MyObjectAutoConfiguration类代码:

  1. package com.bdqn.lyrk.springboot.study.configuration;
  2.  
  3. import com.bdqn.lyrk.springboot.study.pojo.School;
  4. import com.bdqn.lyrk.springboot.study.pojo.Student;
  5. import com.bdqn.lyrk.springboot.study.pojo.Teacher;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
  8. import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
  9. import org.springframework.boot.context.properties.EnableConfigurationProperties;
  10. import org.springframework.context.annotation.Bean;
  11. import org.springframework.context.annotation.Configuration;
  12.  
  13. /**
  14. * 自动创建对象示例,例子中我们创建Teacher与Student对象。
  15. * 当项目打成jar包依赖到其他Spring容器中,这些对象我们可以自动进行注入
  16. */
  17. @Configuration
  18. @EnableConfigurationProperties(MyProperties.class)
  19. public class MyObjectAutoConfiguration {
  20.  
  21. @Configuration
  22. static class TeacherAutoConfiguration {
  23.  
  24. @Bean
  25. @ConditionalOnClass({Teacher.class, School.class})
  26. public static Teacher teacher() {
  27. return new Teacher();
  28. }
  29. }
  30.  
  31. @Configuration
  32. static class StudentAutoConfiguration {
  33.  
  34. @Bean
  35. @ConditionalOnMissingBean
  36. public Student student(@Autowired MyProperties myProperties) {
  37. return new Student(myProperties.getLoginName());
  38. }
  39. }
  40. }

3.MyProperties代码:

  1. package com.bdqn.lyrk.springboot.study.configuration;
  2.  
  3. import org.springframework.boot.context.properties.ConfigurationProperties;
  4.  
  5. /**
  6. * 用于实现读取application.yml中的配置
  7. */
  8. @ConfigurationProperties(prefix = MyProperties.PREFIX)
  9. public class MyProperties {
  10.  
  11. public static final String PREFIX = "my";
  12.  
  13. private String loginName;
  14.  
  15. public String getLoginName() {
  16. return loginName;
  17. }
  18.  
  19. public void setLoginName(String loginName) {
  20. this.loginName = loginName;
  21. }
  22. }

4.application.yml配置:

  1. my:
  2. loginName: test
  3. spring:
  4. main:
  5. web-environment: false

5.Application代码:

  1. package com.bdqn.lyrk.springboot.study;
  2.  
  3. import com.bdqn.lyrk.springboot.study.pojo.Student;
  4. import org.springframework.boot.SpringApplication;
  5. import org.springframework.boot.autoconfigure.SpringBootApplication;
  6. import org.springframework.context.ConfigurableApplicationContext;
  7.  
  8. @SpringBootApplication
  9. public class Application {
  10.  
  11. public static void main(String[] args) {
  12. ConfigurableApplicationContext applicationContext = SpringApplication.run(Application.class, args);
  13. Student student = applicationContext.getBean(Student.class);
  14. System.out.println(student.getLoginName());
  15. }
  16. }

当运行成功时:我们可以看到输出Student的loginName属性是test

6.在META-INF/spring.factories编写如下代码:

  1. org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  2. com.bdqn.lyrk.springboot.study.configuration.MyTestAutoConfiguration
  1. 注意:此配置文件非常重要,当我们这个jar包被SpringBoot依赖时,spring会读取org.springframework.boot.autoconfigure.EnableAutoConfiguration所定义的配置类并加载
  1.  

SpringBoot学习之自动依赖的更多相关文章

  1. Springboot学习03-SpringMVC自动配置

    Springboot学习03-SpringMVC自动配置 前言 在SpringBoot官网对于SpringMVCde 自动配置介绍 1-原文介绍如下: Spring MVC Auto-configur ...

  2. SpringBoot学习之自动装配

    在前面使用SSM集成时,我们可以使用注解实现无配置化注入,但是这种依赖被进行“人工干预了的”,换句话就是说我们手动进行装配,那么此时还没有达到SpringBoot这种自动装配的效果,那么究竟Sprin ...

  3. Springboot学习:底层依赖与自动配置的原理

    springboot依赖的父项目 我们在创建springboot项目的时候,设置了一个父项目: 这个项目可以点进去,可以发现它依赖于另一个父项目 再次点进去,发现没有依赖父项目了 观察这个项目的pom ...

  4. 尚硅谷springboot学习26-嵌入式servlet容器自动配置、启动原理

    EmbeddedServletContainerAutoConfiguration:嵌入式的Servlet容器自动配置 @AutoConfigureOrder(Ordered.HIGHEST_PREC ...

  5. springboot入门之版本依赖和自动配置原理

    前言 Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that ...

  6. springboot 学习笔记(一)

    引子 最近在搞一个项目,走在科技前沿的师兄, 摒弃了公司老套的框架模式, 采用了springboot搭建新应用.看到如此简洁的代码 , 深受诱惑.趁周末闲余之时, 背晒阳光, 学起了springboo ...

  7. springboot学习(一)——helloworld

    以下内容,如有问题,烦请指出,谢谢 springboot出来也很久了,以前零散地学习了不少,不过很长时间了都没有在实际中使用过了,忘了不少,因此要最近准备抽时间系统的学习积累下springboot,给 ...

  8. Springboot学习07-数据源Druid

    Springboot学习07-数据源Druid 关键字 Druid 前言 学习笔记 正文 1-Druid是什么 Druid是阿里巴巴开源平台上的一个项目,整个项目由数据库连接池.插件框架和SQL解析器 ...

  9. 尚硅谷springboot学习1-简介

    以前看过springboot的相关知识,当时偷懒没有做笔记,现在忘得已经差不多了,现在趁着过年有时间,再学习一遍,并做下笔记以备忘. 特性 Spring Boot来简化Spring应用开发,约定大于配 ...

随机推荐

  1. 如何进行服务器Linux系统下的ext文件系统修复

    一.故障描述 服务器是dell 730系列服务器,存储阵列是MD3200系列存储5T的Lun,操作系统是Linux centos 7,文件系统类型是EXT4,因意外断电,导致系统不能正常启动,修复之后 ...

  2. day-5 python协程与I/O编程深入浅出

    基于python编程语言环境,重新学习了一遍操作系统IO编程基本知识,同时也学习了什么是协程,通过实际编程,了解进程+协程的优势. 一.python协程编程实现 1.  什么是协程(以下内容来自维基百 ...

  3. sql 多条记录插入

    --多条记录插入,用逗号分开值. INSERT dbo.studentinfor ( id, name, class, age, hpsw ) ', -- id - nvarchar(50) N'te ...

  4. [JCIP笔记] (二)当我们谈线程安全时,我们在谈论什么

    总听组里几个大神说起线程安全问题.本来对"线程安全"这个定义拿捏得就不是很准,更令人困惑的是,大神们用这个词指代的对象不仅抽象而且千变万化.比如,我们的架构师昨天说: " ...

  5. 新概念英语(1-139)Is that you, John?

    Lesson 139 Is that you, John? 是你吗,约翰? Listen to the tape then answer this question. Which John Smith ...

  6. ssh_maven之controller层开发

    我们已经完成了前两层的开发,现在 只剩下我们的controller层了,对于这一层,我们需要创建一个动作类CustomerAction,另外就是我们的strutss.xml以及我们的applicati ...

  7. [BZOJ4011][HNOI2015] 落忆枫音(学习笔记) - 拓扑+DP

    其实就是贴一下防止自己忘了,毕竟看了题解才做出来 Orz PoPoQQQ 原文链接 Description 背景太长了 给定一个DAG,和一对点(x, y), 在DAG中由x到y连一条有向边,求生成树 ...

  8. Spring Cloud学习笔记-007

    声明式服务调用:Spring Cloud Feign Feign基于Netflix Feign实现,整合了Spring Cloud Ribbon和Spring Cloud Hystrix,除了提供这两 ...

  9. 解决MySQL在修改列时因为外键依赖出错的问题

    因为 favorite_food 中的 person_id 对 person 表中的 person_id 有外键依赖关系,所以在执行 ALTER TABLE person MODIFY person_ ...

  10. 使用 C# (.NET Core) 实现模板方法模式 (Template Method Pattern)

    本文的概念内容来自深入浅出设计模式一书. 项目需求 有一家咖啡店, 供应咖啡和茶, 它们的工序如下: 咖啡: 茶: 可以看到咖啡和茶的制作工序是差不多的, 都是有4步, 其中有两步它们两个是一样的, ...