didida开店流程全部完成后为什么没有收到邮件 英文通知?

&figure&&img src=&https://pic4.zhimg.com/v2-0123aefacc561efa6148864_b.jpg& data-rawwidth=&780& data-rawheight=&259& class=&origin_image zh-lightbox-thumb& width=&780& data-original=&https://pic4.zhimg.com/v2-0123aefacc561efa6148864_r.jpg&&&/figure&&h2&&b&Spring 概述&/b&&/h2&&p&&b&1. 什么是spring?&/b&&/p&&p&Spring 是个java企业级应用的开源开发框架。Spring主要用来开发Java应用,但是有些扩展是针对构建J2EE平台的web应用。Spring 框架目标是简化Java企业级应用开发,并通过POJO为基础的编程模型促进良好的编程习惯。&/p&&p&&b&2. 使用Spring框架的好处是什么?&/b&&/p&&ul&&li&&b&轻量:&/b&Spring 是轻量的,基本的版本大约2MB。&/li&&li&&b&控制反转:&/b&Spring通过控制反转实现了松散耦合,对象们给出它们的依赖,而不是创建或查找依赖的对象们。&/li&&li&&b&面向切面的编程(AOP):&/b&Spring支持面向切面的编程,并且把应用业务逻辑和系统服务分开。&/li&&li&&b&容器:&/b&Spring 包含并管理应用中对象的生命周期和配置。&/li&&li&&b&&a href=&https://link.zhihu.com/?target=http%3A//www.woniuxy.com/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&MVC框架&/a&&/b&:Spring的WEB框架是个精心设计的框架,是Web框架的一个很好的替代品。&/li&&li&&b&事务管理:&/b&Spring 提供一个持续的事务管理接口,可以扩展到上至本地事务下至全局事务(JTA)。&/li&&li&&b&异常处理:&/b&Spring 提供方便的API把具体技术相关的异常(比如由JDBC,Hibernate or JDO抛出的)转化为一致的unchecked 异常。&/li&&/ul&&p&&b&3. Spring由哪些模块组成?&/b&&/p&&p&以下是Spring 框架的基本模块:&/p&&ul&&li&Core module&/li&&li&Bean module&/li&&li&Context module&/li&&li&Expression Language module&/li&&li&JDBC module&/li&&li&ORM module&/li&&li&OXM module&/li&&li&Java Messaging Service(JMS) module&/li&&li&Transaction module&/li&&li&Web module&/li&&li&Web-Servlet module&/li&&li&Web-Struts module&/li&&li&Web-Portlet module&/li&&/ul&&p&&b&4. 核心容器(应用上下文) 模块。&/b&&/p&&p&这是基本的Spring模块,提供spring 框架的基础功能,BeanFactory 是 任何以spring为基础的应用的核心。Spring 框架建立在此模块之上,它使Spring成为一个容器。&/p&&p&&b&5. BeanFactory – BeanFactory 实现举例。&/b&&/p&&p&Bean 工厂是工厂模式的一个实现,提供了控制反转功能,用来把应用的配置和依赖从正真的应用代码中分离。&/p&&p&最常用的BeanFactory 实现是XmlBeanFactory 类。&/p&&p&&b&6. XMLBeanFactory &/b&&/p&&p&最常用的就是org.springframework.beans.factory.xml.XmlBeanFactory ,它根据XML文件中的定义加载beans。该容器从XML 文件读取配置元数据并用它去创建一个完全配置的系统或应用。&/p&&p&&b&7. 解释AOP模块&/b&&/p&&p&AOP模块用于发给我们的Spring应用做面向切面的开发, 很多支持由AOP联盟提供,这样就确保了Spring和其他AOP框架的共通性。这个模块将元数据编程引入Spring。&/p&&p&&b&8. 解释JDBC抽象和DAO模块。&/b&&/p&&p&通过使用JDBC抽象和DAO模块,保证数据库代码的简洁,并能避免数据库资源错误关闭导致的问题,它在各种不同的数据库的错误信息之上,提供了一个统一的异常访问层。它还利用Spring的AOP 模块给Spring应用中的对象提供事务管理服务。&/p&&p&&b&9. 解释对象/关系映射集成模块。&/b&&/p&&p&Spring 通过提供ORM模块,支持我们在直接JDBC之上使用一个对象/关系映射映射(ORM)工具,Spring 支持集成主流的ORM框架,如Hiberate,JDO和 iBATIS SQL Maps。Spring的事务管理同样支持以上所有ORM框架及JDBC。&/p&&p&&b&10. 解释WEB 模块。&/b&&/p&&p&Spring的WEB模块是构建在application context 模块基础之上,提供一个适合web应用的上下文。这个模块也包括支持多种面向web的任务,如透明地处理多个文件上传请求和程序级请求参数的绑定到你的业务对象。它也有对Jakarta Struts的支持。&/p&&p&&b&12. Spring配置文件&/b&&/p&&p&Spring配置文件是个XML 文件,这个文件包含了类信息,描述了如何配置它们,以及如何相互调用。&/p&&p&&b&13. 什么是Spring IOC 容器?&/b&&/p&&p&Spring IOC 负责创建对象,管理对象(通过依赖注入(DI),装配对象,配置对象,并且管理这些对象的整个生命周期。&/p&&p&&b&14. IOC的优点是什么?&/b&&/p&&p&IOC 或 依赖注入把应用的代码量降到最低。它使应用容易测试,单元测试不再需要单例和JNDI查找机制。最小的代价和最小的侵入性使松散耦合得以实现。IOC容器支持加载服务时的饿汉式初始化和懒加载。&/p&&p&&b&15. ApplicationContext通常的实现是什么?&/b&&/p&&ul&&li&&b&FileSystemXmlApplicationContext :&/b&此容器从一个XML文件中加载beans的定义,XML Bean 配置文件的全路径名必须提供给它的构造函数。&/li&&li&&b&ClassPathXmlApplicationContext:&/b&此容器也从一个XML文件中加载beans的定义,这里,你需要正确设置classpath因为这个容器将在classpath里找bean配置。&/li&&li&&b&WebXmlApplicationContext:&/b&此容器加载一个XML文件,此文件定义了一个WEB应用的所有bean。&/li&&/ul&&p&&b&16. Bean 工厂和 Application contexts 有什么区别?&/b&&/p&&p&Application contexts提供一种方法处理文本消息,一个通常的做法是加载文件资源(比如镜像),它们可以向注册为监听器的bean发布事件。另外,在容器或容器内的对象上执行的那些不得不由bean工厂以程序化方式处理的操作,可以在Application contexts中以声明的方式处理。Application contexts实现了MessageSource接口,该接口的实现以可插拔的方式提供获取本地化消息的方法。&/p&&p&&b&17. 一个Spring的应用看起来象什么?&/b&&/p&&ul&&li&一个定义了一些功能的接口。&/li&&li&这实现包括属性,它的Setter , getter 方法和函数等。&/li&&li&Spring AOP。&/li&&li&Spring 的XML 配置文件。&/li&&li&使用以上功能的客户端程序。&/li&&/ul&&h2&&b&依赖注入&/b&&/h2&&p&&b&18. 什么是Spring的依赖注入?&/b&&/p&&p&依赖注入,是IOC的一个方面,是个通常的概念,它有多种解释。这概念是说你不用创建对象,而只需要描述它如何被创建。你不在代码里直接组装你的组件和服务,但是要在配置文件里描述哪些组件需要哪些服务,之后一个容器(IOC容器)负责把他们组装起来。&/p&&p&&b&19. 有哪些不同类型的IOC(依赖注入)方式?&/b&&/p&&ul&&li&&b&构造器依赖注入:&/b&构造器依赖注入通过容器触发一个类的构造器来实现的,该类有一系列参数,每个参数代表一个对其他类的依赖。&/li&&li&&b&Setter方法注入:&/b&Setter方法注入是容器通过调用无参构造器或无参static工厂 方法实例化bean之后,调用该bean的setter方法,即实现了基于setter的依赖注入。&/li&&/ul&&p&&b&20. 哪种依赖注入方式你建议使用,构造器注入,还是 Setter方法注入?&/b&&/p&&p&你两种依赖方式都可以使用,构造器注入和Setter方法注入。最好的解决方案是用构造器参数实现强制依赖,setter方法实现可选依赖。&/p&&h2&&b&Spring Beans&/b&&/h2&&p&&b&21.什么是Spring beans?&/b&&/p&&p&Spring beans 是那些形成Spring应用的主干的java对象。它们被Spring IOC容器初始化,装配,和管理。这些beans通过容器中配置的元数据创建。比如,以XML文件中&bean/& 的形式定义。&/p&&p&Spring 框架定义的beans都是单件beans。在bean tag中有个属性”singleton”,如果它被赋为TRUE,bean 就是单件,否则就是一个 prototype bean。默认是TRUE,所以所有在Spring框架中的beans 缺省都是单件。&/p&&p&&b&22. 一个 Spring Bean 定义 包含什么?&/b&&/p&&p&一个Spring Bean 的定义包含容器必知的所有配置元数据,包括如何创建一个bean,它的生命周期详情及它的依赖。&/p&&p&&b&23. 如何给Spring 容器提供配置元数据?&/b&&/p&&p&这里有三种重要的方法给Spring 容器提供配置元数据。&/p&&p&XML配置文件。&/p&&p&基于注解的配置。&/p&&p&基于java的配置。&/p&&p&&b&24. 你怎样定义类的作用域? &/b&&/p&&p&当定义一个&bean& 在Spring里,我们还能给这个bean声明一个作用域。它可以通过bean &br&定义中的scope属性来定义。如,当Spring要在需要的时候每次生产一个新的bean实例,bean的scope属性被指定为prototype。另一方面,一个bean每次使用的时候必须返回同一个实例,这个bean的scope 属性 必须设为 singleton。&/p&&p&&b&25. 解释Spring支持的几种bean的作用域。&/b&&/p&&p&Spring框架支持以下五种bean的作用域:&/p&&ul&&li&&b&singleton : &/b&bean在每个Spring ioc 容器中只有一个实例。&/li&&li&&b&prototype&/b&:一个bean的定义可以有多个实例。&/li&&li&&b&request&/b&:每次http请求都会创建一个bean,该作用域仅在基于web的Spring ApplicationContext情形下有效。&/li&&li&&b&session&/b&:在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。&/li&&li&&b&global-session&/b&:在一个全局的HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。&/li&&/ul&&p&缺省的Spring bean 的作用域是Singleton.&/p&&p&&b&26. Spring框架中的单例bean是线程安全的吗?&/b&&/p&&p&不,Spring框架中的单例bean不是线程安全的。&/p&&p&&b&27. 解释Spring框架中bean的生命周期。&/b&&/p&&ul&&li&Spring容器 从XML 文件中读取bean的定义,并实例化bean。&/li&&li&Spring根据bean的定义填充所有的属性。&/li&&li&如果bean实现了BeanNameAware 接口,Spring 传递bean 的ID 到 setBeanName方法。&/li&&li&如果Bean 实现了 BeanFactoryAware 接口, Spring传递beanfactory 给setBeanFactory 方法。&/li&&li&如果有任何与bean相关联的BeanPostProcessors,Spring会在postProcesserBeforeInitialization()方法内调用它们。&/li&&li&如果bean实现IntializingBean了,调用它的afterPropertySet方法,如果bean声明了初始化方法,调用此初始化方法。&/li&&li&如果有BeanPostProcessors 和bean 关联,这些bean的postProcessAfterInitialization() 方法将被调用。&/li&&li&如果bean实现了 DisposableBean,它将调用destroy()方法。&/li&&/ul&&p&&b&28. 哪些是重要的bean生命周期方法? 你能重载它们吗?&/b&&/p&&p&有两个重要的bean 生命周期方法,第一个是setup , 它是在容器加载bean的时候被调用。第二个方法是 teardown 它是在容器卸载类的时候被调用。&/p&&p&The bean 标签有两个重要的属性(init-method和destroy-method)。用它们你可以自己定制初始化和注销方法。它们也有相应的注解(@PostConstruct和@PreDestroy)。&/p&&p&&b&29. 什么是Spring的内部bean?&/b&&/p&&p&当一个bean仅被用作另一个bean的属性时,它能被声明为一个内部bean,为了定义inner bean,在Spring 的 基于XML的&br& 配置元数据中,可以在 &property/&或 &constructor-arg/& &br&元素内使用&bean/& 元素,内部bean通常是匿名的,它们的Scope一般是prototype。&/p&&p&&b&30. 在 Spring中如何注入一个java集合?&/b&&/p&&p&Spring提供以下几种集合的配置元素:&/p&&ul&&li&&list&类型用于注入一列值,允许有相同的值。&/li&&li&&set& 类型用于注入一组值,不允许有相同的值。&/li&&li&&map& 类型用于注入一组键值对,键和值都可以为任意类型。&/li&&li&&props&类型用于注入一组键值对,键和值都只能为String类型。&/li&&/ul&&p&&b&31. 什么是bean装配? &/b&&/p&&p&装配,或bean 装配是指在Spring 容器中把bean组装到一起,前提是容器需要知道bean的依赖关系,如何通过依赖注入来把它们装配到一起。&/p&&p&&b&32. 什么是bean的自动装配?&/b&&/p&&p&Spring 容器能够自动装配相互合作的bean,这意味着容器不需要&constructor-arg&和&property&配置,能通过Bean工厂自动处理bean之间的协作。&/p&&p&&b&33. 解释不同方式的自动装配 。&/b&&/p&&p&有五种自动装配的方式,可以用来指导Spring容器用自动装配方式来进行依赖注入。&/p&&ul&&li&&b&no&/b&:默认的方式是不进行自动装配,通过显式设置ref 属性来进行装配。&/li&&li&&b&byName:&/b&通过参数名 自动装配,Spring容器在配置文件中发现bean的autowire属性被设置成byname,之后容器试图匹配、装配和该bean的属性具有相同名字的bean。&/li&&li&&b&byType::&/b&通过参数类型自动装配,Spring容器在配置文件中发现bean的autowire属性被设置成byType,之后容器试图匹配、装配和该bean的属性具有相同类型的bean。如果有多个bean符合条件,则抛出错误。&/li&&li&&b&constructor:这个方式类似于&/b&byType, 但是要提供给构造器参数,如果没有确定的带参数的构造器参数类型,将会抛出异常。&/li&&li&&b&autodetect:&/b&首先尝试使用constructor来自动装配,如果无法工作,则使用byType方式。&/li&&/ul&&p&&b&34.自动装配有哪些局限性 ?&/b&&/p&&p&自动装配的局限性是:&/p&&ul&&li&&b&重写&/b&: 你仍需用 &constructor-arg&和 &property& 配置来定义依赖,意味着总要重写自动装配。&/li&&li&&b&基本数据类型&/b&:你不能自动装配简单的属性,如基本数据类型,String字符串,和类。&/li&&li&&b&模糊特性:&/b&自动装配不如显式装配精确,如果有可能,建议使用显式装配。&/li&&/ul&&p&&b&35. 你可以在Spring中注入一个null 和一个空字符串吗?&/b&&/p&&p&可以。&/p&&h2&&b&Spring注解&/b&&/h2&&p&&b&36. 什么是基于Java的Spring注解配置? 给一些注解的例子.&/b&&/p&&p&基于Java的配置,允许你在少量的&a href=&https://link.zhihu.com/?target=http%3A//www.woniuxy.com/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Java注解&/a&的帮助下,进行你的大部分Spring配置而非通过XML文件。&/p&&p&以@Configuration 注解为例,它用来标记类可以当做一个bean的定义,被Spring IOC容器使用。另一个例子是@Bean注解,它表示此方法将要返回一个对象,作为一个bean注册进Spring应用上下文。&/p&&p&&b&37. 什么是基于注解的容器配置?&/b&&/p&&p&相对于XML文件,注解型的配置依赖于通过字节码元数据装配组件,而非尖括号的声明。&/p&&p&开发者通过在相应的类,方法或属性上使用注解的方式,直接组件类中进行配置,而不是使用xml表述bean的装配关系。&/p&&p&&b&38. 怎样开启注解装配?&/b&&/p&&p&注解装配在默认情况下是不开启的,为了使用注解装配,我们必须在Spring配置文件中配置 &context:annotation-config/&元素。&/p&&p&&b&39. @Required 注解&/b&&/p&&p&这个注解表明bean的属性必须在配置的时候设置,通过一个bean定义的显式的属性值或通过自动装配,若@Required注解的bean属性未被设置,容器将抛出BeanInitializationException。&/p&&p&&b&40. @Autowired 注解&/b&&/p&&p&@Autowired 注解提供了更细粒度的控制,包括在何处以及如何完成自动装配。它的用法和@Required一样,修饰setter方法、构造器、属性或者具有任意名称和/或多个参数的PN方法。&/p&&p&&b&41. @Qualifier 注解&/b&&/p&&p&当有多个相同类型的bean却只有一个需要自动装配时,将@Qualifier 注解和@Autowire 注解结合使用以消除这种混淆,指定需要装配的确切的bean。&/p&&h2&&b&Spring数据访问&/b&&/h2&&p&&b&42.在Spring框架中如何更有效地使用JDBC? &/b&&/p&&p&使用SpringJDBC 框架,资源管理和错误处理的代价都会被减轻。所以开发者只需写statements 和 queries从数据存取数据,JDBC也可以在Spring框架提供的模板类的帮助下更有效地被使用,这个模板叫JdbcTemplate (例子见这里&a href=&https://link.zhihu.com/?target=http%3A//examples.javacodegeeks.com/enterprise-java/spring/jdbc/spring-jdbctemplate-example/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&here&/a&)&/p&&p&&b&43. JdbcTemplate&/b&&/p&&p&JdbcTemplate 类提供了很多便利的方法解决诸如把数据库数据转变成基本数据类型或对象,执行写好的或可调用的数据库操作语句,提供自定义的数据错误处理。&/p&&p&&b&44. Spring对DAO的支持&/b&&/p&&p&Spring对数据访问对象(DAO)的支持旨在简化它和数据访问技术如JDBC,Hibernate or JDO 结合使用。这使我们可以方便切换持久层。编码时也不用担心会捕获每种技术特有的异常。&/p&&p&&b&45. 使用Spring通过什么方式访问Hibernate? &/b&&/p&&p&在Spring中有两种方式访问Hibernate:&/p&&ul&&li&控制反转 Hibernate Template和 Callback。&/li&&li&继承 HibernateDAOSupport提供一个AOP 拦截器。&/li&&/ul&&p&&b&46. Spring支持的ORM&/b&&/p&&p&Spring支持以下ORM:&/p&&ul&&li&Hibernate&/li&&li&iBatis&/li&&li&JPA (Java Persistence API)&/li&&li&TopLink&/li&&li&JDO (Java Data Objects)&/li&&li&OJB&/li&&/ul&&p&&b&47.如何通过HibernateDaoSupport将Spring和Hibernate结合起来?&/b&&/p&&p&用Spring的 SessionFactory 调用 LocalSessionFactory。集成过程分三步:&/p&&ul&&li&配置the Hibernate SessionFactory。&/li&&li&继承HibernateDaoSupport实现一个DAO。&/li&&li&在AOP支持的事务中装配。&/li&&/ul&&p&&b&48. Spring支持的事务管理类型&/b&&/p&&p&Spring支持两种类型的事务管理:&/p&&ul&&li&&b&编程式事务管理&/b&:这意味你通过编程的方式管理事务,给你带来极大的灵活性,但是难维护。&/li&&li&&b&声明式事务管理:&/b&这意味着你可以将业务代码和事务管理分离,你只需用注解和XML配置来管理事务。&/li&&/ul&&p&&b&49. Spring框架的事务管理有哪些优点?&/b&&/p&&ul&&li&它为不同的事务API 如 JTA,JDBC,Hibernate,JPA 和JDO,提供一个不变的编程模式。&/li&&li&它为编程式事务管理提供了一套简单的API而不是一些复杂的事务API如&/li&&li&它支持声明式事务管理。&/li&&li&它和Spring各种数据访问抽象层很好得集成。&/li&&/ul&&p&&b&50. 你更倾向用那种事务管理类型?&/b&&/p&&p&大多数Spring框架的用户选择声明式事务管理,因为它对应用代码的影响最小,因此更符合一个无侵入的轻量级容器的思想。声明式事务管理要优于编程式事务管理,虽然比编程式事务管理(这种方式允许你通过代码控制事务)少了一点灵活性。&/p&&h2&&b&Spring面向切面编程(AOP)&/b&&/h2&&p&&b&51. 解释AOP&/b&&/p&&p&面向切面的编程,或AOP, 是一种编程技术,允许程序模块化横向切割关注点,或横切典型的责任划分,如日志和事务管理。&/p&&p&&b&52. Aspect 切面&/b&&/p&&p&AOP核心就是切面,它将多个类的通用行为封装成可重用的模块,该模块含有一组API提供横切功能。比如,一个日志模块可以被称作日志的AOP切面。根据需求的不同,一个应用程序可以有若干切面。在Spring AOP中,切面通过带有@Aspect注解的类实现。&/p&&p&&b&52. 在Spring AOP 中,关注点和横切关注的区别是什么?&/b&&/p&&p&关注点是应用中一个模块的行为,一个关注点可能会被定义成一个我们想实现的一个功能。&/p&&p&横切关注点是一个关注点,此关注点是整个应用都会使用的功能,并影响整个应用,比如日志,安全和数据传输,几乎应用的每个模块都需要的功能。因此这些都属于横切关注点。&/p&&p&&b&54. 连接点&/b&&/p&&p&连接点代表一个应用程序的某个位置,在这个位置我们可以插入一个AOP切面,它实际上是个应用程序执行Spring AOP的位置。&/p&&p&&b&55. 通知&/b&&/p&&p&通知是个在方法执行前或执行后要做的动作,实际上是程序执行时要通过SpringAOP框架触发的代码段。&/p&&p&Spring切面可以应用五种类型的通知:&/p&&ul&&li&&b&before&/b&:前置通知,在一个方法执行前被调用。&/li&&li&&b&after: &/b&在方法执行之后调用的通知,无论方法执行是否成功。&/li&&li&&b&after-returning: &/b&仅当方法成功完成后执行的通知。&/li&&li&&b&after-throwing: &/b&在方法抛出异常退出时执行的通知。&/li&&li&&b&around: &/b&在方法执行之前和之后调用的通知。&/li&&/ul&&p&&b&56. 切点&/b&&/p&&p&切入点是一个或一组连接点,通知将在这些位置执行。可以通过表达式或匹配的方式指明切入点。&/p&&p&&b&57. 什么是引入? &/b&&/p&&p&引入允许我们在已存在的类中增加新的方法和属性。&/p&&p&&b&58. 什么是目标对象? &/b&&/p&&p&被一个或者多个切面所通知的对象。它通常是一个代理对象。也指被通知(advised)对象。&/p&&p&&b&59. 什么是代理?&/b&&/p&&p&代理是通知目标对象后创建的对象。从客户端的角度看,代理对象和目标对象是一样的。&/p&&p&&b&60. 有几种不同类型的自动代理?&/b&&/p&&p&BeanNameAutoProxyCreator&/p&&p&DefaultAdvisorAutoProxyCreator&/p&&p&Metadata autoproxying&/p&&p&&b&61. 什么是织入。什么是织入应用的不同点?&/b&&/p&&p&织入是将切面和到其他应用类型或对象连接或创建一个被通知对象的过程。&/p&&p&织入可以在编译时,加载时,或运行时完成。&/p&&p&&b&62. 解释基于XML Schema方式的切面实现。&/b&&/p&&p&在这种情况下,切面由常规类以及基于XML的配置实现。&/p&&p&&b&63. 解释基于注解的切面实现&/b&&/p&&p&在这种情况下(基于@AspectJ的实现),涉及到的切面声明的风格与带有java5标注的普通java类一致。&/p&&h2&&b&Spring 的MVC&/b&&/h2&&p&&b&64. 什么是Spring的MVC框架?&/b&&/p&&p&Spring 配备构建Web 应用的全功能MVC框架。Spring可以很便捷地和其他MVC框架集成,如Struts,Spring 的MVC框架用控制反转把业务对象和控制逻辑清晰地隔离。它也允许以声明的方式把请求参数和业务对象绑定。&/p&&p&&b&65. DispatcherServlet&/b&&/p&&p&Spring的MVC框架是围绕DispatcherServlet来设计的,它用来处理所有的HTTP请求和响应。&/p&&p&&b&66. WebApplicationContext&/b&&/p&&p&WebApplicationContext 继承了ApplicationContext 并增加了一些WEB应用必备的特有功能,它不同于一般的ApplicationContext ,因为它能处理主题,并找到被关联的servlet。&/p&&p&&b&67. 什么是Spring MVC框架的控制器?&/b&&/p&&p&控制器提供一个访问应用程序的行为,此行为通常通过服务接口实现。控制器解析用户输入并将其转换为一个由视图呈现给用户的模型。Spring用一个非常抽象的方式实现了一个控制层,允许用户创建多种用途的控制器。&/p&&p&&b&68. @Controller 注解&/b&&/p&&p&该注解表明该类扮演控制器的角色,Spring不需要你继承任何其他控制器基类或引用Servlet API。&/p&&p&&b&69. @RequestMapping 注解&/b&&/p&&p&该注解是用来映射一个URL到一个类或一个特定的方处理法上。&/p&&p&&b&注:&/b&本文译者 &a href=&https://link.zhihu.com/?target=http%3A//ifeve.com/spring-interview-questions-and-answers/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&深海&/a&,原文链接 &a href=&https://link.zhihu.com/?target=https%3A//www.javacodegeeks.com/2014/05/spring-interview-questions-and-answers.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&69 Spring Interview Questions and Answers – The ULTIMATE List (PDF Download)&/a&。做一只IT干货的搬运工,喜欢就给个赞呗。希望继续在IT行业突破提升自己的各位朋友,也欢迎加群,不管你自我感觉牛不牛B。 &/p&
Spring 概述1. 什么是spring?Spring 是个java企业级应用的开源开发框架。Spring主要用来开发Java应用,但是有些扩展是针对构建J2EE平台的web应用。Spring 框架目标是简化Java企业级应用开发,并通过POJO为基础的编程模型促进良好的编程习惯。2. 使用Spring…
&figure&&img src=&https://pic2.zhimg.com/v2-dce0afd67a68bb1be4cb50_b.jpg& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic2.zhimg.com/v2-dce0afd67a68bb1be4cb50_r.jpg&&&/figure&&p&&/p&&p&&/p&&p&IEEE公布的2017年编程语言排行榜,python高居首位。在百度指数上,python的搜索量也跻身到与java相等的量级,成为最火的语言之一。&/p&&figure&&img src=&https://pic1.zhimg.com/v2-68b22b88b69c321ca3975cce29c2e1a6_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic1.zhimg.com/v2-68b22b88b69c321ca3975cce29c2e1a6_r.jpg&&&/figure&&p&那么Python适合用来做服务器编程吗?&/p&&figure&&img src=&https://pic2.zhimg.com/v2-f2ba2ad2d58be5f2b896ba5a_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic2.zhimg.com/v2-f2ba2ad2d58be5f2b896ba5a_r.jpg&&&/figure&&p&首先,看看哪些公司在用Python作为服务器的主要技术栈?可以看到,其中不缺乏一些用户量庞大的公司。&/p&&figure&&img src=&https://pic3.zhimg.com/v2-96ff84eeecabdbca617b2303_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic3.zhimg.com/v2-96ff84eeecabdbca617b2303_r.jpg&&&/figure&&p&得益于语言的简洁性,python很适合用来进行快速开发,编写出可读性强的程序。那么怎么用python来做服务器编程呢?&/p&&p&从一个例子说起...&/p&&figure&&img src=&https://pic4.zhimg.com/v2-14d268cff6ae_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic4.zhimg.com/v2-14d268cff6ae_r.jpg&&&/figure&&p&这是一个简单的回显服务器,服务端每次从请求读取一些字节并返回给客户端。&/p&&figure&&img src=&https://pic1.zhimg.com/v2-b3ee4d6a2fe16b_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic1.zhimg.com/v2-b3ee4d6a2fe16b_r.jpg&&&/figure&&p&但由于服务器是单进程的,如果一个请求占住了服务器,就没办法处理另一个请求。&/p&&figure&&img src=&https://pic1.zhimg.com/v2-60886fff4cbb_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic1.zhimg.com/v2-60886fff4cbb_r.jpg&&&/figure&&p&这次做一些改动,每来一个请求就fork一个进程来处理,这样就不会出现之前的问题。&/p&&figure&&img src=&https://pic4.zhimg.com/v2-534ea6022aba9d67d6eb23_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic4.zhimg.com/v2-534ea6022aba9d67d6eb23_r.jpg&&&/figure&&p&但多进程模型处理不好会出现僵尸进程和孤儿进程,因此父进程需要处理SIGCHILD信号来收集退出的子进程的信息。&/p&&figure&&img src=&https://pic3.zhimg.com/v2-f95b7f9931feab_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic3.zhimg.com/v2-f95b7f9931feab_r.jpg&&&/figure&&p&socketserver模块中ForkingMixIn收集子进程的例子:&/p&&figure&&img src=&https://pic1.zhimg.com/v2-a5d2dccbdf7fffe92ea6cbd599eb7919_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic1.zhimg.com/v2-a5d2dccbdf7fffe92ea6cbd599eb7919_r.jpg&&&/figure&&p&原始的CGI程序就是使用这种方式,对于每个请求都fork进程来解释cgi程序。&/p&&figure&&img src=&https://pic3.zhimg.com/v2-9fe2a5d0528f5_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic3.zhimg.com/v2-9fe2a5d0528f5_r.jpg&&&/figure&&p&不过随着请求数量的变多,fork进程所带来的开销往往很大。&/p&&figure&&img src=&https://pic1.zhimg.com/v2-486d9019afe232ba122f2d26bf910523_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic1.zhimg.com/v2-486d9019afe232ba122f2d26bf910523_r.jpg&&&/figure&&p&所以CGI不仅慢...&/p&&figure&&img src=&https://pic3.zhimg.com/v2-9ebcad8d16db10126e51fef24236ddd6_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic3.zhimg.com/v2-9ebcad8d16db10126e51fef24236ddd6_r.jpg&&&/figure&&p&而且&/p&&figure&&img src=&https://pic4.zhimg.com/v2-f6b2cafbeda74_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic4.zhimg.com/v2-f6b2cafbeda74_r.jpg&&&/figure&&p&甚至&/p&&figure&&img src=&https://pic2.zhimg.com/v2-7edd4f28502aab876e67492f_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic2.zhimg.com/v2-7edd4f28502aab876e67492f_r.jpg&&&/figure&&p&后来出现了FastCGI,它与CGI的区别,就是更Fast(误),它是一个常驻进程,预先启动多个cgi进程来等待处理请求。&/p&&figure&&img src=&https://pic4.zhimg.com/v2-90ace8dab_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic4.zhimg.com/v2-90ace8dab_r.jpg&&&/figure&&p&不同于FastCGI,Apache搞了一套mod_python,使得python解释器可以嵌入在apache进程。&/p&&figure&&img src=&https://pic1.zhimg.com/v2-4fe6b63dd9aba71b7f159_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic1.zhimg.com/v2-4fe6b63dd9aba71b7f159_r.jpg&&&/figure&&p&后来PEP 333中定义了WSGI,成为沿用至今的Python web开发的标准协议。&/p&&figure&&img src=&https://pic1.zhimg.com/v2-feac34bc0b3bd94b130626e_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic1.zhimg.com/v2-feac34bc0b3bd94b130626e_r.jpg&&&/figure&&p&应用WSGI协议的一个示例:&/p&&figure&&img src=&https://pic4.zhimg.com/v2-86c890d195e5b2e5844eeac1c2e7c074_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic4.zhimg.com/v2-86c890d195e5b2e5844eeac1c2e7c074_r.jpg&&&/figure&&p&绝大部分的python web开发框架都遵守了这套标准:&/p&&figure&&img src=&https://pic1.zhimg.com/v2-0ad754a1c82d_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic1.zhimg.com/v2-0ad754a1c82d_r.jpg&&&/figure&&p&gunicorn是一个著名的wsgi http服务器,它采用pre-fork模型来处理和转发请求。(&a href=&https://link.zhihu.com/?target=https%3A//realpython.com/blog/python/kickstarting-flask-on-ubuntu-setup-and-deployment/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&原图出处&/a&)&/p&&figure&&img src=&https://pic2.zhimg.com/v2-a9b9f36bcc04c2d94d634ecc75abf776_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic2.zhimg.com/v2-a9b9f36bcc04c2d94d634ecc75abf776_r.jpg&&&/figure&&figure&&img src=&https://pic4.zhimg.com/v2-447bf828eb774e4c12a3a5c3715bc3ac_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic4.zhimg.com/v2-447bf828eb774e4c12a3a5c3715bc3ac_r.jpg&&&/figure&&figure&&img src=&https://pic2.zhimg.com/v2-329c02e66b84cda5aba9a18_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic2.zhimg.com/v2-329c02e66b84cda5aba9a18_r.jpg&&&/figure&&p&gunicorn包含许多种worker模型:(&a href=&https://link.zhihu.com/?target=https%3A//www.spirulasystems.com/blog//gunicorn-worker-types/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&原图出处&/a&)&/p&&figure&&img src=&https://pic2.zhimg.com/v2-c071f5e4cff8b_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic2.zhimg.com/v2-c071f5e4cff8b_r.jpg&&&/figure&&figure&&img src=&https://pic2.zhimg.com/v2-fe73f2e2e721b089a0ab1c_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic2.zhimg.com/v2-fe73f2e2e721b089a0ab1c_r.jpg&&&/figure&&figure&&img src=&https://pic2.zhimg.com/v2-09fa19d529defabab76842_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic2.zhimg.com/v2-09fa19d529defabab76842_r.jpg&&&/figure&&figure&&img src=&https://pic3.zhimg.com/v2-dbd58f7eaf51a_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic3.zhimg.com/v2-dbd58f7eaf51a_r.jpg&&&/figure&&p&抛开多进程,现在来看多线程的模型,该方案用线程代替进程来处理每一个请求:&/p&&figure&&img src=&https://pic1.zhimg.com/v2-20b74fc45ee64952e6acb_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic1.zhimg.com/v2-20b74fc45ee64952e6acb_r.jpg&&&/figure&&p&但是为什么许多人说python的多线程是个鸡肋呢?看下面同样的代码,用同步的方式和多线程的方式执行,多线程的代码却执行的更慢...&/p&&figure&&img src=&https://pic2.zhimg.com/v2-41a84e900cbff_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic2.zhimg.com/v2-41a84e900cbff_r.jpg&&&/figure&&p&这到底是什么回事?&/p&&figure&&img src=&https://pic4.zhimg.com/v2-3a7b385fb871bdf5fc9d755_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic4.zhimg.com/v2-3a7b385fb871bdf5fc9d755_r.jpg&&&/figure&&p&这就要说到python中的GIL了,由于GIL的制约,多线程很难充分利用cpu的性能(&u&&a href=&https://zhuanlan.zhihu.com/p//www.dabeaz.com/python/GIL.pdf& class=&internal&&原图引用&/a&&/u&)&/p&&figure&&img src=&https://pic2.zhimg.com/v2-da0b877a47893c9ebbe3a_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic2.zhimg.com/v2-da0b877a47893c9ebbe3a_r.jpg&&&/figure&&p&话虽如此,多线程在IO密集型应用上还是有不少用武之地的。下面是多线程在服务器编程的其中一些应用(&u&&a href=&https://link.zhihu.com/?target=http%3A//www.brianstorti.com/the-actor-model/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&原图引用&/a&&/u&)&/p&&p&Actor模型&/p&&figure&&img src=&https://pic3.zhimg.com/v2-251c5cca31d0b3abecb6ed_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic3.zhimg.com/v2-251c5cca31d0b3abecb6ed_r.jpg&&&/figure&&figure&&img src=&https://pic2.zhimg.com/v2-_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic2.zhimg.com/v2-_r.jpg&&&/figure&&p&生产者-消费者&/p&&figure&&img src=&https://pic1.zhimg.com/v2-c7ccdb3ec379a3d1b3ea2_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic1.zhimg.com/v2-c7ccdb3ec379a3d1b3ea2_r.jpg&&&/figure&&figure&&img src=&https://pic3.zhimg.com/v2-e8d736eff5c90cd87dcdd6_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic3.zhimg.com/v2-e8d736eff5c90cd87dcdd6_r.jpg&&&/figure&&figure&&img src=&https://pic2.zhimg.com/v2-bdceaec322c7dfefcd9ead_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic2.zhimg.com/v2-bdceaec322c7dfefcd9ead_r.jpg&&&/figure&&p&concurrent.future在PEP 3148中被定义,它提供了更简单的多进程/多线程API&/p&&figure&&img src=&https://pic2.zhimg.com/v2-9b754f1a252b4fbf408a2bf4b18c0ce5_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic2.zhimg.com/v2-9b754f1a252b4fbf408a2bf4b18c0ce5_r.jpg&&&/figure&&figure&&img src=&https://pic3.zhimg.com/v2-b21ae9bcde9f5fa0c1b1d32_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic3.zhimg.com/v2-b21ae9bcde9f5fa0c1b1d32_r.jpg&&&/figure&&figure&&img src=&https://pic2.zhimg.com/v2-cd8d5c4ddb5c359fe1b4212_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic2.zhimg.com/v2-cd8d5c4ddb5c359fe1b4212_r.jpg&&&/figure&&figure&&img src=&https://pic4.zhimg.com/v2-af56d86f59ca7e7a5b174b_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic4.zhimg.com/v2-af56d86f59ca7e7a5b174b_r.jpg&&&/figure&&p&在很长的一段时间,多进程/多线程的模型都应用的很好,但是&/p&&figure&&img src=&https://pic3.zhimg.com/v2-96c6752abf7de6a1440a_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic3.zhimg.com/v2-96c6752abf7de6a1440a_r.jpg&&&/figure&&figure&&img src=&https://pic4.zhimg.com/v2-4cf18bf45a2eba616a68_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic4.zhimg.com/v2-4cf18bf45a2eba616a68_r.jpg&&&/figure&&p&这时候更适合服务器编程的IO多路复用模型开始被广泛应用:&/p&&figure&&img src=&https://pic4.zhimg.com/v2-c0eb79beebd09d18133f4_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic4.zhimg.com/v2-c0eb79beebd09d18133f4_r.jpg&&&/figure&&figure&&img src=&https://pic3.zhimg.com/v2-22a96b790ee2e4f0f4efeaef_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic3.zhimg.com/v2-22a96b790ee2e4f0f4efeaef_r.jpg&&&/figure&&figure&&img src=&https://pic2.zhimg.com/v2-238d79e141cfe2cd1ed4c7_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic2.zhimg.com/v2-238d79e141cfe2cd1ed4c7_r.jpg&&&/figure&&figure&&img src=&https://pic4.zhimg.com/v2-2270adfda58add1191aa7_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic4.zhimg.com/v2-2270adfda58add1191aa7_r.jpg&&&/figure&&figure&&img src=&https://pic3.zhimg.com/v2-6fdd6eb4b35ca32a310d775fca57e995_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic3.zhimg.com/v2-6fdd6eb4b35ca32a310d775fca57e995_r.jpg&&&/figure&&p&基于事件驱动的异步模型对服务器的资源的有效利用率显然易见(&a href=&https://link.zhihu.com/?target=http%3A//www.aosabook.org/en/twisted.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&原图出处&/a&)&/p&&figure&&img src=&https://pic4.zhimg.com/v2-59f2fbd81c_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic4.zhimg.com/v2-59f2fbd81c_r.jpg&&&/figure&&p&衍生了大量的异步网络框架&/p&&figure&&img src=&https://pic4.zhimg.com/v2-e1e15ce84f0aade75c9bb_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic4.zhimg.com/v2-e1e15ce84f0aade75c9bb_r.jpg&&&/figure&&figure&&img src=&https://pic2.zhimg.com/v2-f5d9542342_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic2.zhimg.com/v2-f5d9542342_r.jpg&&&/figure&&figure&&img src=&https://pic1.zhimg.com/v2-44a26e9d1a5b9c6e16ee65_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic1.zhimg.com/v2-44a26e9d1a5b9c6e16ee65_r.jpg&&&/figure&&figure&&img src=&https://pic4.zhimg.com/v2-1d2bc2ff12ec26d8bd52f1_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic4.zhimg.com/v2-1d2bc2ff12ec26d8bd52f1_r.jpg&&&/figure&&figure&&img src=&https://pic4.zhimg.com/v2-9c51c194e68ceeb897ab850c0cdc9d4e_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic4.zhimg.com/v2-9c51c194e68ceeb897ab850c0cdc9d4e_r.jpg&&&/figure&&figure&&img src=&https://pic1.zhimg.com/v2-d12b42d45630cffefd2a9ec12de1efe3_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic1.zhimg.com/v2-d12b42d45630cffefd2a9ec12de1efe3_r.jpg&&&/figure&&figure&&img src=&https://pic4.zhimg.com/v2-9b743aeca712b9_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic4.zhimg.com/v2-9b743aeca712b9_r.jpg&&&/figure&&figure&&img src=&https://pic1.zhimg.com/v2-14842f71acb0cd72b121fc_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic1.zhimg.com/v2-14842f71acb0cd72b121fc_r.jpg&&&/figure&&figure&&img src=&https://pic1.zhimg.com/v2-9c95d7dc8bac6dcbfe39637_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic1.zhimg.com/v2-9c95d7dc8bac6dcbfe39637_r.jpg&&&/figure&&p&在Python 3.4后出现了专门处理异步IO的标准库asyncio&/p&&figure&&img src=&https://pic2.zhimg.com/v2-3dcf8ba7e3fa0aaa43d331b_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic2.zhimg.com/v2-3dcf8ba7e3fa0aaa43d331b_r.jpg&&&/figure&&figure&&img src=&https://pic2.zhimg.com/v2-c5a4f4a135de1b90a32cea98_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic2.zhimg.com/v2-c5a4f4a135de1b90a32cea98_r.jpg&&&/figure&&figure&&img src=&https://pic1.zhimg.com/v2-cda9a21c877e442d8b576_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic1.zhimg.com/v2-cda9a21c877e442d8b576_r.jpg&&&/figure&&figure&&img src=&https://pic4.zhimg.com/v2-0eeef11c5ec7f693cfe0c6_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic4.zhimg.com/v2-0eeef11c5ec7f693cfe0c6_r.jpg&&&/figure&&p&而在随后的Python 3.5后出现了协程语法糖async/await&/p&&figure&&img src=&https://pic4.zhimg.com/v2-7bf65cfd88b0b826120fe_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic4.zhimg.com/v2-7bf65cfd88b0b826120fe_r.jpg&&&/figure&&figure&&img src=&https://pic2.zhimg.com/v2-22fcabadcf485aab8b20c5fb_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic2.zhimg.com/v2-22fcabadcf485aab8b20c5fb_r.jpg&&&/figure&&p&虽然asyncio成为标准库,但它使用方法却较为复杂,不便于使用,也有人提议要asyncio提供更简洁的接口,也有不少的替代库出现&/p&&figure&&img src=&https://pic4.zhimg.com/v2-89afde58dc9_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic4.zhimg.com/v2-89afde58dc9_r.jpg&&&/figure&&figure&&img src=&https://pic3.zhimg.com/v2-e448b67424_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic3.zhimg.com/v2-e448b67424_r.jpg&&&/figure&&p&总的来说,服务器编程经历了从开始的简单到后来的复杂化最终慢慢演变到简单的方式上。&/p&&figure&&img src=&https://pic4.zhimg.com/v2-b3b3ad88e84faba1c72162cf_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic4.zhimg.com/v2-b3b3ad88e84faba1c72162cf_r.jpg&&&/figure&&figure&&img src=&https://pic1.zhimg.com/v2-dd4b6fc9c5_b.jpg& data-caption=&& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic1.zhimg.com/v2-dd4b6fc9c5_r.jpg&&&/figure&&p&&br&&/p&&p&&br&&/p&&hr&&p&PS:部分代码和幻灯中的图片是从网上找的,原出处不明,侵删请告知&/p&
IEEE公布的2017年编程语言排行榜,python高居首位。在百度指数上,python的搜索量也跻身到与java相等的量级,成为最火的语言之一。那么Python适合用来做服务器编程吗?首先,看看哪些公司在用Python作为服务器的主要技术栈?可以看到,其中不缺乏一些用户量…
这个问题简直就是为我而问的啊!&br&&br&&br&激动ing&br&&br&曾曾经的我也是一名Java工程师&br&&br&曾经是一名大数据工程师&br&&br&,,,,,,,,,,,,,,,,,,,,&br&本人目前是一名大数据工程师,项目数据50T,日均数据增长20G左右。&br&&br&个人是从Java后端开发,经过3个月的业余自学成功转型大数据工程师。&br&&br&背景介绍完毕,开始正式一本正经回答问题:&br&&br&本回答目录:&br&一.大数据方向工作介绍&br&二.大数据工程师的技能要求&br&三.大数据学习路径&br&四.学习资源推荐(书籍、博客、网站)&br&&br&&br&一.大数据方向工作介绍&br&&br&大数据方向的工作目前分为三个主要方向:&br&01.大数据工程师&br&02.数据分析师&br&03.大数据科学家&br&04.其他(数据挖掘本质算是机器学习,不过和数据相关,也可以理解为大数据的一个方向吧)&br&&br&二.大数据工程师的技能要求&br&&br&附上二份比较权威的大数据工程师技能图(图侵删)&br&&br&&figure&&img data-rawheight=&1058& src=&https://pic3.zhimg.com/v2-2712bddb7af89fb828271e_b.jpg& data-rawwidth=&720& class=&origin_image zh-lightbox-thumb& width=&720& data-original=&https://pic3.zhimg.com/v2-2712bddb7af89fb828271e_r.jpg&&&/figure&&br&&figure&&img data-rawheight=&1058& src=&https://pic2.zhimg.com/v2-4ab509dd3cf9cf2a571665_b.jpg& data-rawwidth=&720& class=&origin_image zh-lightbox-thumb& width=&720& data-original=&https://pic2.zhimg.com/v2-4ab509dd3cf9cf2a571665_r.jpg&&&/figure&&br&总结如下:&br&&br&必须技能10条:&br&01.Java高级(虚拟机、并发)&br&02.Linux 基本操作&br&03.Hadoop(此处为侠义概念单指HDFS+MapReduce+Yarn )&br&04.HBase(JavaAPI操作+Phoenix )&br&05.Hive(Hql基本操作和原理理解)&br&06.Kafka &br&07.Storm&br&08.Scala需要&br&09.Python&br&10.Spark (Core+sparksql+Spark streaming )&br&11.一些小工具(Sqoop等)&br&&br&高阶技能6条:&br&11.机器学习算法以及mahout库加MLlib&br&12.R语言&br&13.Lambda 架构&br&14.Kappa架构&br&15.Kylin&br&16.Aluxio&br&&br&三.学习路径&br&&br&由于本人是从Java开发通过大概3个月的自学转到大数据开发的。所以我主要分享一下自己的学习路劲。&br&&br&第一阶段:&br&01.Linux学习(跟鸟哥学就ok了)&br&02.Java 高级学习(《深入理解Java虚拟机》、《Java高并发实战》)&br&&br&第二阶段:&br&03.Hadoop (董西成的书)&br&04.HBase(《HBase权威指南》)&br&05.Hive(《Hive开发指南》)&br&06.Scala(《快学Scala》)&br&07.Spark (《Spark 快速大数据分析》)&br&08.Python (跟着廖雪峰的博客学习就ok了)&br&&br&第三阶段:&br&对应技能需求,到网上多搜集一些资料就ok了,我把最重要的事情(要学什么告诉你了),&br&剩下的就是你去搜集对应的资料学习就ok了&br&&br&当然如果你觉得自己看书效率太慢,你可以网上搜集一些课程,跟着课程走也OK 。这个完全根据自己情况决定。如果看书效率不高就很网课,相反的话就自己看书。&br&&br&四.学习资源推荐:&br&&br&01.Apache 官网&br&02.Stackoverflow&br&04.github&br&03.Cloudra官网&br&04.Databrick官网&br&05.过往的记忆(技术博客)&br&06.CSDN,51CTO &br&07.至于书籍当当一搜会有很多,其实内容都差不多。&br&&br&最后但却很重要一点:要多关注技术动向,持续学习。&b&&br&&/b&&br&&figure&&img data-rawheight=&297& src=&https://pic2.zhimg.com/v2-7f5d05b625_b.jpg& data-rawwidth=&477& class=&origin_image zh-lightbox-thumb& width=&477& data-original=&https://pic2.zhimg.com/v2-7f5d05b625_r.jpg&&&/figure&
这个问题简直就是为我而问的啊! 激动ing 曾曾经的我也是一名Java工程师 曾经是一名大数据工程师 ,,,,,,,,,,,,,,,,,,,, 本人目前是一名大数据工程师,项目数据50T,日均数据增长20G左右。 个人是从Java后端开发,经过3个月的业余自学成…
我今年36岁,本科电信,研究生计算机,工作这些年一直从事研发及研发管理工作。题主那些答案里罗列的书我大部分都看过,几乎所有的知识点也多少有实际的项目经验。这是我第一次在知乎上回答问题,之所以忍不住是个人觉得楼主如果按着那些书单去啃《深入理解计算机系统》效率会相当低,因为我自己当年就走过这样的弯路;以下是一些个人看法,希望对你有帮助:&/p&&p&
当题主打算去阅读《深入理解计算机系统》这种书,其实是分拆为三个层次的知识点:&/p&&p&1、计算机硬件基础:这部分最好的学习方式是先去搞一块单片机的开发板,51什么的都可以;搭个开发环境把芯片手册上的基础程序都跑一遍;你就可以知道MCU、存储、外围电路和软件是如何配合工作的(此时还不涉及操作系统);对于复杂CPU中的知识比如流水线之类,我认为能有概念就可以,可以去看一些类似《大话CPU》这样普及类的书或博客;除非你将来的方向可能是芯片设计,那么数字电路、verilog是需要学习的,然后有一个日本人写的《CPU自制入门》不错:)&/p&&p&&br&&/p&&p&2、操作系统:如果要深入理解OS,不要一开始上来就是大部头的Linux和Unix。我个人经验是先上《嵌入式实时操作系统ucos-II》,搭配大约几千行C源码,它不包含多线程、文件系统、驱动管理等高级OS特性;看这个可以先对OS的进程(任务)调度、内存管理、中断等有基本的认识;之后再去看Linux操作系统,我自己是从《Linux 内核完全注释》(基于linux 0.11版本)啃的,很花时间,也需要很多前置知识,比如保护模式的X86 CPU、AT&T的汇编、内联汇编等;当然要深入OS其实国内也有很多大牛的好书,比如《自己动手写操作系统》、《自己动手写嵌入式操作系统》等。这块我认为如果只是为了学习知识,那么到UCOS就可以了;后面深入的,还是要先等自己积累一定的开发经验,比如实际在linux上写过万把行代码再说。至于编译这块,其实当你在做上面这些工作时多少已经有涉猎到了,比如单片机程序加载、ucosII/Linux 启动加载等。想深入学习,推荐《程序员的自我修养》。&/p&&p&备注:(UCOSII源码4、5K,Linux 0.11 大约10K(含汇编)、Linux 现在的版本光一个进程调度就是10K左右,大家可以自己评估下可行性)&/p&&p&&br&&/p&&p&3、上层软件:按照《深入理解计算机系统》的范畴可以分为应用软件开发和网络编程两部分。网络编程这块一开始去啃所谓的协议栈是没有感觉的。最好的方式是自己去写一些socket程序,比如在Linux环境下去实现一个TCP服务器、UDP服务器等,或搭建一个WEB服务器(书里那个tiny web也不错),然后回过头调试的时候去抓个报文,看看传输通道里面到底有什么。应用软件存粹就是写业务逻辑,刻意尝试下多线程、文件IO等特性就好。&/p&&p&&br&&/p&&p&总结一下吧,如果你目标是深入储备这些知识,那么我不建议现在去啃这些书。经典的书是要看的,但前提是先动手做(&b&动手是最最重要&/b&),储备概念后再回过头来体会理解,到时候你可以花几天翻一遍梳理下知识体系就好。&/p&
我今年36岁,本科电信,研究生计算机,工作这些年一直从事研发及研发管理工作。题主那些答案里罗列的书我大部分都看过,几乎所有的知识点也多少有实际的项目经验。这是我第一次在知乎上回答问题,之所以忍不住是个人觉得楼主如果按着那些书单去啃《深入理解…
&figure&&img src=&https://pic3.zhimg.com/v2-db94eeefce03e1f5743ed2_b.jpg& data-rawwidth=&900& data-rawheight=&500& class=&origin_image zh-lightbox-thumb& width=&900& data-original=&https://pic3.zhimg.com/v2-db94eeefce03e1f5743ed2_r.jpg&&&/figure&&p&程序员在工作过程中,会遇到很多需要阅读源码的场景,比如技术预研、选择技术框架、接手以前的项目、review他人的代码、维护老产品等等。可以说,阅读源代码是程序员的基本功,这项基本功是否扎实,会在很大程度上影响一个程序员在技术上的成长速度。&/p&&p&2014年写《&a href=&https://link.zhihu.com/?target=http%3A//item.jd.com/.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Qt on Android核心编程&/a&》和《&a href=&https://link.zhihu.com/?target=http%3A//item.jd.com/.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Qt Quick核心编程&/a&》时,很多内容都是通过分析Qt源码搞明白的。这阵子研究CEF和PPAPI,也主要靠研究源代码来搞明白用法。最近工作上要修改已有项目的一个子系统,也是得硬着头皮先读懂代码。&/p&&p&总之在开发工作这十来年中,读过太多源码了,从源代码中学习到太多东西了,如果不阅读源代码,真不知道自己能否成长起来。&/p&&p&写代码是从模仿开始的,提高也是从观摩别人的优秀设计和代码开始的。所以阅读源码至关重要,接下来咱从下列方面聊聊阅读源码的事儿。&/p&&ul&&li&&p&目的&/p&&/li&&li&&p&工具&/p&&/li&&li&&p&知识准备&/p&&/li&&li&&p&运行与开发环境&/p&&/li&&li&&p&笔记&/p&&/li&&li&&p&实用技巧&/p&&/li&&li&&p&心理调试(散步在各个环节)&/p&&/li&&/ul&&h1&&& 目的&/h1&&p&当我们阅读面前的源码时,无非有以下几种目的:&/p&&ul&&li&&p&纯粹学习&/p&&/li&&li&&p&添加新功能&/p&&/li&&li&&p&重构旧代码&/p&&/li&&li&&p&修复他人的Bug&/p&&/li&&/ul&&p&不同的目的会有不同的心情,会影响到工作的进展,像修复他人的Bug这种事情,类似于没被掰弯的男猿捏着鼻子给另外一个男人擦屁股,是很恶心的,很容易让人拒绝的。所以因这种目标而阅读源码,往往是欲拒还迎、欲说还休,效率较低。然而修复实际工作中帮别人修复Bug这种情形,十有八九你要遇到,无可逃避。所以,心理调试很重要。&/p&&p&为了学习去读源码,这是最愉快的最放松的。不过提醒一点,设定可检验的目标才会有收获,否则就会像走到大街上看见一美女擦肩而过那样,惊艳一下下,过后嘛关系嘛收获也没了。&/p&&p&其他的目的,重构旧代码、添加新功能,比帮别人擦沟子(陕西话,屁股)略强,因为他带有创造性,创造性的活动能给人带来强烈的愉悦,所以虽然这两种目的也有很多让人不爽的部分,不过想到我可以让一棵老树焕发青春,不爽也就慢慢弱下去了。&/p&&h1&&& 工具&/h1&&p&工欲善其事必先利其器,这是亘古不变的道理。要很好的完成阅读源码的任务,我们大概需要下列这些工具:&/p&&ul&&li&&p&SourceInsight,最好的源码浏览工具,它能维护符号库,动态显示上下文,还能绘制调用关系图,最好的,没有之一&/p&&/li&&li&&p&纸质笔记本,随时记录心得和疑惑,随时绘制各种图(类图、时序图、框图),比UML工具快,也比Visio快&/p&&/li&&li&&p&中性笔&/p&&/li&&li&&p&记事本、Notepad++、有道云笔记、为知笔记等,记录阅读源码过程中的关键点、心得体会、分析过程&/p&&/li&&li&&p&Visio,用于绘制简单的框图,表述源码的模块划分、层次结构等&/p&&/li&&li&&p&StartUML,用于最后绘制类图、时序图等,方便交流&/p&&/li&&li&&p&扫描全能王(CamScanner),一款可以通过拍照达到扫描效果的App,可以用它扫描你在纸质笔记本上写下的文字,绘制的框图,分享给其他人,如果你懒得用软件绘制图标,那手绘之后扫描成电子档就最适合你了&/p&&/li&&/ul&&h1&&& 知识准备&/h1&&p&前戏很重要,准备好了后面水到渠成快感不断,否则就会频频受挫直感道阻且长。&/p&&ul&&li&&p&业务基础,每一份有实际意义的源码都离不开业务,必须先对业务有概念&/p&&/li&&li&&p&技术基础,这个源码用什么语言,什么框架,什么第三方模块,都需要先有所了解&/p&&/li&&li&&p&文档,尽量找到业务、需求、概要、详细等文档,帮助会很大,然而,我们经常面临的情况是,只有源码,只有源码,只有源码,片言只字的文档也无,所以只好坚信——源码是最好的文档。这个心理门槛儿其实也容易过,你就想像着源码只是神仙姐姐的画像,看再多画像也不抵当面一眼效果强大——要么摧毁三观要么魂牵梦萦&/p&&/li&&li&&p&人,搞明白哪个程序员维护过这份代码,方便后面不懂时请教,有时人家点一下顶你自己瞎琢磨一天&/p&&/li&&/ul&&h1&&& 运行与开发环境&/h1&&ul&&li&&p&配置好开发环境,目的是为了调试,对有些程序员来讲,调试是弄明白软件内部机理的最好方法,按着F5、F10、F11、F9,一切都搞定了&/p&&/li&&li&&p&配置好运行环境,为使用软件、体验软件做准备,从用户角度,从外面看看软件到底是怎么回事,便于揣摩内部逻辑&/p&&/li&&/ul&&h1&&& 笔记&/h1&&p&在阅读源码的过程中,做笔记是必须的。我有这样的体会,因为代码不是自己写的,很难很快在脑子里刻下印记,经常是看着这里忘了那里,早上觉得弄懂了数据流向,中午吃个饭就忘了。所以,笔记就显得尤为重要。&/p&&ul&&li&&p&找到适合你的记录方式,小本本、软件皆可。用软件(Notepad++、有道笔记、为知笔记等)来记录有个坏处——必须切换屏幕,会在形式上中断代码阅读过程。所以我经常在紧张得不能中断时随手用笔写些断句残章在本子上,告一段落时梳理下用软件再记录。&/p&&/li&&li&&p&尽可能详细的记录,但不必看到什么记录什么,要间隔性的记录,比如弄明白了某个子模块的逻辑、某个类的作用、某些函数的调用关系时再记录,否则记录这个动作本身会打断思考&/p&&/li&&li&&p&每天工作结束,记录进度(弄明白的部分),记录疑问,记录第二天要弄明白什么东西,这样你的工作状态就入栈了,第二天来了很容易出栈,快速进入工作状态&/p&&/li&&li&&p&记录看到的优秀设计,提高审美,见贤思齐,自我成长&/p&&/li&&/ul&&h1&&& 沧海遗珠&/h1&&p&我在漫长的读码生涯里积攒了一些的经验,算是碎碎念,供参考:&/p&&ul&&li&&p&理清某一业务如何映射在代码执行流程上的,这点很关键。&/p&&/li&&li&&p&理清不同模块间的业务关系,代码调用关系,很关键&/p&&/li&&li&&p&调试是弄明白代码调用流程的最快方式,之一&/p&&/li&&li&&p&找出关键代码(代表实际对象的类、衔接不同模块的类、代表业务关键节点的类)&/p&&/li&&li&&p&分析日志可以帮助分析代码执行流程和业务流程&/p&&/li&&li&&p&先用已有的可运行软件,体验业务,琢磨你点这里一下点那里一下代码可能是怎么做出反应的&/p&&/li&&li&&p&阅读应该围绕目的,把实现目标放在第一位,比如修改Bug,如果有期限,在最后日期前搞定是第一要务,然后有时间就继续读源码或改进Bug修复方案,力求没有副作用和后遗症,再有时间就修修别人留下的破窗户(你也可以顺带鄙视下前任维护者)&/p&&/li&&li&&p&千万次的问,还记得前面说要弄明白谁维护过你要读的代码吧,别不好意思,问吧,问吧,问吧&/p&&/li&&li&&p&对着设计文档、接口文档或测试用例看代码&/p&&/li&&li&&p&心理调试,勿畏难,别放弃。我有时看代码,看两天也不知道看了个甚,一头雾水两眼发花是常有的事儿,有时真是觉得搞不定了,然而,这要么是你基础知识没准备好,要么是你找错了入口,要知道,任何一份代码,都有一条隐形的线串着,耐心点,总会找到。这样不行就那样,多换换角度,多换换方法,读不行,就调试,调试不行,就运行,运行不行,就研究日志,都不行,我靠,while(!i.isDead())i.analyzeCode(),跟Y死磕!总之,你不放弃自己,就没人能放弃你!&/p&&/li&&li&&p&给自己设置小奖励,弄明白某个逻辑或某个模块的代码后奖励自己休息一下,5~10分钟,走出办公室转转,或者干脆在网上瞎逛一下,浏览自己喜欢的网站&/p&&/li&&li&&p&读不懂才要读,想不明白才要想,这是进步和成长的开始。那些阻挡你的蹂躏你的而又杀不死你的,终将帮助你成长让你变得更强大。&/p&&/li&&/ul&&br&&br&&p&++++++&/p&&p&读源码是开发者核心竞争力之一种,是具体的技能,更为重要的,是自我觉察和规划,要学会如何寻找方向,持续保持精进,惟其如此,才能越来越值钱。我的专题“&a href=&https://www.zhihu.com/lives/specials/316352& class=&internal&&程序员的成长课:如何拥有你想要的职场&/a&”,正是聚焦在这个方向,提供理念、方法、工具、经验,让你可以拿来分析自己,找到自己的前进方向,让自己越来越有价值,越来越值钱。&/p&&p&入口在这里:&a href=&https://www.zhihu.com/lives/specials/316352& class=&internal&&程序员的成长课:如何拥有你想要的职场&/a&。&/p&
程序员在工作过程中,会遇到很多需要阅读源码的场景,比如技术预研、选择技术框架、接手以前的项目、review他人的代码、维护老产品等等。可以说,阅读源代码是程序员的基本功,这项基本功是否扎实,会在很大程度上影响一个程序员在技术上的成长速度。2014年…
&p&对于Spring Boot的Actuator模块相信大家已经不陌生了,尤其对于其中的/health、/metrics等强大端点已经不陌生(如您还不了解Actuator模块,建议先阅读&a href=&https://link.zhihu.com/?target=http%3A//blog.didispace.com/spring-boot-actuator-1/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&《Spring Boot Actuator监控端点小结》&/a&)。但是,其中还有一个比较特殊的端点/info经常被大家所忽视,因为从最初的理解,它主要用来输出application.properties配置文件中通过info前缀来定义的一些属性,由于乍看之下可能想不到太多应用场景,只是被用来暴露一些应用的基本信息,而基本信息本身也可以在与Spring Cloud结合时作为服务治理的注册信息统一管理,所以这个端点的用处并不是很大。&/p&&p&然而实际上,该端点除了描述应用信息之外,也还可以用来描述Git版本信息,并且整合方法非常简单,下面我们就来看看如何使用/info端点暴露当前应用的Git版本信息。 &/p&&br&&h3&&b&POM配置&/b&&/h3&&p&首先,我们可以挑选任意一个Spring Boot项目,修改它的pom.xml:&/p&&ul&&li&引入spring-boot-starter-actuator,提供/info端点&/li&&/ul&&br&&div class=&highlight&&&pre&&code class=&language-java&&&span&&/span&&span class=&o&&&&/span&&span class=&n&&dependency&/span&&span class=&o&&&&/span&
&span class=&o&&&&/span&&span class=&n&&groupId&/span&&span class=&o&&&&/span&&span class=&n&&org&/span&&span class=&o&&.&/span&&span class=&na&&springframework&/span&&span class=&o&&.&/span&&span class=&na&&boot&/span&&span class=&o&&&/&/span&&span class=&n&&groupId&/span&&span class=&o&&&&/span&
&span class=&o&&&&/span&&span class=&n&&artifactId&/span&&span class=&o&&&&/span&&span class=&n&&spring&/span&&span class=&o&&-&/span&&span class=&n&&boot&/span&&span class=&o&&-&/span&&span class=&n&&starter&/span&&span class=&o&&-&/span&&span class=&n&&actuator&/span&&span class=&o&&&/&/span&&span class=&n&&artifactId&/span&&span class=&o&&&&/span&
&span class=&o&&&/&/span&&span class=&n&&dependency&/span&&span class=&o&&&&/span&
&/code&&/pre&&/div&&ul&&li&添加git-commit-id-plugin插件,该插件用来产生git的版本信息&/li&&/ul&&div class=&highlight&&&pre&&code class=&language-java&&&span&&/span&&span class=&o&&&&/span&&span class=&n&&plugin&/span&&span class=&o&&&&/span&
&span class=&o&&&&/span&&span class=&n&&groupId&/span&&span class=&o&&&&/span&&span class=&n&&pl&/span&&span class=&o&&.&/span&&span class=&na&&project13&/span&&span class=&o&&.&/span&&span class=&na&&maven&/span&&span class=&o&&&/&/span&&span class=&n&&groupId&/span&&span class=&o&&&&/span&
&span class=&o&&&&/span&&span class=&n&&artifactId&/span&&span class=&o&&&&/span&&span class=&n&&git&/span&&span class=&o&&-&/span&&span class=&n&&commit&/span&&span class=&o&&-&/span&&span class=&n&&id&/span&&span class=&o&&-&/span&&span class=&n&&plugin&/span&&span class=&o&&&/&/span&&span class=&n&&artifactId&/span&&span class=&o&&&&/span&
&span class=&o&&&&/span&&span class=&n&&version&/span&&span class=&o&&&&/span&&span class=&mf&&2.1.15&/span&&span class=&o&&&/&/span&&span class=&n&&version&/span&&span class=&o&&&&/span&
&span class=&o&&&&/span&&span class=&n&&executions&/span&&span class=&o&&&&/span&
&span class=&o&&&&/span&&span class=&n&&execution&/span&&span class=&o&&&&/span&
&span class=&o&&&&/span&&span class=&n&&goals&/span&&span class=&o&&&&/span&
&span class=&o&&&&/span&&span class=&n&&goal&/span&&span class=&o&&&&/span&&span class=&n&&revision&/span&&span class=&o&&&/&/span&&span class=&n&&goal&/span&&span class=&o&&&&/span&
&span class=&o&&&/&/span&&span class=&n&&goals&/span&&span class=&o&&&&/span&
&span class=&o&&&/&/span&&span class=&n&&execution&/span&&span class=&o&&&&/span&
&span class=&o&&&/&/span&&span class=&n&&executions&/span&&span class=&o&&&&/span&
&span class=&o&&&&/span&&span class=&n&&configuration&/span&&span class=&o&&&&/span&
&span class=&o&&&&/span&&span class=&n&&dotGitDirectory&/span&&span class=&o&&&&/span&&span class=&n&&$&/span&&span class=&o&&{&/span&&span class=&n&&project&/span&&span class=&o&&.&/span&&span class=&na&&basedir&/span&&span class=&o&&}/.&/span&&span class=&na&&git&/span&&span class=&o&&&/&/span&&span class=&n&&dotGitDirectory&/span&&span class=&o&&&&/span&
&span class=&o&&&/&/span&&span class=&n&&configuration&/span&&span class=&o&&&&/span&
&span class=&o&&&/&/span&&span class=&n&&plugin&/span&&span class=&o&&&&/span&
&/code&&/pre&&/div&&h3&&b&产生git版本信息&/b&&/h3&&ul&&li&在完成了上面的配置之后,执行git-commit-id-plugin插件&/li&&/ul&&br&&figure&&img src=&https://pic4.zhimg.com/v2-dcb24ead09fc_b.jpg& data-rawwidth=&586& data-rawheight=&366& class=&origin_image zh-lightbox-thumb& width=&586& data-original=&https://pic4.zhimg.com/v2-dcb24ead09fc_r.jpg&&&/figure&&p&运行完成后,我们可以在控台中看到类似下面的信息:&/p&&div class=&highlight&&&pre&&code class=&language-java&&&span&&/span&&span class=&o&&[&/span&&span class=&n&&INFO&/span&&span class=&o&&]&/span& &span class=&n&&pl&/span&&span class=&o&&.&/span&&span class=&na&&project13&/span&&span class=&o&&.&/span&&span class=&na&&maven&/span&&span class=&o&&.&/span&&span class=&na&&git&/span&&span class=&o&&.&/span&&span class=&na&&log&/span&&span class=&o&&.&/span&&span class=&na&&MavenLoggerBridge&/span& &span class=&o&&-&/span& &span class=&n&&dotGitDirectory&/span& &span class=&n&&E&/span&&span class=&o&&:&/span&&span class=&err&&\&/span&&span class=&n&&git_project&/span&&span class=&err&&\&/span&&span class=&n&&oschina&/span&&span class=&err&&\&/span&&span class=&n&&SpringBoot&/span&&span class=&o&&-&/span&&span class=&n&&Learning&/span&&span class=&err&&\&/span&&span class=&o&&.&/span&&span class=&na&&git&/span&
&span class=&o&&[&/span&&span class=&n&&INFO&/span&&span class=&o&&]&/span& &span class=&n&&pl&/span&&span class=&o&&.&/span&&span class=&na&&project13&/span&&span class=&o&&.&/span&&span class=&na&&maven&/span&&span class=&o&&.&/span&&span class=&na&&git&/span&&span class=&o&&.&/span&&span class=&na&&log&/span&&span class=&o&&.&/span&&span class=&na&&MavenLoggerBridge&/span& &span class=&o&&-&/span& &span class=&n&&git&/span&&span class=&o&&.&/span&&span class=&na&&build&/span&&span class=&o&&.&/span&&span class=&na&&user&/span&&span class=&o&&.&/span&&span class=&na&&name&/span& &span class=&n&&didi&/span&
&span class=&o&&[&/span&&span class=&n&&INFO&/span&&span class=&o&&]&/span& &span class=&n&&pl&/span&&span class=&o&&.&/span&&span class=&na&&project13&/span&&span class=&o&&.&/span&&span class=&na&&maven&/span&&span class=&o&&.&/span&&span class=&na&&git&/span&&span class=&o&&.&/span&&span class=&na&&log&/span&&span class=&o&&.&/span&&span class=&na&&MavenLoggerBridge&/span& &span class=&o&&-&/span& &span class=&n&&git&/span&&span class=&o&&.&/span&&span class=&na&&build&/span&&span class=&o&&.&/span&&span class=&na&&user&/span&&span class=&o&&.&/span&&span class=&na&&email&/span& &span class=&n&&dyc87112&/span&&span class=&nd&&@qq.com&/span&
&span class=&o&&[&/span&&span class=&n&&INFO&/span&&span class=&o&&]&/span& &span class=&n&&pl&/span&&span class=&o&&.&/span&&span class=&na&&project13&/span&&span class=&o&&.&/span&&span class=&na&&maven&/span&&span class=&o&&.&/span&&span class=&na&&git&/span&&span class=&o&&.&/span&&span class=&na&&log&/span&&span class=&o&&.&/span&&span class=&na&&MavenLoggerBridge&/span& &span class=&o&&-&/span& &span class=&n&&git&/span&&span class=&o&&.&/span&&span class=&na&&branch&/span& &span class=&n&&master&/span&
&span class=&o&&[&/span&&span class=&n&&INFO&/span&&span class=&o&&]&/span& &span class=&n&&pl&/span&&span class=&o&&.&/span&&span class=&na&&project13&/span&&span class=&o&&.&/span&&span class=&na&&maven&/span&&span class=&o&&.&/span&&span class=&na&&git&/span&&span class=&o&&.&/span&&span class=&na&&log&/span&&span class=&o&&.&/span&&span class=&na&&MavenLoggerBridge&/span& &span class=&o&&-&/span& &span class=&o&&--&/span&&span class=&n&&always&/span& &span class=&o&&=&/span& &span class=&kc&&true&/span&
&span class=&o&&[&/span&&span class=&n&&INFO&/span&&span class=&o&&]&/span& &span class=&n&&pl&/span&&span class=&o&&.&/span&&span class=&na&&project13&/span&&span class=&o&&.&/span&&span class=&na&&maven&/span&&span class=&o&&.&/span&&span class=&na&&git&/span&&span class=&o&&.&/span&&span class=&na&&log&/span&&span class=&o&&.&/span&&span class=&na&&MavenLoggerBridge&/span& &span class=&o&&-&/span& &span class=&o&&--&/span&&span class=&n&&dirty&/span& &span class=&o&&=&/span& &span class=&o&&-&/span&&span class=&n&&dirty&/span&
&span class=&o&&[&/span&&span class=&n&&INFO&/span&&span class=&o&&]&/span& &span class=&n&&pl&/span&&span class=&o&&.&/span&&span class=&na&&project13&/span&&span class=&o&&.&/span&&span class=&na&&maven&/span&&span class=&o&&.&/span&&span class=&na&&git&/span&&span class=&o&&.&/span&&span class=&na&&log&/span&&span class=&o&&.&/span&&span class=&na&&MavenLoggerBridge&/span& &span class=&o&&-&/span& &span class=&o&&--&/span&&span class=&n&&abbrev&/span& &span class=&o&&=&/span& &span class=&mi&&7&/span&
&span class=&o&&[&/span&&span class=&n&&INFO&/span&&span class=&o&&]&/span& &span class=&n&&pl&/span&&span class=&o&&.&/span&&span class=&na&&project13&/span&&span class=&o&&.&/span&&span class=&na&&maven&/span&&span class=&o&&.&/span&&span class=&na&&git&/span&&span class=&o&&.&/span&&span class=&na&&log&/span&&span class=&o&&.&/span&&span class=&na&&MavenLoggerBridge&/span& &span class=&o&&-&/span& &span class=&n&&Tag&/span& &span class=&n&&refs&/span& &span class=&o&&[&/span& &span class=&o&&[&/span&&span class=&n&&Ref&/span&&span class=&o&&[&/span&&span class=&n&&refs&/span&&span class=&o&&/&/span&&span class=&n&&tags&/span&&span class=&o&&/&/span&&span class=&n&&chapter1&/span&&span class=&o&&=&/span&&span class=&n&&ecadea02c8ef0a112&/span&&span class=&o&&]]&/span& &span class=&o&&]&/span&
&span class=&o&&[&/span&&span class=&n&&INFO&/span&&span class=&o&&]&/span& &span class=&n&&pl&/span&&span class=&o&&.&/span&&span class=&na&&project13&/span&&span class=&o&&.&/span&&span class=&na&&maven&/span&&span class=&o&&.&/span&&span class=&na&&git&/span&&span class=&o&&.&/span&&span class=&na&&log&/span&&span class=&o&&.&/span&&span class=&na&&MavenLoggerBridge&/span& &span class=&o&&-&/span& &span class=&n&&Created&/span& &span class=&n&&map&/span&&span class=&o&&:&/span& &span class=&o&&[&/span& &span class=&o&&{}&/span& &span class=&o&&]&/span&
&span class=&o&&[&/span&&span class=&n&&INFO&/span&&span class=&o&&]&/span& &span class=&n&&pl&/span&&span class=&o&&.&/span&&span class=&na&&project13&/span&&span class=&o&&.&/span&&span class=&na&&maven&/span&&span class=&o&&.&/span&&span class=&na&&git&/span&&span class=&o&&.&/span&&span class=&na&&log&/span&&span class=&o&&.&/span&&span class=&na&&MavenLoggerBridge&/span& &span class=&o&&-&/span& &span class=&n&&HEAD&/span& &span class=&n&&is&/span& &span class=&o&&[&/span& &span class=&n&&ede9b5df75ec016fa5e5&/span& &span class=&o&&]&/span&
&span class=&o&&[&/span&&span class=&n&&INFO&/span&&span class=&o&&]&/span& &span class=&n&&pl&/span&&span class=&o&&.&/span&&span class=&na&&project13&/span&&span class=&o&&.&/span&&span class=&na&&maven&/span&&span class=&o&&.&/span&&span class=&na&&git&/span&&span class=&o&&.&/span&&span class=&na&&log&/span&&span class=&o&&.&/span&&span class=&na&&MavenLoggerBridge&/span& &span class=&o&&-&/span& &span class=&n&&Repo&/span& &span class=&n&&is&/span& &span class=&n&&in&/span& &span class=&n&&dirty&/span& &span class=&n&&state&/span& &span class=&o&&[&/span& &span class=&kc&&true&/span& &span class=&o&&]&/span&
&span class=&o&&[&/span&&span class=&n&&INFO&/span&&span class=&o&&]&/span& &span class=&n&&pl&/span&&span class=&o&&.&/span&&span class=&na&&project13&/span&&span class=&o&&.&/span&&span class=&na&&maven&/span&&span class=&o&&.&/span&&span class=&na&&git&/span&&span class=&o&&.&/span&&span class=&na&&log&/span&&span class=&o&&.&/span&&span class=&na&&MavenLoggerBridge&/span& &span class=&o&&-&/span& &span class=&n&&git&/span&&span cl

我要回帖

更多关于 推荐人没有收到邮件 的文章

 

随机推荐