Skip to content

Commit ba531ff

Browse files
committed
Implementing AutoCloser when program shutdown
Signed-off-by: Filip Petrov Signed-off-by: Filip Petrov <lombert.p.v@gmail.com>
1 parent a17b2e2 commit ba531ff

File tree

13 files changed

+142
-69
lines changed

13 files changed

+142
-69
lines changed

.golangci.yml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
linters:
2+
disable-all: true
3+
enable:
4+
- bodyclose
5+
- deadcode
6+
- depguard
7+
- dogsled
8+
- dupl
9+
- errcheck
10+
- funlen
11+
- goconst
12+
- gocritic
13+
- gocyclo
14+
- gofmt
15+
- goimports
16+
- golint
17+
- gomnd
18+
- goprintffuncname
19+
- gosec
20+
- gosimple
21+
- govet
22+
- ineffassign
23+
- interfacer
24+
- lll
25+
- misspell
26+
- nakedret
27+
- noctx
28+
- nolintlint
29+
- rowserrcheck
30+
- scopelint
31+
- staticcheck
32+
- structcheck
33+
- stylecheck
34+
- typecheck
35+
- unconvert
36+
- unparam
37+
- unused
38+
- varcheck
39+
- whitespace
40+
- maligned
41+
- prealloc
42+
43+
linters-settings:
44+
govet:
45+
check-shadowing: true
46+
47+
issues:
48+
exclude-use-default: false

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2021 go-autowire
3+
Copyright (c) 2021 go-autowire (Filip Petrov)
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

atesting/testing.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1+
// atesting package provides Spy function for easy way to mock dependencies
12
package atesting
23

34
import (
45
"container/list"
5-
"github.com/go-autowire/autowire"
66
"log"
77
"reflect"
88
"unicode"
9+
10+
"github.com/go-autowire/autowire"
911
)
1012

