精华内容
下载资源
问答
  • 例如,当前项目有一个第三方依赖,而这个第三方依赖由于某些原因依赖了另一个类库的SNAPSHOT版本,name这个SNAPSHOT就会成为当前项目的传递性依赖,而SNAPSHOT的不稳定性会直接影响到当前的项目。这时就需要排除掉该...

    排除依赖

    传递性依赖会给项目隐式地引入很多依赖,着极大简化了项目依赖的管理,但是有些时候这种特性也会带来问题。例如,当前项目有一个第三方依赖,而这个第三方依赖由于某些原因依赖了另一个类库的SNAPSHOT版本,那么这个SNAPSHOT就会成为当前项目的传递性依赖,而SNAPSHOT的不稳定性会直接影响到当前的项目。这时就需要排除掉该SNAPSHOT,并且在当前项目中声明该类库的某个正式发布的版本。还有一些情况,你可能也想要替换掉某个传递性依赖,比如Sun JTA API,Hibernate依赖与这个JAR,但是由于版权的因素,该类库不在中央仓库中,而Apache Geronimo项目有一个对应的实现。这时你就可以排除Sun JAT API,而声明Geronimo的JTA API实现。

    <project>
      <modelVersion>4.0.0</modelVersion>
    
      <groupId>com.cc.maven</groupId>
      <artifactId>project-a</artifactId>
      <version>1.0.0</version>
      <packaging>jar</packaging>
    
    
      <dependencies>
        <dependency>
          <groupId>com.cc.maven</groupId>
          <artifactId>project-b</artifactId>
          <version>1.0.0</version>
          <exclusions>
                <exclusion>
                 <groupId>com.cc.maven</groupId>
                  <artifactId>project-c</artifactId>
                </exclusion>
        </exclusions>
        </dependency>
    
        <dependency>
          <groupId>com.cc.maven</groupId>
          <artifactId>project-b</artifactId>
          <version>1.1.0</version>
        </dependency>
    
      </dependencies>
    </project>

    上述代码中,项目A依赖于项目B,但是由于一些原因,不想引入传递性依赖C,而是自己显式声明对项目C 1.1.0版本的依赖。代码中使用exclusions元素声明排除依赖,exclusions可以包含一个或者多个exclusion子元素,因此可以排除一个或者多个传递性依赖。需要注意的是,声明exclusion的时候只需要groupId和artifactId,而不需要version元素,这是因为只需要groupId和artifactId就能唯一定位依赖图中的某个依赖。换句话说,maven解析后的依赖中,不可能出现groupId和artifactId项目,但是version不同的两个依赖。该例的依赖解析逻辑如下所示:
    这里写图片描述

    归类依赖

    关于Spring Framework的依赖有很多,他们来自同一个项目的不同模块。因此所有这些依赖的版本都是相同的,可以知道,如果将来想要升级Spring Framework的话,这些依赖版本也会一起升级。这一情况在java中也似曾相识,考虑代码如下:

    public double c(double r){
        return 2 * 3.14 * r;
    }
    
    public double s(double r){
        return 3.14 * r * r;
    }

    这两个简单的方程式计算圆的周长和面积,有经验的程序员一眼就能看出问题,使用字面量3.14显然不合适,应该定义一个常量并在方法中使用,如下:

    public final double PI = 3.14;
    
    public double c(double r){
        return 2 * PI * r;
    }
    
    public double s(double r){
        return PI * r * r;
    }

    使用常量不仅可以使代码变得更加简洁,更重要的是可以避免重复,只需要更改一处,降低了错误的概率。
    使用maven属性归类依赖:

    <project>
      <modelVersion>4.0.0</modelVersion>
    
      <groupId>com.juven.mvnbook.account</groupId>
      <artifactId>account-email</artifactId>
      <version>1.0.0-SNAPSHOT</version>
      <name>Account Email</name>
    
    
      <properties>
         <springframework.version>2.5.6</springframework.version>
      </properties>
    
      <dependencies>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-core</artifactId>
          <version>${springframework.version}</version>
        </dependency>
    
         <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context</artifactId>
          <version>${springframework.version}</version>
        </dependency>
    
         <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context-support</artifactId>
          <version>${springframework.version}</version>
        </dependency>
      </dependencies>
    </project>

    这里简单使用到了Maven的属性,首先使用properties元素定义了Maven的属性,该例子中定义了一个springframework.version子元素,其值为2.5.6,有了这个属性之后,Maven运行的时候,会将POM中所有${springframework.version}替换成2.5.6,也就是说,可以使用${}的方式来引用Maven的属性,然后将所有Spring Framework依赖的版本值用这一属性引用。这个和在java中常量PI替换3.14是同样的道理,只是语法不同而已。

    优化依赖

    在软件开发的过程中,程序员会通过重构等方式不断地优化自己的代码,使其变得更简洁、更灵活。同理,程序员也应该能够对maven项目的依赖了然于胸,并对其优化,如去除多余的依赖,显式声明某些必要的依赖。
    maven会自动解析所有项目的直接依赖和传递性依赖,并且根据规则正确判断每个依赖的范围。对于一些依赖冲突,也能进行调解,以确保任何一个构件只能唯一的版本在依赖中存在。在这些工作之后,最后得到的那些依赖被称为已解析依赖。
    可以通过运行如下命令查看当前项目的已解析依赖:mvn dependency:list
    这里写图片描述
    将直接在当前POM声明的依赖定义为顶层依赖,而这些顶层依赖的依赖则定义为第二层依赖,以此类推,有第三、第四层依赖。当这些依赖经过Maven解析之后,就会构成一个依赖树,通过这颗依赖树,就能够很清楚地看到某个依赖是通过哪条路径引入的。可以运行如下命令查看当前项目的依赖树:mvn dependency:tree
    这里写图片描述

    使用mvn dependency:listmvn dependency:tree可以帮助我们详细了解项目中所有的依赖的具体详细,在此基础上,还有mvn dependency:analyze工具可以帮助分析当前项目的依赖
    这里写图片描述

    展开全文
  • 依赖依赖+stage划分

    千次阅读 2018-03-06 22:22:55
    1.RDD的依赖关系1.1 WordCount中的RDDRDD和它依赖的父RDD(s)的关系有两种不同的类型,即窄依赖(narrow dependency)和宽依赖(wide dependency)。1.2 窄依赖依赖指的是每一个父RDD的Partition最多被子RDD的...

    1.RDD的依赖关系

    1.1  WordCount中的RDD


    RDD和它依赖的父RDD(s)的关系有两种不同的类型,即窄依赖(narrow dependency)和宽依赖(wide dependency)。

    1.2  窄依赖

    窄依赖指的是每一个父RDD的Partition最多被子RDD的一个Partition使用

    总结:窄依赖我们形象的比喻为独生子女

    1.3  宽依赖

    宽依赖指的是多个子RDD的Partition会依赖同一个父RDD的Partition

    总结:窄依赖我们形象的比喻为超生


    窄依赖:可以理解为独生子女

    宽依赖:可以理解为超生

    如上图所示,一个文件被textFile后经过两次转换,每次转换后生成的新的RDD都和原分区一一对应,为窄依赖关系。

    当map算子计算失败时,可以直接去上一步的RDD中重新计算,而不需要其他的分区参与。但是如果最后的action算子在计算某个RDD时,计算失败,将会到上一层的多个分区中寻找依赖关系,比较麻烦。

    stage解决了这个问题,它根据宽依赖和窄依赖的关系进行换分,如上图将存在窄依赖关系的RDD换分成为一个stage。


    2.  DAG的生成

    2.1  什么是DAG

    DAG(Directed Acyclic Graph)叫做有向无环图,原始的RDD通过一系列的转换就就形成了DAG,根据RDD之间的依赖关系的不同将DAG划分成不同的Stage,对于窄依赖,partition的转换处理在Stage中完成计算。对于宽依赖,由于有Shuffle的存在,只能在parent RDD处理完成后,才能开始接下来的计算,因此宽依赖是划分Stage的依据

    2.2  DAG在spark中的应用

    • 在Spark应用中,整个执行流程在逻辑上会形成有向无环图(DAG)。
    • Action算子触发之后,将所有累积的算子形成一个有向无环图,然后由调度器调度该图上的任务进行运算。
    • Spark的调度方式与MapReduce有所不同。Spark根据RDD之间不同的依赖关系切分形成不同的阶段(Stage),一个阶段包含一系列函数执行流水线。
    • 图中的A、B、C、D、E、F分别代表不同的RDD,RDD内的方框代表分区。
    • 数据从HDFS输入Spark,形成RDD A和RDD C,RDD C上执行map操作,转换为RDD D,RDD B和RDD E执行join操作,转换为F,而在B和E连接转化为F的过程中又会执行Shuffle,最后RDD F通过函数saveAsSequenceFile输出并保存到HDFS中。

    2.3.  Spark的任务提交机制

     

    作业执行流程描述:

    1、客户端启动后直接运行用户程序,启动Driver相关的工作:DAGSchedulerBlockManagerMaster等。

    2、客户端的DriverMaster注册。

    3Master还会让Worker启动ExeuctorWorker创建一个ExecutorRunner线程,ExecutorRunner会启动ExecutorBackend进程。

    4ExecutorBackend启动后会向DriverSchedulerBackend注册。DriverDAGScheduler解析作业并生成相应的Stage,每个Stage包含的Task通过TaskScheduler分配给Executor执行。

    5、所有stage都完成后作业结束。


    简单理解:

    首先Driver和master通信(提交任务,申请资源,传送driverUrl地址)如 spark-submit xxx.jar --total-executor-cores 2 --executor-memory 512,该命令执行后master会根据提交的信息申请资源;

    master主要做几件事情:1拿出所有workers上的资源;2按照资源的大小进行排序;3按照排序顺序取资源;4让worker启动executor。

    最后把任务换分为stage,将stage添加到taskSet中。循环taskset,将task下发。


    展开全文
  • 学习过Spring框架的人一定都会听过Spring的IoC(控制反转) 、DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC 、DI这两个概念是模糊不清的,是很难理解的,今天和大家分享网上的一些技术大牛们对Spring...

    依赖注入框架Dagger2详解(一),依赖注入和控制反转的深入理解
    依赖注入框架Dagger2详解(二),Java依赖注入标准JSR-330规范
    依赖注入框架Dagger2详解(三),Java注解处理器APT入门
    依赖注入框架Dagger2详解(四),初级篇
    依赖注入框架Dagger2详解(五),中级篇
    依赖注入框架Dagger2详解(六),高级篇

    什么是JSR

    JSR是Java Specification Requests的缩写,意思是Java 规范提案。是指向JCP(Java Community Process)提出新增一个标准化技术规范的正式请求。任何人都可以提交JSR,以向Java平台增添新的API和服务。JSR已成为Java界的一个重要标准。

    JSR-330与JSR-299的区别

    由于Rod Johnson(SpringSource)和Bob Lee(谷歌公司)领导的JSR-330(Java的依赖注入)成为Java EE 6的一部分,因此存在很多混乱.JSR-330非常简单。它包含了自己的一些注释:javax.inject。该软件包包含以下元素:Inject, Qualifier, Scope, Singleton, Named和Provider。它定义了基本的依赖注入语义。

    以Gavin King为主导的JSR-299(Java上下文和依赖注入)使用JSR-330作为基础,并通过模块化,交叉切割方面(装饰器,拦截器),自定义范围或类型安全注入功能显着增强它。JSR-299位于JSR-330之上。

    JSR-299和JSR-330之间的关系与JPA和JDBC之间的关系相当。JPA使用内部JDBC,但您仍然可以在没有JPA的情况下使用JDBC。在Java EE 6中,您可以使用JSR-330作为基本内容,并使用JSR-299按需增强它。实践中几乎没有重叠。您甚至可以将JSR-299 / JSR-330与EJB 3.1混合使用 - 以简化您的应用程序。

    Java EE 7/Java EE 6 五个依赖注入标准的比较

    在这里插入图片描述
    https://codebulb.github.io/pages/2015/04/java-ee7-java-ee-6-bean-types-overview/wildfly.html

    JSR-330官方文档地址:
    https://docs.oracle.com/javaee/7/api/javax/inject/package-summary.html
    在这里插入图片描述

    javax.inject

    包javax.inject 指定了获取对象的一种方法,该方法与构造器、工厂以及服务定位器(例如JNDI)这些传统方法相比可以获得更好的可重用性、可测试性以及可维护性。此方法的处理过程就是大家熟知的依赖注入,它对于大多数应用是非常有价值的。

    在我们的程序中,很多类型依赖于其他类型。例如,一个 Stopwatch 可能依赖于一个 TimeSource。一些类型被另一个类型依赖,我们就把这些类型叫做这个类型的依赖(物)。在运行时查找一个依赖实例的过程叫做解析依赖。如果找不到依赖的实例,那我们称该依赖为不能满足的,并导致应用运行失败。

    在不使用依赖注入时,对象的依赖解析有几种方式。最常见的就是通过编写直接调用构造器的代码完成:

     class Stopwatch {
         final TimeSource timeSource;
         Stopwatch () {
           timeSource = new AtomicClock(...);
         }
         void start() { ... }
         long stop() { ... }
       }
    

    如果需要更有弹性一点,那么我们可以通过工厂或服务定位器实现:

     class Stopwatch {
         final TimeSource timeSource;
         Stopwatch () {
           timeSource = DefaultTimeSource.getInstance();
         }
         void start() { ... }
         long stop() { ... }
       }
    

    在使用这些传统方式进行依赖解析时,程序员必须做出适当权衡。构造器非常简洁,但却有一些限制(对象生存期,对象复用)。工厂确实解耦了客户与实现,但却需要样本式的代码。服务定位器更进一步地解耦了客户与实现,但却降低了编译时的类型安全。并且,这三个方式都不适合进行单元测试。例如,当程序员使用工厂时,该工厂的每一个产品都必须模拟出来,测试完后还要得记得清理:

    void testStopwatch() {
         TimeSource original = DefaultTimeSource.getInstance();
         DefaultTimeSource.setInstance(new MockTimeSource());
         try {
           // Now, we can actually test Stopwatch.
           Stopwatch sw = new Stopwatch();
           ...
         } finally {
           DefaultTimeSource.setInstance(original);
         }
       }
    

    现实中,要模拟工厂将导致更多的样本式代码。测试模拟出的产品并清理它们在依赖多的情况下很快就控制不了了。更糟的是,程序员必须精确地预测未来到底需要多少这样的弹性,并为他做的“弹性选择”负责。如果程序员开始时选择了构造器方式,但后来需要一个更有弹性的方式,那他就不得不替换所有调用构造器的代码。如果程序员一开始过于谨慎地选择了工厂方式,结果可能导致要编写很多额外的样本式代码,引入了不必要的复杂度,潜在的问题比比皆是。

    依赖注入就是为了解决这些问题。代替程序员调用构造器或工厂,一个称作依赖注入器的工具将把依赖传递给对象:

    class Stopwatch {
         final TimeSource timeSource;
         @Inject Stopwatch(TimeSource TimeSource) {
           this.TimeSource = TimeSource;
         }
         void start() { ... }
         long stop() { ... }
       }
    

    注入器将更进一步地传递依赖给其他的依赖,直到它构造出整个对象图。例如,假设一个程序员需要注入器创建一个 StopwatchWidget 实例:

     /** GUI for a Stopwatch */
       class StopwatchWidget {
         @Inject StopwatchWidget(Stopwatch sw) { ... }
         ...
    }
    

    注入器可能会:

    • 查找一个 TimeSource 实例
    • 使用找到的 TimeSource 实例构造一个 Stopwatch
    • 使用构造的 Stopwatch 实例构造一个 StopwatchWidget

    这使得代码保持干净,使得程序员感到使用依赖(物)的基础设施非常容易。

    现在,在单元测试中,程序员可以直接构造对象(不使用注入器)并将该对象以模拟依赖的方式直接传入待测对象的构造中。程序员再也不需要为每一次测试都配置并清理工厂或服务定位器。这大大简化了我们的单元测试:

     void testStopwatch() {
         Stopwatch sw = new Stopwatch(new MockTimeSource());
         ...
       }
    

    完全降低了单元测试的复杂度,降低的复杂程度与待测对象的数目及其依赖成正比。

    包javax.inject为使用这样的轻便类提供了依赖注入注解,但没有引入依赖配置方式。依赖配置方式取决于注入器的实现。程序员只需要标注了构造器、方法或字段来说明它们的可注入性(上面的例子就是构造器注入)。依赖注入器通过这些注解来识别一个类的依赖,并在运行时注入这些依赖。此外,注入器要能够在构建时验证所有的依赖是否满足。相比之下,服务定位器在构建时是不能检测到依赖不满足情况的,直到运行时才能发现。

    注入器实现有很多形式。一个注入器可以通过 XML、注解、DSL(领域规约语言),或是普通 Java代码来进行配置。注入器实现可以使用反射或代码生成。使用编译时代码生成的注入器甚至可能没有它自己的运行时描述。而其他注入器实现无论在编译时还是运行

    时可能都不使用代码生成。一个“容器”,其实可以把它定义为一个注入器,不过包javax.inject不涉及非常大概念,旨在最小化注入器实现的限制。

    @Inject

    注解 @Inject
    标识了可注入的构造器、方法或字段。可以用于静态或实例成员。一个可注入的成员可以被任何访问修饰符(private、package-
    private、protected、public)修饰。注入顺序为构造器,字段,最后是方法。超类的字段、方法将优先于子类的字段、方法被注入。对于
    同一个类的字段是不区分注入顺序的,同一个类的方法亦同。

    可注入的构造器指的是标注了 @Inject 并接受 0个或多个依赖作为实参的构造器。对于每一个类而言,@Inject最多只允许对一个类的一个构造器进行标注:

    @Inject ConstructorModifiersopt SimpleTypeName(FormalParameterListopt) Throwsopt ConstructorBody
    

    @Inject 对于仅存在默认构造器(访问修饰符为 public 并且无参数)的情况是可选的,注入器将调用默认构造器:

    @Injectopt Annotationsopt public SimpleTypeName() Throwsopt ConstructorBody
    

    可注入的字段:

    • 被 @Inject 标注。
    • 不是 final 的。
    • 可以使用任何有效名。
    @Inject FieldModifiersopt Type VariableDeclarators;
    

    可注入的方法:

    • 被 @Inject 标注。
    • 不是 abstract 的。
    • 没有声明类型参数的方法。
    • 可以带返回值。
    • 可以使用任何有效名。
    • 接受0个或多个依赖作为实参。
    @Inject MethodModifiersopt ResultType Identifier(FormalParameterListopt) Throwsopt MethodBody
    

    注入器忽略了注入方法的返回值,因为方法的非空返回可能会用于其他上下文(例如 builder-style 的方法链)。

    例子:

    public class Car {
         // Injectable constructor
         @Inject public Car(Engine engine) { ... }
    
         // Injectable field
         @Inject private Provider<Seat> seatProvider;
    
         // Injectable package-private method
         @Inject void install(Windshield windshield, Trunk trunk) { ... }
       }
    

    当一个方法标注了 @Inject 并覆写了其他标注了 @Inject 的方法时,对于每一个实例的每一次注入请求,该方法只会被注入一次。当一个方法没有标注 @Inject 并覆写了其他标注了 @Inject 的方法时,该方法不会被注入。

    要进行成员注入就必须标注 @Inject。一个可注入的成员可以使用任何访问修饰符(包括 private)。不过受于平台或注入器限制(例如安全管理或缺乏反射支持),标注了 @Inject 的非公有成员可能将不被注入。

    Qualifiers限定器注解用于标注可注入的字段或参数,外加该字段或参数的类型,就可以标识出待注入的实现。限定符是可选的,当与 @Inject 一起使用在与注入器无关的类时,对于一个字段或参数,应该最多只有一个限定符被标注。在下面的例子中,限定符被标注了粗体:

     public class Car {
         @Inject private @Leather Provider<Seat> seatProvider;
    
         @Inject void install(@Tinted Windshield windshield,
             @Big Trunk trunk) { ... }
       }
    

    如果一个可注入的方法覆写了其他方法,覆写方法的参数不会自动地从被覆写的方法上继承限定器。

    可注入的值
    对于一个给定的类型 T 与可选的限定器,注入器必须能够注入用户指定的类:

    • a. 与 T 是赋值兼容的

    • b. 有一个可注入的构造器。
      例如,用户可能使用外部配置来选择一个 T 的实现。此外,待注入的值取决于注入器实现与它的配置。

    • 循环依赖
      本规范并未详细要求探测循环依赖与解析循环依赖。两个构造器间的循环依赖是一个非常明显的问题,另外,对于可注入字段或方法的循环依赖也很常见,例如:

    class A {
         @Inject B b;
       }
       class B {
         @Inject A a;
       }
    

    当构造 A 的一个实例时,一个简单的注入器可能会无限循环构造:B 的一个实例注入给 A 的一个实例,第二个 A 的实例注入给 B 的一个实例,第二个 B 的实例注入给第二个 A 的实例,……

    一个保守的注入器可能会在构建时探测出这个循环依赖,并生成一个错误,指出程序员可以使用Provider或 Provider 对应替换 A 或 B 来打破这个循环依赖。从注入的构造器或方法调用该 provider 的 get()
    将打破这个循环依赖。对于方法或字段注入的情况,将其依赖的一边放置到某作用域(例如单例作用域)也可以使得循环依赖能够被注入器解析。

    @Qualifier

    注解 @Qualifier 用于标识限定器注解。任何人都可以定义新的限定器注解。一个限定器注解:
    是被 @Qualifier、@Retention(RUNTIME) 标注的,通常也被 @Documented 标注。可以拥有属性。

    可能是公共 API 的一部分,就像依赖类型一样,而不像类型实现那样不作为公共 API 的一部分。如果标注了 @Target 可能会有一些用法限制。本规范只是指定了限定器注解可以被使用在字段和参数上,但一些注入器配置可能使用限定器注解在其他一些地方(例如方法或类)上。

    例子:

     @java.lang.annotation.Documented
       @java.lang.annotation.Retention(RUNTIME)
       @javax.inject.Qualifier
       public @interface Leather {
         Color color() default Color.TAN;
         public enum Color { RED, BLACK, TAN }
       }
    

    Provider

    接口 Provider 用于提供类型 T 的实列。Provider 是一般情况是由注入器实现的。对于任何可注入的 T 而言,您也可以注入 Provider。与直接注入 T 相比,注入 Provider 使得:

    • 可以返回多个实例。
    • 实例的返回可以延迟化或可选
    • 打破循环依赖。
    • 可以在一个已知作用域的实例内查询一个更小作用域内的实例。

    例子:

    class Car {
         @Inject Car(Provider<Seat> seatProvider) {
           Seat driver = seatProvider.get();
           Seat passenger = seatProvider.get();
           ...
         }
       }
    

    get()用于提供一个完全构造的类型 T 的实例。

    异常抛出:RuntimeException —— 当注入器在提供实例时遇到错误将抛出此异常。例如,对于一个可注入的成员 T
    抛出了一个异常,注入器将包装此异常并将它抛给 get()
    的调用者。调用者不应该尝试处理此类异常,因为不同注入器实现的行为不一样,即使是同一个注入器,也会因为配置不同而表现的行为不同。

    @Named

    基于String 的限定器。
    例子:

     public class Car {
         @Inject @Named("driver") Seat driverSeat;
         @Inject @Named("passenger") Seat passengerSeat;
         ...
       }
    

    @Scope

    注解 @Scope
    用于标识作用域注解。一个作用域注解是被标识在包含一个可注入构造器的类上的,用于控制该类型的实例如何被注入器重用。缺省情况下,如果没有标识作用域注
    解,注入器将为每一次注入都创建(通过注入类型的构造器)新实例,并不重用已有实例。如果多个线程都能够访问一个作用域内的实例,该实例实现应该是线程安
    全的。作用域实现由注入器完成。

    在下面的例子中,作用域注解 @Singleton 确保我们始终只有一个 Log 实例:

    @Singleton
       class Log {
         void log(String message) { ... }
       }
    

    当多于一个作用域注解或不被注入器支持的作用域注解被使用在同一个类上时,注入器将生成一个错误。
    一个作用域注解:

    • 被标注了 @Scope、@Retention(RUNTIME) 标注的,通常也被 @Documented 标注。
    • 不应该含有属性。
    • 不应该被 @Inherited 标注,因此作用域与继承实现(正交)无关。
    • 如果标注了 @Target 可能会有一些用法限制。本规范只是指定了作用域注解可以被使用在类上,但一些注入器配置可能使用作用域注解在其他一些地方(例如工厂方法返回)上。
      例子:
     @java.lang.annotation.Documented
       @java.lang.annotation.Retention(RUNTIME)
       @javax.inject.Scope
       public @interface RequestScoped {}
    

    使用 @Scope 来标识一个作用域注解有助于注入器探测程序员使用了作用域注解但却忘了去配置作用域的情况。一个保守的注入器应该生成一个错误而不是去适用该作用域。

    @Singleton

    注解 @Singleton 标识了注入器只实例化一次的类型,该注解不能被继承。

    展开全文
  • 管理服务之间的依赖关系

    千次阅读 2019-08-16 15:29:14
    依赖在某种程度上不可避免,但是过多的依赖势必会增加系统复杂性和降低代码维护性,从而成为团队开发的阻碍。在微服务架构中存在众多服务,服务之间需要管理相互之间的依赖关系。 1. 构建无环依赖架构 依赖关系有...

    在系统的各种组件之间,尤其是类、包、模块以及服务之间都可能存在依赖关系。依赖在某种程度上不可避免,但是过多的依赖势必会增加系统复杂性和降低代码维护性,从而成为团队开发的阻碍。在微服务架构中存在众多服务,服务之间需要管理相互之间的依赖关系。

    1. 构建无环依赖架构

    依赖关系有三种基本的表现形式,其中类似Service1依赖于Service2这种直接依赖最容易识别和管理(见下图a);间接依赖即直接依赖关系的衍生,当Service1依赖Service2,而Service2又依赖Service3时,Service1就与Service3发生了间接依赖关系(见下图b);而所谓循环依赖就是Service1和Service2之间相互依赖(见下图c),循环依赖有时候并不像图中描述的那么容易识别,因为产生循环依赖的多个组件之间可能同时存在各种直接和间接依赖关系。

    下图就是一个循环依赖的例子,User对象可以创建Order对象并保持Order对象列表,而Order对象同样需要使用User对象,并根据User对象中的打折(Discount)信息计算Order金额,这样对象User和Order之间就存在循环依赖关系。

    根据无环依赖原则(Acyclic Dependencies Principle,ADP),系统设计中不应该存在循环依赖,该条原则对于微服务架构而言同样适用。消除循环依赖的基本思路就是通过在两个相互循环依赖的组件之间添加中间层,变循环依赖为间接依赖。有三种策略可以做到这一点,分别是上移、下移和回调。下面我们将通过基于组件的具体示例介绍这三个策略,因为服务由一个或多个组件构成,所以其适用于服务之间的关系管理。

    (1)上移

    关系上移意味着把两个相互依赖组件中的交互部分抽象出来形成一个新的组件,而新组件同时包含着原有两个组件的引用,这样就把循环依赖关系剥离出来并上升到一个更高层次的组件中。如下图就是使用上移策略对User和Order原始关系进行重构的结果,我们引入了一个新的组件Mediator,并通过其提供的payOrder方法对循环依赖进行了剥离,该方法同时使用Order和User作为参数并实现了Order中根据User的打折信息进行金额计算的业务逻辑。Mediator组件消除了Order中原有对User的依赖关系并在依赖关系上处于User和Order的上层。

    (2)下移

    关系下移策略与上移策略切入点刚好相反。我们同样针对User和Order的循环依赖关系进行重构,重构的方法是抽象出一个Calculator组件专门包含打折信息的金额计算方法,该Calculator由User创建,并注入到Order的pay方法中去(见下图)。通过这种方式,原有的Order对User的依赖关系就转变为Order对Calculator的依赖关系,而User因为是Calculator的创建者同样依赖于Calculator,这种生成一个位于User和Order之下但能同样消除Order中原有对User的依赖关系的组件的策略,就称之为下移。

    (3)回调

    回调(Callback)本质上就是一种双向调用模式,也就是说,被调用方在被调用的同时也会调用对方。在面向对象的语言中,回调通常是通过接口或抽象类的方式来实现。下图就是通过回调机制进行依赖关系重构后的结果。我们抽象出一个Calculator接口用于封装金额计算逻辑,该接口与Order处于同一层次,而User则实现了该接口,这样Order对User的依赖就转变成Order对Calculator接口的依赖,也就是把对User的直接依赖转变成了间接依赖。通过依赖注入机制,我们可以很容易的实现Order和User之间的有效交互。

    2. 弱依赖与强依赖

    从故障容忍度的角度来看,服务之间的依赖关系又可以分为弱依赖与强依赖。如果某个微服务无法正常提供服务,则依赖它的整个业务流程无法正常执行下去,那么即为强依赖关系,也就是说,强依赖关系是服务正常运转的基本单元。而弱依赖则没有这样的限制,对于如消息发送等服务,如果该服务无法正常提供功能,核心业务流程同样可以正常运行。

    对强依赖和弱依赖对应的消息进行区分可以得到可靠消息和非可靠消息。可靠消息必须通过系统级的方式进行保障,使得关键服务能够运行,而对非可靠消息,则可以简单容忍丢失行为,使得整体系统的复杂度降低。通常,我们可以对弱依赖设置开关,其目的是在极端资源瓶颈出现的时候,使得业务系统能够丢弃一些非核心服务从而保全更关键的核心服务。关于可靠事件以及服务依赖关系所涉及的服务分级、限流和降级操作我们将在后面的文章中进一步展开讨论。

     

    如果对文章感兴趣,可以关注我的微信公众号:程序员向架构师转型,或扫描下面的二维码。

    我出版了《系统架构设计:程序员向架构师转型之路》、《向技术管理者转型:软件开发人员跨越行业、技术、管理的转型思维与实践》、《微服务设计原理与架构》、《微服务架构实战》等书籍,并翻译有《深入RabbitMQ》和《Spring5响应式编程实战》,欢迎交流。

    展开全文
  • springboot基本依赖整理

    千次阅读 2019-08-23 10:00:18
    当我们创建一个springboot项目时我们需要一个springboot的项目依赖,这个依赖添加后标志着着这个maven项目成为了一个speingboot项目,依赖如下 <dependency> <groupId>org.mybatis.spring.boot</...
  • 深入理解NPM依赖模型

    千次阅读 2018-09-15 20:30:05
    虽然有其他选择,但npm的江湖地位短期内已经无法撼动。即便是强大如Bower这样可以管理前端所有文件的工具也被推到了一边,对我来说最有趣的是npm相对新颖的依赖管理方法。不幸的是,根据我的经验,它实际上并没有...
  • spring之依赖注入

    千次阅读 2015-01-23 17:49:29
    spring的核心是依赖注入,此基础成为整个spring框架的基石。 所谓依赖注入,是指在程序运行过程中,如果需要调用另一个对象协助时,无须在代码中创建按被调用者,而是依赖外部注入。   Spring的依赖注入对调用...
  • 模块依赖关系分析-Java实现

    万次阅读 2017-08-18 14:13:31
    一个系统的若干模块间存在相互依赖的关系,如果A模块调用了B模块的接口,那么成为A依赖B,记为A->B 如果A->B,B->A,那么称A和B模块都存在循环依赖。 如果A->B,B->C,C->D,D->B,那么BCD存在循环依赖,A不存在循环...
  • Maven之——依赖与插件管理

    千次阅读 2014-11-08 19:12:39
    摘要: 掌握如何在项目中使用聚合继承、以及如何使用这一特性来管理、优化依赖与插件的使用。
  • RDD的依赖关系彻底解密

    千次阅读 2016-12-01 21:51:37
    RDD依赖关系
  • Java:控制反转(IoC)与依赖注入(DI)

    千次阅读 多人点赞 2019-08-07 13:27:11
    很长一段时间里,我对控制反转和依赖注入这两个概念很模糊,闭上眼睛想一想,总有一种眩晕的感觉。但为了成为一名优秀的 Java 工程师,我花了一周的时间,彻底把它们搞清楚了。 01、紧耦合 在我们编码的过程中,通常...
  • 利用JD-GUI寻找JAR内部依赖

    千次阅读 2019-03-11 11:49:03
    有时候需要搞清楚jar包内部的方法调用...一种思路是能不能把jar包批量反编译成为项目,导入IDE中,这样就能分析依赖了。我们可以用jd-gui工具:http://java-decompiler.github.io/ 但是,jd-gui也有反编译不了的时...
  • 设计模式 : 依赖倒转原则

    千次阅读 2018-03-31 17:52:42
    依赖倒转原则 : A . 高层模块不应该依赖底层模块.两个模块都应该依赖抽象. B . 抽象不应该依赖细节.细节应该依赖抽象. 依赖倒转原则的核心在于,在编程中,应该针对接口编程,而不是针对实现编程. 面向过程的开发时,...
  • ABP官方文档(七)【依赖注入】

    千次阅读 2017-11-01 14:04:40
    2.1 ABP公共结构 - 依赖注入如果你已经了解依赖注入的概念、构造函数和属性注入模式,你可以跳过这一节。维基百科:“依赖注入是一种软件设计模式,指一个或多个依赖(或服务)被注入,或通过引用传递,传入一个依赖...
  • 依赖管理是每个构建的关键特性,并且 Gradle 强调提供最好的依赖管理,容易理解以及使用各种各样的方法来兼容。如果您熟悉使用 Maven 或 Ivy 的方法,那么你会很高兴地知道,Gradle 完全兼容这两种方法,除此之外,...
  • .NET MVC 依赖注入

    千次阅读 2019-03-24 12:01:52
    .NET MVC 依赖注入 当一个组件依赖于其他组件时,我们称其为耦合(coupling)。一个类知道与其交互的类的大量信息,我们称其为高耦合。 在软件设计过程中,高耦合通常认为是软件设计的责任。当一个类精确地知道另一...
  • 数据库之函数依赖

    千次阅读 多人点赞 2018-08-23 14:34:26
    今天又重新拾起了《数据库系统原理》,因为之前对它学的不够扎实,所以现在需要重新进行深入的学习,函数依赖这一部分虽然不是特别难,但是我就是有点“迷”,老是有点弄不清楚,所以今天抽出点时间“收拾”他一下,...
  • maven依赖包版本冲突小尝试

    千次阅读 2015-09-11 17:52:35
    冲突1项目Demo1依赖于Y、Z依赖包,Y依赖于A,Z依赖于A、B、C,故项目Demo1最终依赖于Y、Z、A、B、C。但是Y依赖于A的1.x版本,Z依赖于A的2.x版本,这时候就出现依赖包冲突。
  • laravel 依赖注入原理理解

    千次阅读 2019-10-17 09:21:27
    作为一个进入职场五年的职场菜鸟,讲述如何进阶成为一个职场大神的进阶之路
  • 【学习笔记】Maven依赖特性

    万次阅读 2015-06-24 00:57:33
    scope:依赖的作用域 ... 在大部分情况下不用将某些jar打包加入,因为服务器中已经存在,在运行时也会存在的情况下会造成jar冲突。  test:在测试的范围有效,在编译和打包的时候不会使用这个依赖。  runtime:在
  • Silverlight的依赖属性

    千次阅读 2012-08-04 15:23:41
    自定义依赖项对象和依赖项属性 本主题描述了 Silverlight 的应用程序开发人员和组件的作者可能想要创建自定义依赖项属性的原因。本主题描述为依赖项属性,以及一些可以提高性能、可用性、或属性的多功能性的...
  • 入门系列-依赖注入

    千次阅读 2019-12-05 17:35:22
    依赖注入 ABP的依赖注入系统是基于Microsoft的依赖注入扩展库(Microsoft.Extensions.DependencyInjection nuget包)开发的.因此,它的文档在ABP中也是有效的. 模块化 由于ABP是一个模块化框架,因此每个模块都定义...
  • Maven教程3(依赖管理)

    千次阅读 2019-01-17 23:53:30
    Maven项目,依赖,构建配置,以及构件:所有这些都是要建模和表述的对象。这些对 象通过一个名为项目对象模型(Project Object Model, POM)的XML文件描述。这个POM 告诉Maven它正处理什么类型的项目,如何修改默认...
  • 前面我们了解了依赖注入的基本概念,也对一些依赖注入框架进行了简单的介绍,这一章我们主要来讨论作为开发者如何利用依赖注入框架来实现依赖注入的设计思想。   1. 依赖注入的方式 前面我们提到,所谓“依赖”...
  • 在学习面向对象设计时,类关系涉及依赖、关联、聚合、组合和泛化这五种关系,耦合性依次递增。关于耦合度,可以简单地理解为当一个类发生变更时,对其他类造成的影响程度,影响越小则耦合度越弱,影响越大耦合度越强...
  • 以前写过一篇关于go管理依赖包工具 dep的文章,当时认为dep将会成为官方依赖工具,现在看来是自己图样图斯内幕破了,正如官方一直提到dep是“official experiment”官方实验项目的那样,随着go modules 在go1.11版...
  • Angular2 之 依赖注入

    千次阅读 2016-12-29 10:25:07
    依赖注入这部分分为两部分来学习。第一部分自然是官网上的文档,另外一部分,是自己的“血泪时间史”。 之所以称之为“血泪时间史”,是因为在这部分上花费的时间实在是有点多,也就是前面提到过的“时间的教训”...
  • 使用Kotlin Tools 快速添加Kotlin依赖

    千次阅读 2017-05-23 15:56:43
    快速增加kotlin依赖到Android、Java、Js 项目
  • 在前几篇文章中,我们已经分析和讨论了有关angular依赖注入的几个方面: angular如何处理模块的声明和获取 angular注入器的概念和它是如何加载模块以及执行模块定义的任务 angular注入器如何管理被托管的对象 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 556,122
精华内容 222,448
关键字:

已经成为了依赖