Go-如何为动态软件包组织代码

I have a small web application written in Go. It is created a base for a larger system and I would like it to be extendable where components can be added/removed without needing this base to be modified in any way.

The structure is currently:

       App
         Modules
             Core
                 ... Core Files Here ...
       app.go
   main.go

app.go will contain a routing method which should take a web request and based on the request path know which module is responsible for handling the request. Each module/component having its on controller.

Each component will have its own package name so i think this is going to be impossible since go forces an explicit import.

For example i may add a new module/component called say blog such as:

       App
         Modules
             Core
                 ... Core Files Here ...
                 controller.go
             Blog
                 ... Blog Files Here ...
                 controller.go
       app.go
   main.go

There are several ways to achieve your goal. Since Go does not support dynamically loaded libraries at the moment, you need to probably recompile your application whenever you add/remove any components. The simplest way therefore would be a yourapp/core package with the following:

  • an Application type with an ServeHTTP method that acts as your main application
  • a Component interface that all your components have to implement. Your might want include a BaseUrl() string and a ServeHTTP method there.
  • a Register method to your Application type, that can be used to add new components to your app.

Your components can then be implemented in separate packages (e.g. yourapp/blog) and they will probably depend on your yourapp/core package.

The only thing that still needs to be "user-editable" is the main.go file, which might look like this:

func main() {
    app := core.NewApplication()
    app.Register(blog.Blog{
        Title: "My Personal Blog",
    })
    app.Register(...)
    app.Run()
}

Another approach might be to define an RPC interface for your components (which might include functions like RegisterComponent, UnregisterComponent and a GetGlobalConfig).

Then, you can run those components in separate processes which has the advantage that you can start/stop/reload those components dynamically and they can not break your main app. Take a look at the net/rpc package and maybe even httputil.NewSingleHostReverseProxy if you want to use this approach instead.