option.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. package di
  2. import (
  3. "fmt"
  4. "strings"
  5. "kpt-grpc-demo/util/di/xreflect"
  6. "go.uber.org/dig"
  7. )
  8. // Option configures a Hub. It's included for future functionality;
  9. // currently, there are no concrete implementations.
  10. type Option = dig.Option
  11. // A ProvideOption modifies the default behavior of Provide.
  12. type ProvideOption = dig.ProvideOption
  13. // An InvokeOption modifies the default behavior of Invoke. It's included for
  14. // future functionality; currently, there are no concrete implementations.
  15. type InvokeOption = dig.InvokeOption
  16. // HubOption is an option configures an Hub using the functional options paradigm
  17. // popularized by Rob Pike. If you're unfamiliar with this style, see
  18. // https://commandcenter.blogspot.com/2014/01/self-referential-functions-and-design.html.
  19. type HubOption interface {
  20. fmt.Stringer
  21. Apply(hub *Hub)
  22. }
  23. // Options converts a collection of Options into a single Option. This allows
  24. // packages to bundle sophisticated functionality into easy-to-use Fx modules.
  25. // For example, a logging package might export a simple option like this:
  26. //
  27. // package logging
  28. //
  29. // var Module = fx.Provide(func() *log.Logger {
  30. // return log.New(os.Stdout, "", 0)
  31. // })
  32. //
  33. // A shared all-in-one microservice package could then use Options to bundle
  34. // logging with similar metrics, tracing, and gRPC modules:
  35. //
  36. // package server
  37. //
  38. // var Module = fx.Options(
  39. // logging.Module,
  40. // metrics.Module,
  41. // tracing.Module,
  42. // grpc.Module,
  43. // )
  44. //
  45. // Since this all-in-one module1 has a minimal API surface, it's easy to add
  46. // new functionality to it without breaking existing users. Individual
  47. // applications can take advantage of all this functionality with only one
  48. // line of code:
  49. //
  50. // app := di.New(server.Module)
  51. //
  52. // Use this pattern sparingly, since it limits the user's ability to customize
  53. // their application.
  54. func Options(opts ...HubOption) HubOption {
  55. return optionGroup(opts)
  56. }
  57. type optionGroup []HubOption
  58. func (og optionGroup) Apply(hub *Hub) {
  59. for _, opt := range og {
  60. opt.Apply(hub)
  61. }
  62. }
  63. func (og optionGroup) String() string {
  64. items := make([]string, len(og))
  65. for i, opt := range og {
  66. items[i] = fmt.Sprint(opt)
  67. }
  68. return fmt.Sprintf("di.Options(%s)", strings.Join(items, ", "))
  69. }
  70. // Annotation define annotated and apply to Provided
  71. // Annotation provides instantiated values for dependency injection as if
  72. // they had been provided using a constructor that simply returns them.
  73. // The most specific type of each value (as determined by reflection) is used.
  74. //
  75. // type K0 struct {
  76. // Closed bool
  77. // }
  78. //
  79. // func (k *K0) Close() {
  80. // k.Closed = true
  81. // }
  82. //
  83. // k0 := &K0{}
  84. // var module = Annotation(func(ann *Annotated) {
  85. // ann.Target = func() *K0 { return k0 }
  86. // ann.Close = k0.Close
  87. // })
  88. //
  89. // hub, err := di.New(module)
  90. func Annotation(f func(ann *Annotated)) HubOption {
  91. annotation := &Annotated{}
  92. f(annotation)
  93. return provideOption{
  94. Targets: []interface{}{*annotation},
  95. Stack: xreflect.CallerStack(1, 0),
  96. }
  97. }
  98. // Provide registers any number of constructor functions, teaching the
  99. // application how to instantiate various types. The supplied constructor
  100. // function(s) may depend on other types available in the application, must
  101. // return one or more objects, and may return an error. For example:
  102. //
  103. // // Constructs type *C, depends on *A and *B.
  104. // func(*A, *B) *C
  105. //
  106. // // Constructs type *C, depends on *A and *B, and indicates failure by
  107. // // returning an error.
  108. // func(*A, *B) (*C, error)
  109. //
  110. // // Constructs types *B and *C, depends on *A, and can fail.
  111. // func(*A) (*B, *C, error)
  112. func Provide(constructors ...interface{}) HubOption {
  113. // check no nil or error
  114. for _, value := range constructors {
  115. switch value.(type) {
  116. case nil:
  117. panic("untyped nil passed to di.Provide")
  118. case error:
  119. panic("error value passed to di.Provide")
  120. }
  121. }
  122. return provideOption{
  123. Targets: constructors,
  124. Stack: xreflect.CallerStack(1, 0),
  125. }
  126. }
  127. type provideOption struct {
  128. Targets []interface{}
  129. Stack xreflect.Stack
  130. }
  131. func (o provideOption) Apply(hub *Hub) {
  132. for _, target := range o.Targets {
  133. hub.provides = append(hub.provides, Provided{
  134. Target: target,
  135. Stack: o.Stack,
  136. })
  137. }
  138. }
  139. func (o provideOption) String() string {
  140. items := make([]string, len(o.Targets))
  141. for i, c := range o.Targets {
  142. items[i] = xreflect.FuncName(c)
  143. }
  144. return fmt.Sprintf("fx.Provide(%s)", strings.Join(items, ", "))
  145. }
  146. // ValidateHub validates that supplied graph would run and is not missing any dependencies.
  147. func ValidateHub(v bool) HubOption {
  148. return validateOption{validate: v}
  149. }
  150. type validateOption struct {
  151. validate bool
  152. }
  153. func (o validateOption) Apply(hub *Hub) {
  154. hub.validate = o.validate
  155. }
  156. func (o validateOption) String() string {
  157. return fmt.Sprintf("fx.validate(%v)", o.validate)
  158. }