https://blog.ndepend.com/hexagonal-architecture/
The spirit is to separate responsibility, not to allow initialization of dependency (database connection etc.) contaminate business code.
To achieve this, CDI is a quite mature and elegant concept. This Hexagonal architecture doesn't seem as elegant as CDI solution:
Hexagonal architecture is all about swapping components—specifically, external components. The bottom line is that you don’t need to rely on external factors to test your application.
Put inputs & outputs at edge of design (ports & adapters)
Isolate central logic from outside concerns
"Use case" is the core business logic, at the center of the hexagon. "Use case", or the business logic, should be pure, only use objects and not contaminated.
In one implementation the "use case" has empty "ports methods". Use case can call these methods, and it's up to the ports to AOP (decorate, before/after etc.) these empty methods to make them work. In another implementation, the "use case" depends on a "ports" object and calls the methods of such object. Think about it......
Interface is the port, is abstraction and represents another thing - database, message bus, etc.
Or on implementation, ports object is the thing to glue everything together: use case, adapter.
In one implementation the ports object uses YouAreDaBomb library (AOP) to glue things together.
Adapters implement the interface. Adapters should not have any business logic.
Makes input/output exchangeable, so the core can be tested with "test doubles", i.e. fakes.
See an example here:
Use case - accepts a "ports" and builds an object that interact with outside from ports methods. So user case depends on ports. Ports removes all concerns of the outside from use case. Use case calls ports and then ignore whatever outside effect happens.
Ports - for input, the ports object subscribes to event bus and call user case methods, for output, the ports object implement port interface methods to allow user case to invoke, when initializing, the ports object take in a bunch of adapters, the concrete implementations of UI, router, eventBus, etc. to invoke, so as to do the real works
Adapters - concrete implementations
Dependency injection - sounds like can be used to put everything together.
AOP: https://github.com/arkency/YouAreDaBomb AOP library, adds before/after/around/guard method combinations to projects. Style ".clazz(..).method('methodName').after
EventBus: https://github.com/arkency/event-bus subscribe/push events