{"id":13413452,"url":"https://github.com/logrange/linker","last_synced_at":"2026-01-16T19:13:55.503Z","repository":{"id":57490761,"uuid":"160434102","full_name":"logrange/linker","owner":"logrange","description":"Dependency Injection and Inversion of Control package","archived":false,"fork":false,"pushed_at":"2024-02-21T03:17:07.000Z","size":38,"stargazers_count":35,"open_issues_count":0,"forks_count":6,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-07-31T20:52:22.140Z","etag":null,"topics":["dependency-injection","injector","ioc-framework","lifecycle"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/logrange.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"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}},"created_at":"2018-12-04T23:56:34.000Z","updated_at":"2024-02-21T03:17:11.000Z","dependencies_parsed_at":"2024-06-18T21:27:33.180Z","dependency_job_id":null,"html_url":"https://github.com/logrange/linker","commit_stats":{"total_commits":30,"total_committers":4,"mean_commits":7.5,"dds":"0.23333333333333328","last_synced_commit":"a2d82c14f745dd818986d84ffd764934f980ba06"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/logrange/linker","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/logrange%2Flinker","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/logrange%2Flinker/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/logrange%2Flinker/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/logrange%2Flinker/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/logrange","download_url":"https://codeload.github.com/logrange/linker/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/logrange%2Flinker/sbom","scorecard":{"id":597437,"data":{"date":"2025-08-11","repo":{"name":"github.com/logrange/linker","commit":"5a47cc9a5661d853da623031613fcd4ed6626083"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/30 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":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"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":"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":"Dangerous-Workflow","score":-1,"reason":"no workflows found","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":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"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":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"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: Apache License 2.0: 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":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"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"}}]},"last_synced_at":"2025-08-20T23:30:00.462Z","repository_id":57490761,"created_at":"2025-08-20T23:30:00.462Z","updated_at":"2025-08-20T23:30:00.462Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28481592,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T11:59:17.896Z","status":"ssl_error","status_checked_at":"2026-01-16T11:55:55.838Z","response_time":107,"last_error":"SSL_read: 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","injector","ioc-framework","lifecycle"],"created_at":"2024-07-30T20:01:40.723Z","updated_at":"2026-01-16T19:13:55.468Z","avatar_url":"https://github.com/logrange.png","language":"Go","readme":"# Linker\n\n[![Go Report Card](https://goreportcard.com/badge/github.com/logrange/linker)](https://goreportcard.com/report/github.com/logrange/linker) [![codecov](https://codecov.io/gh/logrange/linker/branch/master/graph/badge.svg)](https://codecov.io/gh/logrange/linker) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/logrange/linker/blob/master/LICENSE) [![GoDoc](https://godoc.org/github.com/logrange/linker?status.png)](https://godoc.org/github.com/logrange/linker)\n[![Mentioned in Awesome Go](https://awesome.re/mentioned-badge-flat.svg)](https://github.com/avelino/awesome-go)\n\nLinker is Dependency Injection and Inversion of Control package. It supports the following features:\n\n- Components registry\n- Automatic dependency injection of the registered components\n- Components lifecycle support via `PostConstructor`, `Initializer` and `Shutdowner` interfaces implementations\n- Post-injection notification\n- Automatic ordering of components initialization \n- Circular dependency detection\n- Components shutdowning\n\nPlease refer to [this blogpost](https://www.logrange.io/blog/linker.html) for some details.\n\nLinker is used by [Logrange](https://github.com/logrange/logrange), please take a look how it is used [there](https://github.com/logrange/logrange/blob/be1cc8dc0ae8fa9154eec91bea33cd2105509e11/server/server.go#L53).\n\n```golang\n\nimport (\n     \"github.com/logrange/linker\"\n)\n\ntype DatabaseAccessService interface {\n    RunQuery(query string) DbResult\n}\n\n// MySQLAccessService implements DatabaseAccessService\ntype MySQLAccessService struct {\n\t// Conns uses field's tag to specify injection param name(mySqlConns)\n\t// or sets-up the default value(32), if the param is not provided \n    Conns int `inject:\"mySqlConns, optional:32\"`\n}\n\ntype BigDataService struct {\n\t// DBa has DatabaseAccessService type which value will be injected by the injector\n\t// in its Init() function, or it fails if there is no appropriate component with the name(dba)\n\t// was registered...\n    DBa DatabaseAccessService `inject:\"dba\"`\n}\n...\n\nfunc main() {\n    // 1st step is to create the injector\n    inj := linker.New()\n\t\n    // 2nd step is to register components\n    inj.Register(\n\t\tlinker.Component{Name: \"dba\", Value: \u0026MySQLAccessService{}},\n\t\tlinker.Component{Name: \"\", Value: \u0026BigDataService{}},\n\t\tlinker.Component{Name: \"mySqlConns\", Value: int(msconns)},\n\t\t...\n\t)\n\t\n\t// 3rd step is to inject dependecies and initialize the registered components\n\tinj.Init(ctx)\n\t\n\t// the injector fails-fast, so if no panic everything is good so far.\n\t\n\t...\n\t// 4th de-initialize all compoments properly\n\tinj.Shutdown()\n}\n\n```\n### Annotate fields using fields tags\nThe `inject` tag field has the following format:\n```\ninject: \"\u003cname\u003e[,optional[:\u003cdefaultValue]]\"\n```\nSo annotated fields can be assigned using different rules:\n```golang\n// Field will be assigned by component with registration name \"compName\",\n// if there is no comonent with the name, or it could not be assigned to the type \n// FieldType, panic will happen\nField FieldType `inject:\"compName\"`\n\n// Field will be assigned by component with any name (indicated as \"\"), which could be \n// assigned to the FieldType. If no such component or many matches to the type, \n// panic will happen.\nField FieldType `inject:\"\"`\n\n// If no components match to either Field1 or Field2 they will be skipped with \n// no panic. Ambigious situation still panics\nField1 FieldType `inject:\"aaa, optional\"`\nField2 FieldType `inject:\", optional\"`\n\n// Default values could be provided for numeric and string types. The \n// default values will be assigned if no components match to the rules\nNumFld int `inject:\"intFld, optional: 21\"`\nStrFld string `inject:\"strFld,optional:abc\"`\n```\n### Create the injector\nInjector is a main object, which  controls the components: registers them, initializes, checks and provides initialization and shutdown calls.\n```golang\ninj := linker.New()\n```\n### Register components using names or anonymously\nComponent is an object that can be used for initialization of other components, or which requires an initialization. Components can have different types, but only fields of components, with 'pointer to struct' type, could be assigned by the Injector. Injector is responsible for the injection(initialization a component's fields) process. All components must be registered in injector via `Register()` function before the initialization process will be run.\n### Initialize components\nWhen all components are registered `Init()` function of the `Injector` allows to perform initialization. The `Init()` function does the following actions:\n1. Walks over all registered components and assigns all tagged fields using named and unnamed components. If no matches or ambiguity happens, the `Init()` can panic.\n2. For components, which implement [linker.PostConstructor](https://github.com/logrange/linker/blob/5dbea0d87b81a70e721f6c359d5f28dc1a01e080/inject.go#L74) interface, the `PostConstruct()` function will be called.\n3. For components, which implements [linker.Initializer](https://github.com/logrange/linker/blob/5dbea0d87b81a70e721f6c359d5f28dc1a01e080/inject.go#L90) interface, the `Init(ctx)` function will be called in a specific order. The initialization order is defined as following: less dependent components are initialized before the components \n4. If circular dependency between registered components is found, Init() will panic.\n### Shutting down registered components properly\nProperly initialized components could be shut-down in back-initialization order by calling `Shutdown()` function of the injector. Components, that implement [linker.Shutdowner](https://github.com/logrange/linker/blob/5dbea0d87b81a70e721f6c359d5f28dc1a01e080/inject.go#L108) interface, will be called by the `Shutdown()`\n","funding_links":[],"categories":["Miscellaneous","其他杂项","杂项","Microsoft Office","Dependency Injection"],"sub_categories":["Dependency Injection","依赖性注入","依赖注入"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flogrange%2Flinker","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flogrange%2Flinker","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flogrange%2Flinker/lists"}