How do their APIs compare?
How do their APIs compare?
About netflix/hystrix · 2 messages · last activity 8/12/2026
I can compare the two projects' core APIs based on what's in the retrieved data, though I should note that comparing "API design philosophy" between a fault-tolerance library and a dependency-injection library involves comparing quite different problem domains.
netflix/hystrix — Command-wrapping API
Hystrix's core usage pattern is subclassing a command object and invoking it through one of several execution styles. From the README:
public class CommandHelloWorld extends HystrixCommand<String> {
private final String name;
public CommandHelloWorld(String name) {
super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
this.name = name;
}
@Override
protected String run() {
return "Hello " + name + "!";
}
}
[README.md:L56-L74]
Callers then choose synchronous, Future-based, or Observable-based invocation:
String s = new CommandHelloWorld("Bob").execute();
Future<String> s = new CommandHelloWorld("Bob").queue();
Observable<String> s = new CommandHelloWorld("Bob").observe();
[README.md:L79-L82]
This is an inheritance/wrapper-based API — you extend HystrixCommand<T>, override run(), and the base class handles circuit-breaking, isolation, and fallback logic.
On top of that imperative API, hystrix-javanica offers an annotation-driven alternative so you don't have to write command classes by hand — you annotate a method with @HystrixCommand and an AspectJ/Spring AOP aspect (HystrixCommandAspect) wraps the call [hystrix-contrib/hystrix-javanica/README.md:L1-L46]. It also layers in caching annotations like @CacheResult, @CacheRemove, and @CacheKey, where cache keys are derived either from annotated parameters or a designated cacheKeyMethod [hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/cache/annotation/CacheResult.java:L36-L49] [hystrix-contrib/hystrix-javanica/README.md:L487-L516].
square/dagger — Annotation-driven dependency injection API
Dagger's API is annotation-first from the start. Consumers declare dependencies with @Inject fields and wire them via @Module/@Provides classes, then bootstrap through ObjectGraph:
class TestApp implements Runnable {
@Inject Foo foo;
public static void main(String[] args) {
ObjectGraph.create(new TestModule()).get(TestApp.class).run();
}
@Module(injects = TestApp.class)
static class TestModule {
@Provides Foo providesFoo(MyFoo foo) { return foo; }
}
}
[compiler/src/it/same-provides-method-name/src/main/java/test/TestApp.java:L27-L57]
There's no runtime reflection-heavy proxying by default for the primary path — Dagger's compiler module generates adapter code at compile time (InjectAdapter, ModuleAdapter, etc.), documented via javadoc templates like GET_METHOD, GET_DEPENDENCIES_METHOD, and MODULE_TYPE [compiler/src/main/java/dagger/internal/codegen/AdapterJavadocs.java:L25-L45]. If generated adapters aren't found at runtime, FailoverLoader falls back to reflective equivalents (ReflectiveAtInjectBinding, ReflectiveStaticInjection) [core/src/main/java/dagger/internal/FailoverLoader.java:L16-L31].
Key contrasts
| Aspect | Hystrix | Dagger |
|---|---|---|
| Primary integration style | Subclass + override (HystrixCommand<T>) | Field/constructor annotations (@Inject, @Provides, @Module) |
| Alternate style | Annotation-based via javanica + AOP proxy | N/A (annotations are the only style; codegen is transparent) |
| Concurrency model exposed in API | Explicit: execute(), queue(), observe() give sync/Future/Observable | Not concurrency-related; API is about graph construction and injection |
Want to ask your own question?
Open chat for netflix/hystrixPublic Q&A. Generated by RepoPilot from the actual source of netflix/hystrix. AI answers can be incomplete or stale — verify before relying on them.