questions
@Startup
@Singleton
public class ConsulConfig {
String serviceId = "s1-2";
Consul client;
AgentClient agentClient;
@PostConstruct
void init() {
client = Consul.builder()
.withHostAndPort(HostAndPort.fromParts("consul", 8500)).build();
agentClient = client.agentClient();
Registration service = ImmutableRegistration.builder()
.id(serviceId)
.name("s1")
.port(8080)
.address("wildfly")
.tags(Collections.singletonList("s1"))
.meta(Collections.singletonMap("version", "1.0"))
.build();
agentClient.register(service);
}
@PreDestroy
private void deregisterService(){
agentClient.deregister(serviceId);
}
}
spring:
cloud:
consul:
host: localhost
port: 8500
service {
name = "pancake-service"
id = "terra-pancake"
tags = ["jakartaee", "wildfly"]
address = "terra"
port = 8080
check {
name = "HTTP API on terra"
type = "http"
interval = "10s"
timeout = "1s"
method = "GET"
path = "/health"
http = "http://terra:8080/health"
}
}
consul services register helios-service.hcl
consul services register terra-service.hcl
consul services register aqua-service.hcl
def register_service():
url = "http://localhost:8500/v1/agent/service/register"
service_data = {
"name": "example-service",
"id": "example-service-1",
"address": "127.0.0.1",
"port": 5000,
"check": {
"http": "http://127.0.0.1:5000/health",
"interval": "10s"
}
}
response = requests.put(url, data=json.dumps(service_data))
if response.status_code == 200:
print("Service registered successfully.")
else:
print(f"Failed to register service: {response.text}")
register_service()
there is no server-side load balancers (consul is not server-side)
all the requests are balancing via ribbon, haproxy, nginx or other client applications
consul-template also should be noticed for nginx
soap - protocol based on xml. message in soap contains envelope, body, header, errors. does not need http protocol extended with other soap specifications (ws-security, ws-addressing)
wsdl - xml document which describes all meta information needed to communicate with some server. like in rpc allows programmers to generate code from service description
<message name="getTermRequest">
<part name="term" type="xs:string"/>
</message>
<message name="getTermResponse">
<part name="value" type="xs:string"/>
</message>
<portType name="glossaryTerms">
<operation name="getTerm">
<input message="getTermRequest"/>
<output message="getTermResponse"/>
</operation>
</portType>
uddi - specification for universal description, discovery, integration of web service. centralized registry for web servers. nowdays i can't find public uddi registry in the internet, but it can be personally deployed by some company. there is 3 types of pages in uddi:
<businessEntity businessKey="uuid:C0E6D5A8-C446-4f01-99DA-70E212685A40"
operator="http://www.ibm.com" authorizedName="John Doe">
<name>Acme Company</name>
<description>
We create cool Web services
</description>
<contacts>
<contact useType="general info">
<description>General Information</description>
<personName>John Doe</personName>
<phone>(123) 123-1234</phone>
<email>jdoe@acme.com</email>
</contact>
</contacts>
<businessServices>
...
</businessServices>
<identifierBag>
<keyedReference tModelKey="UUID:8609C81E-EE1F-4D5A-B202-3EB13AD01823"
name="D-U-N-S" value="123456789" />
</identifierBag>
<categoryBag>
<keyedReference tModelKey="UUID:C0B9FE13-179F-413D-8A5B-5004DB8E5BB2"
name="NAICS" value="111336" />
</categoryBag>
</businessEntity>
jax-rs is not xml based, "x" is not xml.
can be integrated with jaxb (java architecture for xml binding)
@XmlRootElement(name = "CarDto")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlAttribute(name = "cool")
@XmlElement(name = "id")
@XmlElementWrapper(name = "teamList")
@Consumes(MediaType.APPLICATION_XML)
@Produces(MediaType.APPLICATION_XML)
@Path("/v1/")
public class HumanWebServiceImpl implements HumanWebService {
@Override
@Consumes(MediaType.APPLICATION_XML)
@Produces(MediaType.APPLICATION_XML)
@POST
@Path("/human-being")
public Response createHumanBeing(@Valid CreateHumanBeingRequest request) {
remoteServiceEjb.createHumanBeing(request);
return Response.ok().build();
}
}
see question #1
@EnableEurekaServer
@EnableZuulProxy
@SpringBootApplication
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
@SpringBootApplication
@EnableDiscoveryClient
public class RibbonApplication {
public static void main(String[] args) {
SpringApplication.run(RibbonApplication.class, args);
}
}
Eureka client:
eureka.client.serviceUrl.defaultZone=http://eureka-server:8761/eureka/
Eureka server:
spring.application.name=eureka-server
server.port=8761
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
zuul.prefix=/api
zuul.routes.s2.path=/s2/**
zuul.routes.s2.url=http://ribbon:9004
main entity in mule esb - message (header + payload). message exchange via flows
configuring via xml descriptors or graphical interface. built with maven / anypoint
+-------------------+
| HTTP Listener |
| (Trigger) |
+-------------------+
|
v
+-------------------+
| Database Read |
| (Fetch Records) |
+-------------------+
|
v
+-------------------+
| Transform Data |
| (to XML Format) |
+-------------------+
|
v
+-------------------+
| HTTP Requester |
| (Send to Server) |
+-------------------+
|
v
+-------------------+
| Logger (End) |
+-------------------+
<mule xmlns:db="http://www.mulesoft.org/schema/mule/db"
xmlns:http="http://www.mulesoft.org/schema/mule/http"
xmlns="http://www.mulesoft.org/schema/mule/core"
xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd
http://www.mulesoft.org/schema/mule/db http://www.mulesoft.org/schema/mule/db/current/mule-db.xsd">
<!-- HTTP Listener Configuration -->
<http:listener-config name="HTTP_Listener_config" doc:name="HTTP Listener config">
<http:listener-connection host="0.0.0.0" port="8081"/>
</http:listener-config>
<!-- Flow Definition -->
<flow name="database-to-server-flow" doc:id="db-to-server-flow">
<!-- HTTP Listener -->
<http:listener doc:name="HTTP Listener" config-ref="HTTP_Listener_config" path="/fetch">
</http:listener>
<!-- Database Configuration -->
<db:config name="Database_Config" doc:name="Database config">
<db:connection>
<!-- Configure your database connection here -->
<db:mysql-connection host="your-db-host" port="3306" user="your-user" password="your-password" database="your-db"/>
</db:connection>
</db:config>
<!-- Database Select -->
<db:select doc:name="Database Select" config-ref="Database_Config">
<db:sql>#["SELECT * FROM your_table"]</db:sql>
</db:select>
<!-- Transform to XML -->
<transform doc:name="Transform to XML">
<dw:set-payload><![CDATA[%dw 2.0
output application/xml
---
payload]]></dw:set-payload>
</transform>
<!-- HTTP Request -->
<http:request doc:name="HTTP Request" method="POST" url="http://your-service-endpoint.com/api/data">
<http:request-config>
<!-- Optional: include additional configuration like security -->
</http:request-config>
</http:request>
<!-- Logger -->
<logger level="INFO" doc:name="Logger" message="Data sent to server"/>
</flow>
</mule>
@EnableCircuitBreaker
@EnableHystrixDashboard
@HystrixCommand(fallbackMethod = "myFallbackMethod")
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.stereotype.Service;
@Service
public class MyService {
@HystrixCommand(fallbackMethod = "myFallbackMethod")
public String performService() {
// Logic that may fail or take too long
if (someCondition()) {
throw new RuntimeException("Failed!");
}
return "Service completed successfully!";
}
public String myFallbackMethod() {
return "Fallback response: Service is currently unavailable.";
}
private boolean someCondition() {
// Simulate a condition that causes failure
return true;
}
}
@WebService(serviceName = "EchoService", endpointInterface = "com.ibm.was.wssample.echo.EchoServicePortType", targetNamespace="http://com/ibm/was/wssample/echo/", portName="EchoServicePort")
@WebMethod(name = 'xxx')
@WebResult(name = 'yyy')
@WebParam
public class EmployeeServicePublisher {
public static void main(String[] args) {
Endpoint.publish(
"http://localhost:8080/employeeservice",
new EmployeeServiceImpl());
}
}
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
@WebService
@SOAPBinding(style = SOAPBinding.Style.DOCUMENT, use = SOAPBinding.Use.LITERAL)
public class MyWebService {
public String sayHello(String name) {
return "Hello, " + name;
}
}
@WebService
public class NotificationService {
@WebMethod
@Oneway
public void sendNotification(String message) {
// Send a notification without expecting a response
System.out.println("Notification sent: " + message);
}
}
@WebServiceRef(wsdlLocation="http://localhost:8080/employeeservice?wsdl")
static EmployeeService service;
EmployeeService port = service.getEmployeeServicePort();
wsimport -keep -verbose http://localhost:8080/employeeservice?wsdl
orchestring tools: kubernetes, apache mesos, elastic container service
choreography tools: spring boot kit, kafka, other message brokers
image just because i like ascii images:
+------------------+
| Orchestrator |
+------------------+
/ | | \
/ | | \
v v v v
+-----+ +-----+ +-----+ +-----+
| | | | | | | |
| Svc | | Svc | | Svc | | Svc |
| A | | B | | C | | D |
| | | | | | | |
+-----+ +-----+ +-----+ +-----+
+-----+ +-----+ +-----+ +-----+
| |------>| |------>| |------>| |
| Svc | | Svc | | Svc | | Svc |
| A |<------| B |<------| C |<------| D |
| | | | | | | |
+-----+ +-----+ +-----+ +-----+
operator/manager uses api server on master kubernetes node. master node upodating confuguration on nodes via kubelet. users get access to kubernetes nodes via kubeproxy. etcd - key-value database value. kubernetes pod is set of container. kubernetes provides:
wsimport -s . -p com.baeldung.jaxws.server.topdown employeeservicetopdown.wsdl
@WebService(
name = "EmployeeServiceTopDown",
targetNamespace = "http://topdown.server.jaxws.baeldung.com/")
@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
@XmlSeeAlso({
ObjectFactory.class
})
public interface EmployeeServiceTopDown {
@WebMethod(
action = "http://topdown.server.jaxws.baeldung.com/"
+ "EmployeeServiceTopDown/countEmployees")
@WebResult(
name = "countEmployeesResponse",
targetNamespace = "http://topdown.server.jaxws.baeldung.com/",
partName = "parameters")
public int countEmployees();
}
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-all</artifactId>
<version>3.1.1</version>
</dependency>
spring:
cloud:
consul:
host: localhost
port: 8500
spring:
cloud:
consul:
discovery:
healthCheckPath: /my-health-check
healthCheckInterval: 20s
microservice is subtype of service oriented architecture. symmetric, but not hierarchical architecture. microservice is small, independant has small context, pattern smart end, no centralization, automatization. size of microservice must be so that one command can rewrite one service in sprint.
microservice has own database and use pattern "eventual consistency". in pattern smart endpoints & dumb pipes it is better to use async calls, possible both text-based and binary protocols.
package com.example.distributedsorting;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/sort")
public class SortingController {
@Autowired
private RabbitTemplate rabbitTemplate;
@PostMapping
public int[] sortArray(@RequestBody int[] array) {
rabbitTemplate.convertAndSend("sortingQueue", array);
return array;
}
}
@Component
public class SortingListener {
@RabbitListener(queues = "sortingQueue")
public void receiveMessage(int[] array) {
Arrays.sort(array);
}
}