t := reflect.TypeOf(name)
o := reflect.New(t)
e := o.Elem()
f := e.Interface()
s, ok := f.(AuthService)
if !ok {
println("bad type")
continue
}
s.Auth()
}
}
===========
notice that the plugins are provided by others , the host only know the package name and the interface it provides.
so in the main package ( the host), it needs to create the specific plugin type at runtime.
but the above code does not work.
why does not the reflect.TypeOf() work for given type name ?
what is the workaround for this ?
The type of name is string. TypeOf works as designed here. (Try fmt.Println(t))
Regarding the overall goal of using different implementations for AuthService, I am not sure why you would need reflection here. The two structs already implement the AuthService interface and hence can be passed to any function that expects an AuthService.
because plugins are from a different binary under package named “external”, provided by external vendors in different companies.
the package “main” is the hosting app i developed, the agreement between me and external plugin is the interface:
type AuthService interface {
Auth()
}
the vendors only gives me their binary file (no source code share) so i have to get their objects at runtime to know which object has implemented the above interface.
your suggestion means there will be a big “if … else” , and i have to know the name of each structs that implements the interface
type AuthService interface {
Auth()
}
again, plugins are provided by other companies in binary file. i have no way to know their objects. i only know they will implement the above interface.
I have not yet heard of a way of reverse-engineering and accessing data structures and methods out of a different binary using reflection. I guess you would have to dig into the binary’s symbol table and use some debugger techniques to find and call that external code.
You might want to look into how Delve (the popular Go debugger) is doing this, but a much better way IMHO would be to agree with your external providers on a protocol to remote-call the third-party binaries. There are quite a few options available, including -
simple stdin/stdout pipelines
net/rpc
message queues (NATS, or brokerless versions like nsq)
gRPC
REST
GraphQL
Here is a nice article from some random guy on the internet as a starter: Plugins in Go · Applied Go (Also showcases net/rpc.)
Then at startup your system can load all plugins and create a map like
var PluginsMap map[string]func() = map[string]func(){}
func init() {
// Load all plugins and put in the map the plugin's Name and NewService
}
func main() {
var pluginName string
// Use some criteria to decide the Name
var svc AuthService
if f, ok := PluginsMap[string]; ok {
svc - f()
} else {
// default implementation or panic
}
}
the only thing is that vendors can easily forget to build their code as a plugin with the ‘go build -buildmode=plugin’ option, that results their binary file can not be used to get symbols.
actually under the hood of the plugin.Open() is what missing in the golang reflection.
why can not golang expose the way it implements of plugin.Open as public methods so that anyone can load any binary file to look up symbols in it (not only limit to binary build with the -buildmode=plugin option)?
well, to be honest … this is how other plugins system works. People have to know they are building a plugin and then have to know what are the symbols to expose.
Many languages without any reflection feature (like C/C++) implement plugins in the way I described, the main system define commons interface and the plugin’s creator shall implement it.
In general a plugin shall have
a unique identifier (usually in the form of a reverse DNS name like com.my-company.audio-plugin)
[optional] a version string
a initialization/registration method that who loads the plugin uses to get information and then use the plugin