forked from Netflix/Hystrix
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
0de2eb6
commit c9a73cd
Showing
46 changed files
with
2,763 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
} | ||
} |
66 changes: 66 additions & 0 deletions
66
...anica/src/main/java/com/netflix/hystrix/contrib/javanica/annotation/HystrixCollapser.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 {}; | ||
|
||
} |
93 changes: 93 additions & 0 deletions
93
...avanica/src/main/java/com/netflix/hystrix/contrib/javanica/annotation/HystrixCommand.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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.