Permalink
Browse files

hystrix-javanica: initial commit

  • Loading branch information...
1 parent 0de2eb6 commit c9a73cd594dd7df6a1fc5a3eea42438ba8f18e8c @dmgcodevil dmgcodevil committed Mar 6, 2014
Showing with 2,763 additions and 0 deletions.
  1. +169 −0 hystrix-contrib/hystrix-javanica/README.md
  2. +38 −0 hystrix-contrib/hystrix-javanica/build.gradle
  3. +66 −0 ...trix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/annotation/HystrixCollapser.java
  4. +93 −0 ...ystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/annotation/HystrixCommand.java
  5. +47 −0 ...strix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/annotation/HystrixProperty.java
  6. +28 −0 ...ix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/aop/ProxyType.java
  7. +77 −0 ...vanica/src/main/java/com/netflix/hystrix/contrib/javanica/aop/aspectj/HystrixCollapserAspect.java
  8. +94 −0 ...javanica/src/main/java/com/netflix/hystrix/contrib/javanica/aop/aspectj/HystrixCommandAspect.java
  9. +72 −0 ...ystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/collapser/CollapserResult.java
  10. +109 −0 ...strix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/collapser/CommandCollapser.java
  11. +112 −0 ...x-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/command/AbstractHystrixCommand.java
  12. +110 −0 ...ica/src/main/java/com/netflix/hystrix/contrib/javanica/command/AbstractHystrixCommandFactory.java
  13. +59 −0 ...rib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/command/AsyncCommand.java
  14. +69 −0 ...trix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/command/BatchHystrixCommand.java
  15. +44 −0 ...vanica/src/main/java/com/netflix/hystrix/contrib/javanica/command/BatchHystrixCommandFactory.java
  16. +70 −0 ...ib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/command/CommandAction.java
  17. +38 −0 ...x-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/command/CommandExecutionAction.java
  18. +73 −0 ...rix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/command/CommandSetterBuilder.java
  19. +85 −0 ...b/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/command/GenericCommand.java
  20. +44 −0 ...nica/src/main/java/com/netflix/hystrix/contrib/javanica/command/GenericHystrixCommandFactory.java
  21. +38 −0 ...ix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/command/HystrixCommandFactory.java
  22. +184 −0 ...ntrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/command/MetaHolder.java
  23. +99 −0 ...ix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/conf/HystrixPropertiesManager.java
  24. +51 −0 ...src/main/java/com/netflix/hystrix/contrib/javanica/exception/CommandActionExecutionException.java
  25. +128 −0 ...x-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/utils/AopUtils.java
  26. 0 hystrix-contrib/hystrix-javanica/src/main/resources/dummy.txt
  27. +64 −0 hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/CommonUtils.java
  28. +11 −0 ...-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/spring/conf/AopCglibConfig.java
  29. +11 −0 ...ix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/spring/conf/AopJdkConfig.java
  30. +13 −0 ...src/test/java/com/netflix/hystrix/contrib/javanica/test/spring/conf/AopLoadTimeWeavingConfig.java
  31. +22 −0 ...src/test/java/com/netflix/hystrix/contrib/javanica/test/spring/conf/SpringApplicationContext.java
  32. +27 −0 ...vanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/spring/rest/client/RestClient.java
  33. +102 −0 .../src/test/java/com/netflix/hystrix/contrib/javanica/test/spring/rest/client/SimpleRestClient.java
  34. +110 −0 ...test/java/com/netflix/hystrix/contrib/javanica/test/spring/rest/collapser/BaseRestClientTest.java
  35. +13 −0 ...est/java/com/netflix/hystrix/contrib/javanica/test/spring/rest/collapser/CglibRestClientTest.java
  36. +12 −0 .../test/java/com/netflix/hystrix/contrib/javanica/test/spring/rest/collapser/JdkRestClientTest.java
  37. +166 −0 ...c/test/java/com/netflix/hystrix/contrib/javanica/test/spring/rest/command/BaseRestClientTest.java
  38. +11 −0 .../test/java/com/netflix/hystrix/contrib/javanica/test/spring/rest/command/CglibRestClientTest.java
  39. +11 −0 ...rc/test/java/com/netflix/hystrix/contrib/javanica/test/spring/rest/command/JdkRestClientTest.java
  40. +12 −0 .../test/java/com/netflix/hystrix/contrib/javanica/test/spring/rest/command/LoadTimeWeavingTest.java
  41. +69 −0 ...rix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/spring/rest/domain/User.java
  42. +20 −0 ...est/java/com/netflix/hystrix/contrib/javanica/test/spring/rest/exception/BadRequestException.java
  43. +20 −0 .../test/java/com/netflix/hystrix/contrib/javanica/test/spring/rest/exception/NotFoundException.java
  44. +71 −0 ...ca/src/test/java/com/netflix/hystrix/contrib/javanica/test/spring/rest/resource/UserResource.java
  45. 0 hystrix-contrib/hystrix-javanica/src/test/resources/dummy.txt
  46. +1 −0 settings.gradle