1113
// Spy Function is replacing object field with the one provided in the function as a second argument.
@@ -17,17 +19,19 @@ import (
1719
// atesting.Spy(application, &TestAuditClient{})
1820
// Or this is equivalent of
1921
// application.UserSvc().SetAuditClient(&TestAuditClient{})
20-
// Getter UserSvc() is used to access userSvc field, which is unexported. For more information take a look at example package.
21-
//Parameters of Spy function:
22+
// Getter UserSvc() is used to access userSvc field, which is unexported.
23+
// For more information take a look at example package.
24+
// Parameters of Spy function:
2225
// - `v` : pointer to structure inside which spy object will be applied
2326
// - `dependency` : pointer to structure which will be injected
2427
func Spy(v interface{}, dependency interface{}) {
2528
slice := []interface{}{dependency}
2629
Spies(v, slice)
2730
}
2831

29-
// Spies Function is replacing object fields with the list of provided dependencies in the function as a second argument.
30-
// Spy Function detects automatically which field could be replaced with the provided one in the list of dependencies.
32+
// Spies Function is replacing object fields with the list of provided dependencies
33+
// in the function as a second argument. Spy Function detects automatically which field
34+
// could be replaced with the provided one in the list of dependencies.
3135
// Important note: In order to traverse fields of the unexported fields we need to implement Getters.
3236
// As shown inside example package, we are replacing AuditClient with our mock implementation and in order to reach this
3337
// field we need Getter.
@@ -36,7 +40,8 @@ func Spy(v interface{}, dependency interface{}) {
3640
// Or this is equivalent of
3741
// application.UserSvc().SetAuditClient(&TestAuditClient{})
3842
// application.UserSvc().PaymentSvc = &TestPaymentServiceTest{}
39-
// Getter UserSvc() is used to access userSvc field, which is unexported. In case of PaymentSvc it is not required as field PaymentSvc is exported.
43+
// Getter UserSvc() is used to access userSvc field, which is unexported. In case of PaymentSvc it is not required
44+
// as field PaymentSvc is exported.
4045
// Parameters of Spies function:
4146
// - `v` : structure inside which spy objects will be applied
4247
// - `dependencies` : list of dependencies which will be injected

autowire.go

Lines changed: 47 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ package autowire
33
import (
44
"io"
55
"log"
6-
"os"
7-
"os/signal"
86
"reflect"
97
"regexp"
108
"strings"
@@ -13,15 +11,13 @@ import (
1311

1412
var dependencies map[string]interface{}
1513
var currentProfile = getProfile()
16-
var ch = make(chan os.Signal)
1714

1815
// Tag name
1916
const Tag = "autowire"
2017

2118
func init() {
2219
log.SetFlags(log.LstdFlags | log.Lshortfile)
2320
log.Println("Init Autowire Context")
24-
signal.Notify(ch, os.Interrupt, os.Kill)
2521
dependencies = make(map[string]interface{})
2622
}
2723

@@ -34,49 +30,60 @@ func InitProd(initFunc func()) {
3430
}
3531

3632
// Autowire function injects all dependencies for the given structure v.
37-
// In order dependencies to be injected the desired struct fields should be marked with
38-
// autowire tag.
33+
// Autowire function should be executed in the init() function of the
34+
// package. In order dependencies to be injected the desired struct fields
35+
// should be marked with autowire tag.
3936
//
4037
// Concrete type Injection
4138
//
4239
// Currently both type of fields exported and unexported are supported.
4340
//
4441
// Unexported field
4542
//
46-
// Following snippet shows injecting dependencies inside private structure fields using `autowire:""` tag:
43+
// Following snippet shows injecting dependencies inside private structure
44+
// fields using `autowire:""` tag:
4745
// type Application struct {
4846
// config *configuration.ApplicationConfig `autowire:""`
4947
// }
5048
// func (a *Application) SetConfig(config *configuration.ApplicationConfig) {
5149
// a.config = config
5250
// }
53-
// If we need given dependency to be injected into unexported field Setter function(Set<FieldName>) is required, as show above.
54-
// If you have a field called config (lower case, unexported), the setter method should be called SetConfig (upper case, exported), not Setconfig.
51+
// If we need given dependency to be injected into unexported field Setter
52+
// function(Set<FieldName>) is required, as show above. If you have a field
53+
// called config (lower case, unexported), the setter method should be called
54+
// SetConfig, not Setconfig.
5555
//
5656
// Exported field
5757
//
58-
// The use of upper-case names of the struct fields indicated field is exported.
58+
// The use of upper-case names of the struct fields indicated that field is exported.
5959
// type Application struct {
6060
// Config *configuration.ApplicationConfig `autowire:""`
6161
// }
62-
// Dependency injection of exported field is supported with the difference that we don`t provide additional Setter function.
62+
// Dependency injection of exported field is supported with the difference that we don't
63+
// provide additional Setter function.
6364
//
6465
// Interface Injection
6566
//
66-
// Often it`s better to rely on interface instead of concrete type, in order to accomplish this decoupling we specify
67-
// interfaces as a type of struct fields. The following snippet demonstrate that
67+
// Often it's better to rely on interface instead of concrete type, in order to
68+
// accomplish this decoupling we should specify interfaces as a type of struct
69+
// fields. The following snippet demonstrate that:
6870
// type UserService struct {
6971
// userRoleRepository UserRoleRepository `autowire:"repository/InMemoryUserRoleRepository"`
7072
// }
7173
// func (u *UserService) SetUserRoleRepository(userRoleRepository UserRoleRepository) {
7274
// u.userRoleRepository = userRoleRepository
7375
// }
74-
// UserRoleRepository is simply an interface and InMemoryUserRoleRepository is a struct, which implements this interface.
75-
// As it`s done dependency injection on unexported field, providing Setter is required. Just to highlight unexported fields
76-
// needs Setter while exported not. For more information take a look at example#https://github.com/go-autowire/autowire/tree/main/example package.
77-
// Example:
78-
//
79-
//
76+
// UserRoleRepository is simply an interface and InMemoryUserRoleRepository is a
77+
// struct, which implements that interface. As dependency injection is executed
78+
// on unexported field, providing Setter is required. Just to highlight unexported
79+
// fields needs Setter while exported not. For more information take a look at
80+
// example https://github.com/go-autowire/autowire/tree/main/example package.
81+
// Very Simplified Example:
82+
// type App struct {}
83+
// func init() {
84+
// autowire.Autowire(&App{})
85+
// }
86+
// As mentioned above Autowire function should be invoked in the package init function.
8087
func Autowire(v interface{}) {
8188
value := reflect.ValueOf(v)
8289
switch value.Kind() {
@@ -95,12 +102,12 @@ func Autowire(v interface{}) {
95102
default: // reflect.Array, reflect.Struct, reflect.Interface
96103
log.Println(value.Type().String() + " value")
97104
}
98-
//log.Println(dependencies)
105+
// log.Println(dependencies)
99106
}
100107

101108
// Autowired function returns fully initialized with all dependencies instance, which is ready to be used.
102-
//As the result is empty interface, type assertions is required before using the instance.
103-
//Take a look at https://golang.org/ref/spec#Type_assertions for more information.
109+
// As the result is empty interface, type assertions is required before using the instance.
110+
// Take a look at https://golang.org/ref/spec#Type_assertions for more information.
104111
// The following snippet demonstrate how could be done :
105112
// app := autowire.Autowired(app.Application{}).(*app.Application)
106113
func Autowired(v interface{}) interface{} {
@@ -121,6 +128,24 @@ func Autowired(v interface{}) interface{} {
121128
return nil
122129
}
123130

131+
// Close function invoke Close method on each autowired struct
132+
// which implements io.Closer interface, so currently active
133+
// occupied resources (connections, channels, descriptor, etc.)
134+
// could be released.
135+
func Close() {
136+
log.Println("Closing...")
137+
for _, dependency := range dependencies {
138+
valueDepend := reflect.ValueOf(dependency)
139+
closerType := reflect.TypeOf((*io.Closer)(nil)).Elem()
140+
if valueDepend.Type().Implements(closerType) {
141+
err := dependency.(io.Closer).Close()
142+
if err != nil {
143+
log.Println(err.Error())
144+
}
145+
}
146+
}
147+
}
148+
124149
func getStructPtrFullPath(value reflect.Value) string {
125150
return getFullPath(value.Elem().Type().PkgPath(), value.Type().String())
126151
}
@@ -191,25 +216,3 @@ func findDependency(tagDependencyType string) []interface{} {
191216
}
192217
return result
193218
}
194-
195-
// Run executes function function after the function execution completes for each autowired struct
196-
// which implements io.Closer interface will be invoked Call() function, so currently active
197-
//occupied resources(connections, channels, etc.) could be released.
198-
func Run(function func()) {
199-
defer closeAll()
200-
function()
201-
}
202-
203-
func closeAll() {
204-
log.Println("Closing...")
205-
for _, dependency := range dependencies {
206-
valueDepend := reflect.ValueOf(dependency)
207-
closerType := reflect.TypeOf((*io.Closer)(nil)).Elem()
208-
if valueDepend.Type().Implements(closerType) {
209-
err := dependency.(io.Closer).Close()
210-
if err != nil {
211-
log.Println(err.Error())
212-
}
213-
}
214-
}
215-
}

doc.go

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
1-
// Package Autowire is a framework that makes dependency injection in Golang.
1+
// Package autowire is a framework that makes easy using the dependency
2+
// injection in Golang.
23
//
3-
// Autowire applications use dependency injection framework to eliminate usage
4-
// of globals without the tedious approach to manually wiring all the
5-
// dependencies together. Current approach of Autowire framework to accomplish
6-
// dependency injection is via using struct tags.
4+
// The main purpose of using Autowire as dependency injection framework is
5+
// to eliminate usage of globals without the tedious approach to manually
6+
// wiring all the dependencies together. Current approach of Autowire
7+
// framework is relying on dependency injection via using struct tags and
8+
// reflection. All the dependencies are injected via golang reflection.
79
//
810
// Basic usage is explained in the package-level example below. If you're new
911
// to Autowire, start there!
1012
//
1113
// Testing of Autowire Applications
1214
//
13-
// To write end-to-end tests of your application, you can use functions provided
14-
//by atesting package https://godoc.org/github.com/go-autowire/autowire/atesting
15+
// To write unit or end-to-end tests of your application, you can use functions
16+
// provided by atesting package. For more information take a look at
17+
// https://godoc.org/github.com/go-autowire/autowire/atesting.
1518
package autowire

example/app/application.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
1+
// app package
12
package app
23

34
import (
4-
"fmt"
5+
"log"
6+
57
"github.com/go-autowire/autowire"
68
"github.com/go-autowire/autowire/example/configuration"
79
"github.com/go-autowire/autowire/example/service"
8-
"log"
910
)
1011

1112
func init() {
1213
autowire.Autowire(&Application{})
1314
}
1415

16+
// Application represents named struct
1517
type Application struct {
1618
config *configuration.ApplicationConfig `autowire:""`
1719
userSvc *service.UserService `autowire:""`
@@ -25,7 +27,7 @@ func (a Application) Start() {
2527
if err != nil {
2628
log.Fatalln(err.Error())
2729
}
28-
fmt.Println("Current balance is " + balance.String())
30+
log.Println("Current balance is " + balance.String())
2931
}
3032

3133
// SetConfig method is a Setter of private field config

example/autowire_test.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
package example
22

33
import (
4-
"github.com/go-autowire/autowire"
5-
"github.com/go-autowire/autowire/atesting"
6-
"github.com/go-autowire/autowire/example/app"
74
"log"
85
"math/big"
96
"testing"
7+
8+
"github.com/go-autowire/autowire"
9+
"github.com/go-autowire/autowire/atesting"
10+
"github.com/go-autowire/autowire/example/app"
1011
)
1112

1213
type TestPaymentServiceTest struct {
@@ -26,6 +27,7 @@ func (TestAuditClient) Send(_ string) {
2627
}
2728

2829
func TestAutowire(t *testing.T) {
30+
defer autowire.Close()
2931
application := autowire.Autowired(app.Application{}).(*app.Application)
3032
atesting.Spies(application, []interface{}{&TestPaymentServiceTest{}, &TestAuditClient{}})
3133
application.Start()

example/configuration/application_config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// configuration package
12
package configuration
23

34
import (

example/repository/user_repo.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// repository package
12
package repository
23

34
import "github.com/go-autowire/autowire"
@@ -10,7 +11,7 @@ func init() {
1011
type UserRole string
1112

1213
const (
13-
// OwnerRole
14+
// OwnerRole literal
1415
OwnerRole UserRole = "owner"
1516
)
1617

example/service/audit_service.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,13 @@ type AuditService struct {
1515
Type string
1616
}
1717

18-
// A Send is dispatching the event
18+
// Send is dispatching the event
1919
func (AuditService) Send(event string) {
2020
log.Printf("auditClient Event %s sent", event)
2121
}
22+
23+
// Close method release all occupied resources
24+
func (a AuditService) Close() error {
25+
log.Println("Closing AuditService")
26+
return nil
27+
}

0 commit comments

Comments
 (0)