BAEL-3091: The Prototype Pattern in Java (changed code based on valid comments from a reader)

This commit is contained in:
Vivek Balasubramaniam
2019-10-29 22:27:15 +05:30
parent db85c8f275
commit d3d5b060e7
20517 changed files with 1642290 additions and 0 deletions
+12
View File
@@ -0,0 +1,12 @@
*.class
#folders#
/target
/src/main/webapp/WEB-INF/classes
*/META-INF/*
# Packaged files #
*.jar
*.war
*.ear
*.iml
+7
View File
@@ -0,0 +1,7 @@
## Hystrix
This module contains articles about Hystrix.
### Relevant Articles:
- [Hystrix Integration with Existing Spring Application](https://www.baeldung.com/hystrix-integration-with-spring-aop)
- [Introduction to Hystrix](https://www.baeldung.com/introduction-to-hystrix)
+59
View File
@@ -0,0 +1,59 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>hystrix</artifactId>
<version>1.0</version>
<name>hystrix</name>
<parent>
<artifactId>parent-boot-1</artifactId>
<groupId>com.baeldung</groupId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../parent-boot-1</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>com.netflix.hystrix</groupId>
<artifactId>hystrix-core</artifactId>
<version>${hystrix-core.version}</version>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.netflix.hystrix</groupId>
<artifactId>hystrix-metrics-event-stream</artifactId>
<version>${hystrix-metrics-event-stream.version}</version>
</dependency>
<dependency>
<groupId>com.netflix.rxjava</groupId>
<artifactId>rxjava-core</artifactId>
<version>${rxjava-core.version}</version>
</dependency>
</dependencies>
<properties>
<!-- Hystrix -->
<hystrix-core.version>1.5.8</hystrix-core.version>
<rxjava-core.version>0.20.7</rxjava-core.version>
<!-- maven plugins -->
<hystrix-metrics-event-stream.version>1.5.8</hystrix-metrics-event-stream.version>
</properties>
</project>
@@ -0,0 +1,20 @@
package com.baeldung.hystrix;
import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class AppConfig {
public static void main(String[] args) {
SpringApplication.run(AppConfig.class, args);
}
@Bean
public ServletRegistrationBean adminServletRegistrationBean() {
return new ServletRegistrationBean(new HystrixMetricsStreamServlet(), "/hystrix.stream");
}
}
@@ -0,0 +1,19 @@
package com.baeldung.hystrix;
import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
class CommandHelloWorld extends HystrixCommand<String> {
private final String name;
CommandHelloWorld(String name) {
super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
this.name = name;
}
@Override
protected String run() {
return "Hello " + name + "!";
}
}
@@ -0,0 +1,83 @@
package com.baeldung.hystrix;
import com.netflix.hystrix.*;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component
@Aspect
public class HystrixAspect {
private HystrixCommand.Setter config;
private HystrixCommandProperties.Setter commandProperties;
private HystrixThreadPoolProperties.Setter threadPoolProperties;
@Value("${remoteservice.command.execution.timeout}")
private int executionTimeout;
@Value("${remoteservice.command.sleepwindow}")
private int sleepWindow;
@Value("${remoteservice.command.threadpool.maxsize}")
private int maxThreadCount;
@Value("${remoteservice.command.threadpool.coresize}")
private int coreThreadCount;
@Value("${remoteservice.command.task.queue.size}")
private int queueCount;
@Value("${remoteservice.command.group.key}")
private String groupKey;
@Value("${remoteservice.command.key}")
private String key;
@Around("@annotation(com.baeldung.hystrix.HystrixCircuitBreaker)")
public Object circuitBreakerAround(final ProceedingJoinPoint aJoinPoint) {
return new RemoteServiceCommand(config, aJoinPoint).execute();
}
@PostConstruct
private void setup() {
this.config = HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(groupKey));
this.config = config.andCommandKey(HystrixCommandKey.Factory.asKey(key));
this.commandProperties = HystrixCommandProperties.Setter();
this.commandProperties.withExecutionTimeoutInMilliseconds(executionTimeout);
this.commandProperties.withCircuitBreakerSleepWindowInMilliseconds(sleepWindow);
this.threadPoolProperties = HystrixThreadPoolProperties.Setter();
this.threadPoolProperties.withMaxQueueSize(maxThreadCount).withCoreSize(coreThreadCount).withMaxQueueSize(queueCount);
this.config.andCommandPropertiesDefaults(commandProperties);
this.config.andThreadPoolPropertiesDefaults(threadPoolProperties);
}
private static class RemoteServiceCommand extends HystrixCommand<String> {
private final ProceedingJoinPoint joinPoint;
RemoteServiceCommand(final Setter config, final ProceedingJoinPoint joinPoint) {
super(config);
this.joinPoint = joinPoint;
}
@Override
protected String run() throws Exception {
try {
return (String) joinPoint.proceed();
} catch (final Throwable th) {
throw new Exception(th);
}
}
}
}
@@ -0,0 +1,11 @@
package com.baeldung.hystrix;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface HystrixCircuitBreaker {
}
@@ -0,0 +1,22 @@
package com.baeldung.hystrix;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HystrixController {
@Autowired
private SpringExistingClient client;
@RequestMapping("/withHystrix")
public String withHystrix() throws InterruptedException{
return client.invokeRemoteServiceWithHystrix();
}
@RequestMapping("/withOutHystrix")
public String withOutHystrix() throws InterruptedException{
return client.invokeRemoteServiceWithOutHystrix();
}
}
@@ -0,0 +1,20 @@
package com.baeldung.hystrix;
import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
class RemoteServiceTestCommand extends HystrixCommand<String> {
private final RemoteServiceTestSimulator remoteService;
RemoteServiceTestCommand(Setter config, RemoteServiceTestSimulator remoteService) {
super(config);
this.remoteService = remoteService;
}
@Override
protected String run() throws Exception {
return remoteService.execute();
}
}
@@ -0,0 +1,16 @@
package com.baeldung.hystrix;
public class RemoteServiceTestSimulator {
private long wait;
RemoteServiceTestSimulator(long wait) throws InterruptedException {
this.wait = wait;
}
String execute() throws InterruptedException {
Thread.sleep(wait);
return "Success";
}
}
@@ -0,0 +1,20 @@
package com.baeldung.hystrix;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component("springClient")
public class SpringExistingClient {
@Value("${remoteservice.timeout}")
private int remoteServiceDelay;
@HystrixCircuitBreaker
public String invokeRemoteServiceWithHystrix() throws InterruptedException{
return new RemoteServiceTestSimulator(remoteServiceDelay).execute();
}
public String invokeRemoteServiceWithOutHystrix() throws InterruptedException{
return new RemoteServiceTestSimulator(remoteServiceDelay).execute();
}
}
@@ -0,0 +1,8 @@
remoteservice.command.group.key=RemoteServiceGroup
remoteservice.command.key=RemoteServiceKey
remoteservice.command.execution.timeout=10000
remoteservice.command.threadpool.coresize=5
remoteservice.command.threadpool.maxsize=10
remoteservice.command.task.queue.size=5
remoteservice.command.sleepwindow=5000
remoteservice.timeout=15000
+13
View File
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>
@@ -0,0 +1,132 @@
package com.baeldung.hystrix;
import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.HystrixCommandProperties;
import com.netflix.hystrix.HystrixThreadPoolProperties;
import com.netflix.hystrix.exception.HystrixRuntimeException;
import org.junit.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
public class HystrixTimeoutManualTest {
@Test
public void givenInputBobAndDefaultSettings_whenCommandExecuted_thenReturnHelloBob() {
assertThat(new CommandHelloWorld("Bob").execute(), equalTo("Hello Bob!"));
}
@Test
public void givenSvcTimeoutOf100AndDefaultSettings_whenRemoteSvcExecuted_thenReturnSuccess()
throws InterruptedException {
HystrixCommand.Setter config = HystrixCommand
.Setter
.withGroupKey(HystrixCommandGroupKey.Factory.asKey("RemoteServiceGroup2"));
assertThat(new RemoteServiceTestCommand(config, new RemoteServiceTestSimulator(100)).execute(),
equalTo("Success"));
}
@Test(expected = HystrixRuntimeException.class)
public void givenSvcTimeoutOf10000AndDefaultSettings__whenRemoteSvcExecuted_thenExpectHRE() throws InterruptedException {
HystrixCommand.Setter config = HystrixCommand
.Setter
.withGroupKey(HystrixCommandGroupKey.Factory.asKey("RemoteServiceGroupTest3"));
new RemoteServiceTestCommand(config, new RemoteServiceTestSimulator(10_000)).execute();
}
@Test
public void givenSvcTimeoutOf5000AndExecTimeoutOf10000_whenRemoteSvcExecuted_thenReturnSuccess()
throws InterruptedException {
HystrixCommand.Setter config = HystrixCommand
.Setter
.withGroupKey(HystrixCommandGroupKey.Factory.asKey("RemoteServiceGroupTest4"));
HystrixCommandProperties.Setter commandProperties = HystrixCommandProperties.Setter();
commandProperties.withExecutionTimeoutInMilliseconds(10_000);
config.andCommandPropertiesDefaults(commandProperties);
assertThat(new RemoteServiceTestCommand(config, new RemoteServiceTestSimulator(500)).execute(),
equalTo("Success"));
}
@Test(expected = HystrixRuntimeException.class)
public void givenSvcTimeoutOf15000AndExecTimeoutOf5000__whenExecuted_thenExpectHRE()
throws InterruptedException {
HystrixCommand.Setter config = HystrixCommand
.Setter
.withGroupKey(HystrixCommandGroupKey.Factory.asKey("RemoteServiceGroupTest5"));
HystrixCommandProperties.Setter commandProperties = HystrixCommandProperties.Setter();
commandProperties.withExecutionTimeoutInMilliseconds(5_000);
config.andCommandPropertiesDefaults(commandProperties);
new RemoteServiceTestCommand(config, new RemoteServiceTestSimulator(15_000)).execute();
}
@Test
public void givenSvcTimeoutOf500AndExecTimeoutOf10000AndThreadPool__whenExecuted_thenReturnSuccess()
throws InterruptedException {
HystrixCommand.Setter config = HystrixCommand
.Setter
.withGroupKey(HystrixCommandGroupKey.Factory.asKey("RemoteServiceGroupThreadPool"));
HystrixCommandProperties.Setter commandProperties = HystrixCommandProperties.Setter();
commandProperties.withExecutionTimeoutInMilliseconds(10_000);
config.andCommandPropertiesDefaults(commandProperties);
config.andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter()
.withMaxQueueSize(10)
.withCoreSize(3)
.withQueueSizeRejectionThreshold(10));
assertThat(new RemoteServiceTestCommand(config, new RemoteServiceTestSimulator(500)).execute(),
equalTo("Success"));
}
@Test
public void givenCircuitBreakerSetup__whenRemoteSvcCmdExecuted_thenReturnSuccess()
throws InterruptedException {
HystrixCommand.Setter config = HystrixCommand
.Setter
.withGroupKey(HystrixCommandGroupKey.Factory.asKey("RemoteServiceGroupCircuitBreaker"));
HystrixCommandProperties.Setter properties = HystrixCommandProperties.Setter();
properties.withExecutionTimeoutInMilliseconds(1000);
properties.withCircuitBreakerSleepWindowInMilliseconds(4000);
properties.withExecutionIsolationStrategy(
HystrixCommandProperties.ExecutionIsolationStrategy.THREAD);
properties.withCircuitBreakerEnabled(true);
properties.withCircuitBreakerRequestVolumeThreshold(1);
config.andCommandPropertiesDefaults(properties);
config.andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter()
.withMaxQueueSize(1)
.withCoreSize(1)
.withQueueSizeRejectionThreshold(1));
assertThat(this.invokeRemoteService(config, 10_000), equalTo(null));
assertThat(this.invokeRemoteService(config, 10_000), equalTo(null));
assertThat(this.invokeRemoteService(config, 10_000), equalTo(null));
Thread.sleep(5000);
assertThat(new RemoteServiceTestCommand(config, new RemoteServiceTestSimulator(500)).execute(),
equalTo("Success"));
assertThat(new RemoteServiceTestCommand(config, new RemoteServiceTestSimulator(500)).execute(),
equalTo("Success"));
assertThat(new RemoteServiceTestCommand(config, new RemoteServiceTestSimulator(500)).execute(),
equalTo("Success"));
}
public String invokeRemoteService(HystrixCommand.Setter config, int timeout)
throws InterruptedException {
String response = null;
try {
response = new RemoteServiceTestCommand(config,
new RemoteServiceTestSimulator(timeout)).execute();
} catch (HystrixRuntimeException ex) {
System.out.println("ex = " + ex);
}
return response;
}
}
@@ -0,0 +1,36 @@
package com.baeldung.hystrix;
import com.netflix.hystrix.exception.HystrixRuntimeException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT, classes = AppConfig.class)
public class SpringAndHystrixIntegrationTest {
@Autowired
private HystrixController hystrixController;
@Rule
public final ExpectedException exception = ExpectedException.none();
@Test
public void givenTimeOutOf15000_whenClientCalledWithHystrix_thenExpectHystrixRuntimeException() throws InterruptedException {
exception.expect(HystrixRuntimeException.class);
hystrixController.withHystrix();
}
@Test
public void givenTimeOutOf15000_whenClientCalledWithOutHystrix_thenExpectSuccess() throws InterruptedException {
assertThat(hystrixController.withOutHystrix(), equalTo("Success"));
}
}