@@ -0,0 +1,169 @@
+# hystrix-javanica
+
+Java language has a great advantages over other languages such as reflection and annotations.
+All modern frameworks such as Spring, Hibernate, myBatis and etc. seek to use this advantages to the maximum.
+The idea of introduction annotations in Hystrix is obvious solution for improvement. Currently using Hystrix involves writing a lot of code that is a barrier to rapid development. You likely be spending a lot of time on writing a Hystrix commands. Idea of the Javanica project is make easier using of Hystrix by the introduction of support annotations.
+
+First of all in order to use hystrix-javanica you need to add hystrix-javanica dependency in your project.
+
+Example for Maven:
+```xml
+<dependency>
+ <groupId>com.netflix.hystrix</groupId>
+ <artifactId>hystrix-javanica</artifactId>
+ <version>x.y.z</version>
+</dependency>
+```
+
+To implement AOP functionality in the project was used AspectJ library. If in your project already used AspectJ then you need to add hystrix aspect in aop.xml as below:
+```xml
+<aspects>
+ ...
+ <aspect name="com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixAspect"/>
+ ...
+</aspects>
+```
+More about AspectJ configuration read [here] (http://www.eclipse.org/aspectj/doc/next/devguide/ltw-configuration.html)
+
+
+If you use Spring AOP in your project then you need to add specific configuration using Spring aop namespace in order to make Spring capable to manage aspects which were written using AspectJ and declare HystrixAspect as Spring bean like below:
+
+```xml
+ <aop:aspectj-autoproxy/>
+ <bean id="hystrixAspect" class="com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixAspect"></bean>
+```
+
+It doesn't matter which approach you use to create proxies in Spring, javanica works fine with JDK and CGLIB proxies. If you use another framework for aop which supports AspectJ and uses other libs (Javassist for instance) to create proxies then let us know what lib you use to create proxies and we'll try to add support for this library in near future.
+
+More about Spring AOP + AspectJ read [here] (http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/aop.html)
+
+# How to use
+
+## Hystrix command
+
+To run method as Hystrix command you need to annotate method with @HystrixCommand annotation, for example
+```java
+ @HystrixCommand(fallbackMethod = "defaultUser")
+ public User getUserById(String id) {
+ return userResource.getUserById(id);
+ }
+
+ private User defaultUser(String id) {
+ return new User();
+ }
+```
+In example above the 'getUserById' method will be processed [synchronously](https://github.com/Netflix/Hystrix/wiki/How-To-Use#wiki-Synchronous-Execution) as Hystrix command. Fallback method can be private or public. Method 'defaultUser' will be used to process fallback logic in a case of any errors. If you need to run 'defaultUser' as command then you can annotate it with HystrixCommand annotation as below:
+```java
+ @HystrixCommand(fallbackMethod = "defaultUser")
+ public User getUserById(String id) {
+ return userResource.getUserById(id);
+ }
+
+ @HystrixCommand
+ private User defaultUser(String id) {
+ return new User();
+ }
+```
+
+If fallback method was marked with @HystrixCommand then this method also can has own fallback method, as in the example below:
+```java
+ @HystrixCommand(fallbackMethod = "defaultUser")
+ public User getUserById(String id) {
+ return userResource.getUserById(id);
+ }
+
+ @HystrixCommand(fallbackMethod = "defaultUserSecond")
+ private User defaultUser(String id) {
+ return new User();
+ }
+
+ @HystrixCommand
+ private User defaultUserSecond(String id) {
+ return new User("def", "def");
+ }
+```
+
+Its important to remember that Hystrix command and fallback should be placed in the same class.
+
+To process Hystrix command asynchronously you should return an instance of AsyncCommand in your command method as in the exapmple below:
+```java
+ @HystrixCommand
+ public Future<User> getUserByIdAsync(final String id) {
+ return new AsyncCommand<User>() {
+ @Override
+ public User invoke() {
+ return userResource.getUserById(id);
+ }
+ };
+ }
+```
+
+The return type of command method should be Future that indicates that a command should be executed [asynchronously] (https://github.com/Netflix/Hystrix/wiki/How-To-Use#wiki-Asynchronous-Execution).
+
+Command properties can be set using commandProperties field like below:
+```java
+
+ @HystrixCommand(fallbackMethod = "defaultUser",
+ commandProperties = {
+ @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "500")
+ })
+ public User getUserById(String id) {
+ return userResource.getUserById(id);
+ }
+```
+
+
+Javanica sets command properties using Hystrix ConfigurationManager.
+For the example above Javanica behind the scenes performs next action:
+```java
+ConfigurationManager.getConfigInstance().setProperty("hystrix.command.getUserById.execution.isolation.thread.timeoutInMilliseconds", "500");
+```
+
+More about Hystrix command properties [command](https://github.com/Netflix/Hystrix/wiki/Configuration#wiki-CommandExecution) and [fallback](https://github.com/Netflix/Hystrix/wiki/Configuration#wiki-CommandFallback)
+
+## Hystrix collapser
+
+Suppose you have some command which calls should be collapsed in one backend call. For this goal you can use HystrixCollapser annotation.
+
+Hystrix command:
+```java
+ @HystrixCommand
+ public User getUserById(String id) {
+ return userResource.getUserById(id);
+ }
+```
+
+Asynchronous call:
+```java
+ @HystrixCollapser(commandMethod = "getUserById",
+ collapserProperties = {@HystrixProperty(name = "timerDelayInMilliseconds", value = "200")})
+ public Future<User> getUserByIdCollapserAsync(String id) {
+ return CollapserResult.async();
+ }
+```
+
+Synchronous call:
+```java
+ @HystrixCollapser(commandMethod = "getUserById",
+ collapserProperties = {@HystrixProperty(name = "maxRequestsInBatch", value = "3")})
+ @Override
+ public User getUserByIdCollapser(String id) {
+ return CollapserResult.sync();
+ }
+```
+
+Lines:
+```java
+ return CollapserResult.async();
+ return CollapserResult.sync();
+```
+In examples above don't affect the result of a collapser call. This just to avoid ```return null;``` statement in code.
+It's important to remember that Hystrix command and сollapser should be placed in the same class.
+
+Read more about Hystrix request collapsing [here] (https://github.com/Netflix/Hystrix/wiki/How-it-Works#wiki-RequestCollapsing)
+
+#Development Status and Future
+
+```java
+todo
+```
@@ -0,0 +1,38 @@
+apply plugin: 'java'
+apply plugin: 'eclipse'
+apply plugin: 'idea'
+
+aspectjVersion = '1.7.4'
+
+dependencies {
+ compile project(':hystrix-core')
+
+ compile "org.aspectj:aspectjweaver:$aspectjVersion"
+ compile "org.aspectj:aspectjrt:$aspectjVersion"
+
+ compile 'com.google.guava:guava:15.0'
+ compile 'commons-collections:commons-collections:3.2.1'
+ compile 'org.apache.commons:commons-lang3:3.1'
+ testCompile 'junit:junit-dep:4.10'
+ testCompile 'org.springframework:spring-core:4.0.0.RELEASE'
+ testCompile 'org.springframework:spring-context:4.0.0.RELEASE'
+ testCompile 'org.springframework:spring-aop:4.0.0.RELEASE'
+ testCompile 'org.springframework:spring-test:4.0.0.RELEASE'
+ testCompile 'cglib:cglib:3.1'
+}
+
+eclipse {
+ classpath {
+ // include 'provided' dependencies on the classpath
+ plusConfigurations += configurations.provided
+ downloadSources = true
+ downloadJavadoc = true
+ }
+}
+
+idea {
+ module {
+ // include 'provided' dependencies on the classpath
+ scopes.COMPILE.plus += configurations.provided
+ }
+}
@@ -0,0 +1,66 @@
+/**
+ * Copyright 2012 Netflix, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.netflix.hystrix.contrib.javanica.annotation;
+
+import com.netflix.hystrix.HystrixCollapser.Scope;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation is used to mark some methods to collapse some commands into a single backend dependency call.
+ */
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface HystrixCollapser {
+
+ /**
+ * Specifies a collapser key.
+ * <p/>
+ * default => the name of annotated method.
+ *
+ * @return collapser key.
+ */
+ String collapserKey() default "";
+
+ /**
+ * Defines what scope the collapsing should occur within.
+ * <p/>
+ * default => the {@link Scope#REQUEST}.
+ *
+ * @return {@link Scope}
+ */
+ Scope scope() default Scope.REQUEST;
+
+ /**
+ * Specifies name of a method which has @HystrixCommand annotation and should be collapsed.
+ *
+ * @return method name.
+ */
+ String commandMethod();
+
+ /**
+ * Specifies collapser properties.
+ *
+ * @return collapser properties
+ */
+ HystrixProperty[] collapserProperties() default {};
+
+}
@@ -0,0 +1,93 @@
+/**
+ * Copyright 2012 Netflix, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.netflix.hystrix.contrib.javanica.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+/**
+ * This annotation used to specify some methods which should be processes as hystrix commands.
+ */
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface HystrixCommand {
+
+ /**
+ * The command group key is used for grouping together commands such as for reporting,
+ * alerting, dashboards or team/library ownership.
+ * <p/>
+ * default => the runtime class name of annotated method
+ *
+ * @return group key
+ */
+ String groupKey() default "";
+
+ /**
+ * Hystrix command key.
+ * <p/>
+ * default => the name of annotated method. for example:
+ * <code>
+ * ...
+ * @HystrixCommand
+ * public User getUserById(...)
+ * ...
+ * the command name will be: 'getUserById'
+ * </code>
+ *
+ * @return command key
+ */
+ String commandKey() default "";
+
+ /**
+ * The thread-pool key is used to represent a
+ * HystrixThreadPool for monitoring, metrics publishing, caching and other such uses.
+ *
+ * @return thread pool key
+ */
+ String threadPoolKey() default "";
+
+ /**
+ * Specifies a method to process fallback logic.
+ * A fallback method should be defined in the same class where is HystrixCommand.
+ * Also a fallback method should have same signature to a method which was invoked as hystrix command.
+ * for example:
+ * <code>
+ * @HystrixCommand(fallbackMethod = "getByIdFallback")
+ * public String getById(String id) {...}
+ *
+ * private String getByIdFallback(String id) {...}
+ * </code>
+ * Also a fallback method can be annotated with {@link HystrixCommand}
+ * <p/>
+ * default => see {@link com.netflix.hystrix.contrib.javanica.command.GenericCommand#getFallback()}
+ *
+ * @return method name
+ */
+ String fallbackMethod() default "";
+
+ /**
+ * Specifies command properties.
+ *
+ * @return command properties
+ */
+ HystrixProperty[] commandProperties() default {};
+}
+
Oops, something went wrong.

0 comments on commit c9a73cd

Please sign in to comment.