{"id":13413444,"url":"https://github.com/goioc/di","last_synced_at":"2026-01-17T12:08:17.220Z","repository":{"id":38319972,"uuid":"271540448","full_name":"goioc/di","owner":"goioc","description":"Simple and yet powerful Dependency Injection for Go","archived":false,"fork":false,"pushed_at":"2024-03-21T19:20:42.000Z","size":173,"stargazers_count":351,"open_issues_count":2,"forks_count":15,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-07-31T20:52:21.483Z","etag":null,"topics":["dependency-injection","go","golang","golang-library","inversion-of-control"],"latest_commit_sha":null,"homepage":"https://pkg.go.dev/github.com/goioc/di/?tab=doc","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/goioc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"ko_fi":"dtitov"}},"created_at":"2020-06-11T12:28:06.000Z","updated_at":"2024-07-26T16:46:19.000Z","dependencies_parsed_at":"2024-01-28T13:22:47.751Z","dependency_job_id":"530e80a3-8e94-47ff-8ebf-f3b50fc53a3d","html_url":"https://github.com/goioc/di","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/goioc/di","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goioc%2Fdi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goioc%2Fdi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goioc%2Fdi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goioc%2Fdi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/goioc","download_url":"https://codeload.github.com/goioc/di/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goioc%2Fdi/sbom","scorecard":{"id":434103,"data":{"date":"2025-08-11","repo":{"name":"github.com/goioc/di","commit":"0ccac80090b0b6ad83cbb50ace4b80caa6212346"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.4,"checks":[{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":0,"reason":"Found 0/15 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Pinned-Dependencies","score":2,"reason":"dependency not pinned by hash detected -- score normalized to 2","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql.yml:27: update your workflow using https://app.stepsecurity.io/secureworkflow/goioc/di/codeql.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql.yml:30: update your workflow using https://app.stepsecurity.io/secureworkflow/goioc/di/codeql.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql.yml:36: update your workflow using https://app.stepsecurity.io/secureworkflow/goioc/di/codeql.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql.yml:39: update your workflow using https://app.stepsecurity.io/secureworkflow/goioc/di/codeql.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/dependency-review.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/goioc/di/dependency-review.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/dependency-review.yml:20: update your workflow using https://app.stepsecurity.io/secureworkflow/goioc/di/dependency-review.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/go.yml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/goioc/di/go.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/go.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/goioc/di/go.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/go.yml:27: update your workflow using https://app.stepsecurity.io/secureworkflow/goioc/di/go.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/greetings.yml:12: update your workflow using https://app.stepsecurity.io/secureworkflow/goioc/di/greetings.yml/master?enable=pin","Info:   0 out of   9 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned","Info:   1 out of   1 goCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Info: jobLevel 'actions' permission set to 'read': .github/workflows/codeql.yml:16","Info: jobLevel 'contents' permission set to 'read': .github/workflows/codeql.yml:17","Warn: no topLevel permission defined: .github/workflows/codeql.yml:1","Info: topLevel 'contents' permission set to 'read': .github/workflows/dependency-review.yml:11","Warn: no topLevel permission defined: .github/workflows/go.yml:1","Warn: no topLevel permission defined: .github/workflows/greetings.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":7,"reason":"SAST tool detected but not run on all commits","details":["Info: SAST configuration detected: CodeQL","Warn: 1 commits out of 15 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-19T04:10:09.539Z","repository_id":38319972,"created_at":"2025-08-19T04:10:09.539Z","updated_at":"2025-08-19T04:10:09.539Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28508464,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-17T11:50:55.898Z","status":"ssl_error","status_checked_at":"2026-01-17T11:50:55.569Z","response_time":85,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dependency-injection","go","golang","golang-library","inversion-of-control"],"created_at":"2024-07-30T20:01:40.539Z","updated_at":"2026-01-17T12:08:17.183Z","avatar_url":"https://github.com/goioc.png","language":"Go","funding_links":["https://ko-fi.com/dtitov","https://ko-fi.com/G2G5JUKU7"],"categories":["Go","其他杂项","HarmonyOS","杂项","Miscellaneous","Microsoft Office","Dependency Injection"],"sub_categories":["依赖性注入","Windows Manager","依赖注入","Dependency Injection"],"readme":"# goioc/di: Dependency Injection\n[![goioc](https://habrastorage.org/webt/ym/pu/dc/ympudccm7j7a3qex_jjroxgsiwg.png)](https://github.com/goioc)\n\n[![Go](https://github.com/goioc/di/workflows/Go/badge.svg)](https://github.com/goioc/di/actions)\n[![go.dev reference](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go\u0026logoColor=white\u0026style=flat-square)](https://pkg.go.dev/github.com/goioc/di/?tab=doc)\n[![CodeFactor](https://www.codefactor.io/repository/github/goioc/di/badge)](https://www.codefactor.io/repository/github/goioc/di)\n[![Go Report Card](https://goreportcard.com/badge/github.com/goioc/di)](https://goreportcard.com/report/github.com/goioc/di)\n[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=goioc_di\u0026metric=alert_status)](https://sonarcloud.io/dashboard?id=goioc_di)\n[![codecov](https://codecov.io/gh/goioc/di/branch/master/graph/badge.svg)](https://codecov.io/gh/goioc/di)\n[![DeepSource](https://static.deepsource.io/deepsource-badge-light-mini.svg)](https://deepsource.io/gh/goioc/di/?ref=repository-badge)\n[![Awesome](https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg)](https://github.com/sindresorhus/awesome)\n\n[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/G2G5JUKU7)\n\n## Why DI in Go? Why IoC at all?\nI've been using Dependency Injection in Java for nearly 10 years via [Spring Framework](https://spring.io/). I'm not saying that one can't live without it, but it's proven to be very useful for large enterprise-level applications. You may argue that Go follows a completely different ideology, values different principles and paradigms than Java, and DI is not needed in this better world. And I can even partly agree with that. And yet I decided to create this light-weight Spring-like library for Go. You are free to not use it, after all 🙂\n\n## Is it the only DI library for Go?\nNo, of course not. There's a bunch of libraries around which serve a similar purpose (I even took inspiration from some of them). The problem is that I was missing something in all of these libraries... Therefore I decided to create Yet Another IoC Container that would rule them all. You are more than welcome to use any other library, for example [this nice project](https://github.com/sarulabs/di). And still, I'd recommend stopping by here 😉\n\n## So, how does it work? \nIt's better to show than to describe. Take a look at this toy-example (error-handling is omitted to minimize code snippets):\n\n**services/weather_service.go**\n```go\npackage services\n\nimport (\n\t\"io\"\n\t\"net/http\"\n)\n\ntype WeatherService struct {\n}\n\nfunc (ws *WeatherService) Weather(city string) (*string, error) {\n\tresponse, err := http.Get(\"https://wttr.in/\" + city)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tall, err := io.ReadAll(response.Body)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tweather := string(all)\n\treturn \u0026weather, nil\n}\n```\n\n**controllers/weather_controller.go**\n```go\npackage controllers\n\nimport (\n\t\"di-demo/services\"\n\t\"github.com/goioc/di\"\n\t\"net/http\"\n)\n\ntype WeatherController struct {\n\t// note that injection works even with unexported fields\n\tweatherService *services.WeatherService `di.inject:\"weatherService\"`\n}\n\nfunc (wc *WeatherController) Weather(w http.ResponseWriter, r *http.Request) {\n\tweather, _ := wc.weatherService.Weather(r.URL.Query().Get(\"city\"))\n\t_, _ = w.Write([]byte(*weather))\n}\n```\n\n**init.go**\n```go\npackage main\n\nimport (\n\t\"di-demo/controllers\"\n\t\"di-demo/services\"\n\t\"github.com/goioc/di\"\n\t\"reflect\"\n)\n\nfunc init() {\n\t_, _ = di.RegisterBean(\"weatherService\", reflect.TypeOf((*services.WeatherService)(nil)))\n\t_, _ = di.RegisterBean(\"weatherController\", reflect.TypeOf((*controllers.WeatherController)(nil)))\n\t_ = di.InitializeContainer()\n}\n```\n\n**main.go**\n```go\npackage main\n\nimport (\n\t\"di-demo/controllers\"\n\t\"github.com/goioc/di\"\n\t\"net/http\"\n)\n\nfunc main() {\n\thttp.HandleFunc(\"/weather\", func(w http.ResponseWriter, r *http.Request) {\n\t\tdi.GetInstance(\"weatherController\").(*controllers.WeatherController).Weather(w, r)\n\t})\n\t_ = http.ListenAndServe(\":8080\", nil)\n}\n```\n\nIf you run it, you should be able to observe a neat weather forecast at http://localhost:8080/weather?city=London (or for any other city).\n\nOf course, for such a simple example it may look like an overkill. But for larger projects with many interconnected services with complicated business logic, it can really simplify your life!\n\n## Looks nice... Give me some details!\n\nThe main component of the library is the [Inversion of Control Container](https://www.martinfowler.com/articles/injection.html) that contains and manages instances of your structures (called \"beans\").\n\n### Types of beans\n\n- **Singleton**. Exists only in one copy in the container. Every time you retrieve the instance from the container (or every time it's being injected to another bean) - it will be the same instance.\n- **Prototype**. It can exist in multiple copies: a new copy is created upon retrieval from the container (or upon injection into another bean).\n- **Request**. Similar to `Prototype`, however it has a few differences and features (since its lifecycle is bound to a web request):\n   - Can't be injected to other beans.\n   - Can't be manually retrieved from the Container.\n   - `Request` beans are automatically injected to the `context.Context` of a corresponding `http.Request`. \n   - If a `Request` bean implements `io.Closer`, it will be \"closed\" upon corresponding request's cancellation.\n\n### Beans registration\n\nFor the container to become aware of the beans, one must register them manually (unlike Java, unfortunately, we can't scan classpath to do it automatically, because Go runtime doesn't contain high-level information about types). How can one register beans in the container?\n\n- **By type**. This is described in the example above. A structure is declared with a field tagged with `di.scope:\"\u003cscope\u003e\"`. This field can be even omitted - in this case, the default scope will be `Singleton`. Then the registration is done like this:\n```go\ndi.RegisterBean(\"beanID\", reflect.TypeOf((*YourAwesomeStructure)(nil)))\n```\n\n- **Using pre-created instance**. What if you already have an instance that you want to register as a bean? You can do it like this:\n```go\ndi.RegisterBeanInstance(\"beanID\", yourAwesomeInstance)\n```\nFor this type of beans, the only supported scope is `Singleton`, because I don't dare to clone your instances to enable prototyping 😅\n\n- **Via bean factory**. If you have a method that is producing instances for you, you can register it as a bean factory:\n```go\ndi.RegisterBeanFactory(\"beanID\", Singleton, func(context.Context) (interface{}, error) {\n\t\treturn \"My awesome string that is going to become a bean!\", nil\n\t})\n```\nFeel free to use any scope with this method. By the way, you can even lookup other beans within the factory:\n```go\ndi.RegisterBeanFactory(\"beanID\", Prototype, func(context.Context) (interface{}, error) {\n\t\treturn di.GetInstance(\"someOtherBeanID\"), nil\n\t})\n```\nNote that factory-method accepts `context.Context`. It can be useful for request-scoped beans (the HTTP request context is set in this case). For all other beans it will be `context.Background()`.\n\n### Beans initialization\n\nThere's a special interface `InitializingBean` that can be implemented to provide your bean with some initialization logic that will be executed after the container is initialized (for `Singleton` beans) or after the `Prototype`/`Request` instance is created. Again, you can also lookup other beans during initialization (since the container is ready by that time):\n\n```go\ntype PostConstructBean1 struct {\n\tValue string\n}\n\nfunc (pcb *PostConstructBean1) PostConstruct() error {\n\tpcb.Value = \"some content\"\n\treturn nil\n}\n\ntype PostConstructBean2 struct {\n\tScope              Scope `di.scope:\"prototype\"`\n\tPostConstructBean1 *PostConstructBean1\n}\n\nfunc (pcb *PostConstructBean2) PostConstruct() error {\n\tinstance, err := di.GetInstanceSafe(\"postConstructBean1\")\n\tif err != nil {\n\t\treturn err\n\t}\n\tpcb.PostConstructBean1 = instance.(*PostConstructBean1)\n\treturn nil\n}\n```\n\n### Beans post-processors\n\nThe alternative way of initializing beans is using so-called \"beans post-processors\". Take a look at the example:\n\n```go\ntype postprocessedBean struct {\n\ta string\n\tb string\n}\n\n_, _ := RegisterBean(\"postprocessedBean\", reflect.TypeOf((*postprocessedBean)(nil)))\n\n_ = RegisterBeanPostprocessor(reflect.TypeOf((*postprocessedBean)(nil)), func(instance interface{}) error {\n    instance.(*postprocessedBean).a = \"Hello, \"\n    return nil\n})\n\n_ = RegisterBeanPostprocessor(reflect.TypeOf((*postprocessedBean)(nil)), func(instance interface{}) error {\ninstance.(*postprocessedBean).b = \"world!\"\n    return nil\n})\n\n_ = InitializeContainer()\n\ninstance := GetInstance(\"postprocessedBean\")\n\npostprocessedBean := instance.(*postprocessedBean)\nprintln(postprocessedBean.a+postprocessedBean.b) // prints out \"Hello, world!\"\n```\n\n### Beans injection\n\nAs was mentioned above, one bean can be injected into another with the `PostConstruct` method. However, the more handy way of doing it is by using a special tag:\n\n```go\ntype SingletonBean struct {\n\tSomeOtherBean *SomeOtherBean `di.inject:\"someOtherBean\"`\n}\n```\n\n... or via interface ...\n\n```go\ntype SingletonBean struct {\n\tSomeOtherBean SomeOtherBeansInterface `di.inject:\"someOtherBean\"`\n}\n```\n\nNote that you can refer dependencies either by pointer, or by interface, but not by value. And just a reminder: you can't inject `Request` beans.\n\nSometimes we might want to have optional dependencies. By default, all declared dependencies are considered to be required: if some dependency is not found in the Container, you will get an error. However, you can specify an optional dependency like this:\n\n```go\ntype SingletonBean struct {\n\tSomeOtherBean *string `di.inject:\"someOtherBean\" di.optional:\"true\"`\n}\n```\n\nIn this case, if `someOtherBean` is not found in the Container, you will get `nil` injected into this field.\n\nIn fact, you don't need a bean ID to preform an injection! Check this out:\n\n```go\ntype SingletonBean struct {\n\tSomeOtherBean *string `di.inject:\"\"`\n}\n```\n\nIn this case, DI will try to find a candidate for the injection automatically (among registered beans of type `*string`). Cool, ain't it? 🤠\nIt will panic though if no candidates are found (and if the dependency is not marked as optional), or if there is more than one candidate found. \n\nFinally, you can inject beans to slices and maps. It works similarly to the ID-less inections above, but injects all candidates that were found:\n\n```go\ntype SingletonBean struct {\n\tsomeOtherBeans []*string `di.inject:\"\"`\n}\n```\n\n```go\ntype SingletonBean struct {\n\tsomeOtherBeans map[string]*string `di.inject:\"\"`\n}\n```\n\n### Circular dependencies\n\nThe problem with all IoC containers is that beans' interconnection may suffer from so-called circular dependencies. Consider this example:\n\n```go\ntype CircularBean struct {\n\tScope        Scope         `di.scope:\"prototype\"`\n\tCircularBean *CircularBean `di.inject:\"circularBean\"`\n}\n```\n\nTrying to use such bean will result in the `circular dependency detected for bean: circularBean` error. There's no problem as such with referencing a bean from itself - if it's a `Singleton` bean. But doing it with `Prototype`/`Request` beans will lead to infinite creation of the instances. So, be careful with this: \"with great power comes great responsibility\" 🕸 \n\n## What about middleware?\n\nWe have some 😎 Here's an example with [gorilla/mux](https://github.com/gorilla/mux) router (but feel free to use any other router). \nBasically, it's an extension of the very first example with the weather controller, but this time we add `Request` beans and access them via request's context. \nAlso, this example demonstrates how DI can automatically close resources for you (DB connection in this case). The proper error handling is, again, omitted for simplicity.\n\n**controllers/weather_controller.go**\n```go\npackage controllers\n\nimport (\n\t\"database/sql\"\n\t\"di-demo/services\"\n\t\"github.com/goioc/di\"\n\t\"net/http\"\n)\n\ntype WeatherController struct {\n\t// note that injection works even with unexported fields\n\tweatherService *services.WeatherService `di.inject:\"weatherService\"`\n}\n\nfunc (wc *WeatherController) Weather(w http.ResponseWriter, r *http.Request) {\n\tdbConnection := r.Context().Value(di.BeanKey(\"dbConnection\")).(*sql.Conn)\n\tcity := r.URL.Query().Get(\"city\")\n\t_, _ = dbConnection.ExecContext(r.Context(), \"insert into log values (?, ?, datetime('now'))\", city, r.RemoteAddr)\n\tweather, _ := wc.weatherService.Weather(city)\n\t_, _ = w.Write([]byte(*weather))\n}\n```\n\n**controllers/index_controller.go**\n```go\npackage controllers\n\nimport (\n\t\"database/sql\"\n\t\"fmt\"\n\t\"github.com/goioc/di\"\n\t\"net/http\"\n\t\"strings\"\n\t\"time\"\n)\n\ntype IndexController struct {\n}\n\nfunc (ic *IndexController) Log(w http.ResponseWriter, r *http.Request) {\n\tdbConnection := r.Context().Value(di.BeanKey(\"dbConnection\")).(*sql.Conn)\n\trows, _ := dbConnection.QueryContext(r.Context(), \"select * from log\")\n\tcolumns, _ := rows.Columns()\n\t_, _ = w.Write([]byte(strings.ToUpper(fmt.Sprintf(\"Requests log: %v\\n\\n\", columns))))\n\tfor rows.Next() {\n\t\tvar city string\n\t\tvar ip string\n\t\tvar dateTime time.Time\n\t\t_ = rows.Scan(\u0026city, \u0026ip, \u0026dateTime)\n\t\t_, _ = w.Write([]byte(fmt.Sprintln(city, \"\\t\", ip, \"\\t\", dateTime)))\n\t}\n}\n```\n\n**init.go**\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"di-demo/controllers\"\n\t\"di-demo/services\"\n\t\"github.com/goioc/di\"\n\t\"os\"\n\t\"reflect\"\n)\n\nfunc init() {\n\t_, _ = di.RegisterBean(\"weatherService\", reflect.TypeOf((*services.WeatherService)(nil)))\n\t_, _ = di.RegisterBean(\"indexController\", reflect.TypeOf((*controllers.IndexController)(nil)))\n\t_, _ = di.RegisterBean(\"weatherController\", reflect.TypeOf((*controllers.WeatherController)(nil)))\n\t_, _ = di.RegisterBeanFactory(\"db\", di.Singleton, func(context.Context) (interface{}, error) {\n\t\t_ = os.Remove(\"./di-demo.db\")\n\t\tdb, _ := sql.Open(\"sqlite3\", \"./di-demo.db\")\n\t\tdb.SetMaxOpenConns(1)\n\t\t_, _ = db.Exec(\"create table log ('city' varchar not null, 'ip' varchar not null, 'time' datetime not null)\")\n\t\treturn db, nil\n\t})\n\t_, _ = di.RegisterBeanFactory(\"dbConnection\", di.Request, func(ctx context.Context) (interface{}, error) {\n\t\tdb, _ := di.GetInstanceSafe(\"db\")\n\t\treturn db.(*sql.DB).Conn(ctx)\n\t})\n\t_ = di.InitializeContainer()\n}\n```\n\n**main.go**\n```go\npackage main\n\nimport (\n\t\"di-demo/controllers\"\n\t\"github.com/goioc/di\"\n\t\"github.com/gorilla/mux\"\n\t_ \"github.com/mattn/go-sqlite3\"\n\t\"net/http\"\n)\n\nfunc main() {\n\trouter := mux.NewRouter()\n\trouter.Use(di.Middleware)\n\trouter.Path(\"/\").HandlerFunc(di.GetInstance(\"indexController\").(*controllers.IndexController).Log)\n\trouter.Path(\"/weather\").Queries(\"city\", \"{*?}\").HandlerFunc(di.GetInstance(\"weatherController\").(*controllers.WeatherController).Weather)\n\t_ = http.ListenAndServe(\":8080\", router)\n}\n```\n\n## Okaaay... More examples?\n\nPlease, take a look at the [unit-tests](https://github.com/goioc/di/blob/master/di_test.go) for more examples.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgoioc%2Fdi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgoioc%2Fdi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgoioc%2Fdi/lists"}