RPC

или социализация приложений

RPC

  • Remote Procedure Call
  • Удалённый вызов процедур

RPC зачем?

  • Уменьшить использование ресурсов
  • Разнести логику

RPC что?

  • это не протокол!
  • это набор технологий

RPC из чего состоит

  • протокол обмена
  • сериализатор данных

RPC протокол обмена

  • TCP/UDP
  • HTTP(S) [хотя и не является транспортным уровнем ISO/OSI]

RPC сериализаторы

  • текстовый
    • XML
    • JSON
  • бинарный

Особенности вызова

  • Асимметричность
  • Синхронность

Более сложная реализация

  • Разделение адресного пространства
  • Транспорт
  • аварийные ситуации на одном из концов
  • Неоднородность

RMI

Remote Method Invocation

RMI

  • API Java
  • служит для выполнения кода на другой JVM
  • Связь клиент-серверная

RMI что кого

  • Объекты передаются по значению (Serializeble)
  • Удаленные объекты передаются в виде Stub
  • RemoteException
  • всё можно найти в java.rmi.*

RMI интерфейс


import java.rmi.Remote;
import java.rmi.RemoteException;

public interface RMIInterface extends Remote {
    String sayHello(String name) throws RemoteException;
}

RMI сервер


import java.rmi.*;
import java.rmi.registry.*;
import java.rmi.server.*;

public class RMIServer implements RMIInterface {

    public String sayHello(String name) {
        String string = "Hello, " + name + "!";
        return string;
    }

    public static void main(String... args) throws Exception {
        final Registry registry = LocateRegistry.createRegistry(2099);
        final RMIInterface service = new RMIServer();
        Remote stub = UnicastRemoteObject.exportObject(service, 0);
        registry.bind("sample/HelloService", stub);
    }
}
        

RMI клиент


import java.rmi.registry.*;

public class RMIClient {
    public static void main(String... args) throws Exception {
        Registry registry = LocateRegistry.getRegistry("localhost", 2099);
        RMIInterface service = (RMIInterface) registry
                .lookup("sample/HelloService");
        String[] names = { "John", "Jan", "Иван"};
        for (String name : names) {
            System.out.println(service.sayHello(name));
        }
    }
}
        

RMI безопасность


grant {
    permission java.net.SocketPermission "127.0.0.1:*", "connect,resolve";
    permission java.net.SocketPermission "127.0.0.1:*", "accept";
};
        

grant {
    permission java.security.AllPermission;
};
        

RMI и современность

  • JMX
  • jconsole
  • jvisualvm

SOAP

Simple Object Access Protocol

SOAP

  • RPC
  • обмен сообщениями

SOAP

  • расширение XML-RPC
  • транспорт HTTP(S), SMTP, FTP, TCP, UDP
  • WSDL [Web Service Destribution Language]

SOAP RPC

encoded literal


  
    
      5
      5.0
    
  

        


  
    
      5
      5.0
    s
  

        

SOAP Document

Document RPC


    
        
        
    


    
    



    
        
        
    

        


    
    



    
        
        
    

        

SOAP минусы

  • избыточость информации
  • неторопливсть

SOAP плюсы

  • кроссплатформенность
  • расширяемость (WS-адресация)
  • нейтралитет (протоколы)
  • независимость (модель программирования)

SOAP примеры


import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;

@WebService
@SOAPBinding(style = SOAPBinding.Style.RPC)
public interface SOAPInterface {
    String sayHello(String name);
}
        

SOAP примеры


import javax.jws.WebService;

@WebService(endpointInterface = "ru.matmex.rpc.soap.SOAPInterface")
public class SOAPImpl implements SOAPInterface {
    @Override
    public String sayHello(String name) {
        return "Hello " + name + "!";
    }
}
        

SOAP примеры


import javax.xml.ws.Endpoint;

public class SOAPServer {

    public static void main(String... args) {
        Endpoint.publish("http://localhost:9999/ws/hello", new SOAPImpl());
    }

}
        

SOAP примеры


import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;

public class SOAPClient {
    public static void main(String... args) throws Exception {
        URL url = new URL("http://localhost:9999/ws/hello?wsdl");
        QName qname = new QName("http://soap.rpc.matmex.ru/", "SOAPImplService");
        Service service = Service.create(url, qname);
        SOAPInterface hello = service.getPort(SOAPInterface.class);
        System.out.println(hello.sayHello("Magaz"));
    }
}
        

SOAP примеры


wsimport -keep http://localhost:9999/ws/hello?wsdl
        

SOAP примеры


@WebServiceClient(name = "SOAPImplService",
                targetNamespace = "http://soap.rpc.matmex.ru/",
                wsdlLocation = "http://localhost:9999/ws/hello?wsdl")
public class SOAPImplService extends Service {/**/}

@WebService(name = "SOAPInterface", targetNamespace = "http://soap.rpc.matmex.ru/")
@SOAPBinding(style = SOAPBinding.Style.RPC)
public interface SOAPInterface {/**/}
        

SOAP примеры


public class SOAPClientWSImport {
    public static void main(String... args) {
        SOAPImplService helloService = new SOAPImplService();
        SOAPInterface hello = helloService.getSOAPImplPort();
        System.out.println(hello.sayHello("Magaz"));
    }
}
        

HTTP

HyperText Transfer Protocol

протокол передачи гипертекста

HTTP

  • протокол прикладного уровня
  • клиент-север, запрос-ответ

HTTP методы

  • GET
  • POST
  • PUT
  • DELETE
  • HEAD
  • OPTIONS

HTTP заголовки

  • Host
  • User-Agent
  • Accept
  • Content-Type
  • DoNotTrack

HTTP коды ответа

  • 1xx - информационные
  • 2xx - успешно
  • 3xx - перенаправление
  • 4xx - ошибка клиента
  • 5xx - ошибка сервера

HTTP запрос


GET /search?q=REST HTTP/2
Host: www.google.com
Accept-Encoding: deflate, gzip, br
User-Agent: Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:65.0) Gecko/20100101 Firefox/65.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3
Connection: keep-alive

HTTP ответ


HTTP/2 200 
content-type: text/html; charset=UTF-8
date: Tue, 12 Mar 2019 20:12:12 GMT
expires: -1
cache-control: private, max-age=0
trailer: X-Google-GFE-Current-Request-Cost-From-GWS
strict-transport-security: max-age=31536000
content-encoding: br
server: gws
x-xss-protection: 1; mode=block
x-frame-options: SAMEORIGIN

REST

Representational State Transfer

передача состояния представления

Требования к REST

  • Клиент-сервер
  • Отсутствие состояния
  • Кэширование
  • Единообразие интерфейса
    • Идентификация ресурсов
    • Манипуляция ресурсами через представление
    • «Самоописываемые» сообщения
    • Гипермедиа (HATEOAS)
  • Слои

Характеризуется

метод запроса GET, POST, DELETE
путь запроса /objects/list, /objects/100500
тело запросв форма, json, xml
код ответа 200 OK, 404 NotFound
тело ответа json, html, xml

REST и Java

  • JAX-RS
  • Spring Framework
  • и другое

JAX-RS

  • Java API for RESTful Web Services
  • JavaEE

JAX-RS аннотации

  • @Path
  • @GET, @PUT, @POST, @DELETE, @HEAD
  • @Produces
  • @Consumes

JAX-RS аннотации

  • @PathParam
  • @QueryParam
  • @HeaderParam
  • @CookieParam
  • @FormParam
  • @DefaultValue
  • @Context

SpringFramework

  • @RequestMapping
  • @GetMapping, @PostMapping, @PutMapping, @PatchMapping, @DeleteMapping

  • @PathVariable
  • @RequestAttribute
  • @RequestBody
  • @RequestParam
  • @SessionAttribute(s)

JAX-RS пример


@Path("/greetings")
public class JaxRsController {
    @GET
    @Path("/{name}")
    @Produces(MediaType.TEXT_PLAIN)
    public Response greeting(@PathParam("name") String name) {
        String greeting = "Hello " + name;
        return Response.ok(greeting).build();
    }
}
      

Spring пример 1


@RestController
@RequestMapping("/greetings")
public class SpringRestController {
    @RequestMapping(method = RequestMethod.GET,
                    value = "/{name}",
                    produces = MediaType.TEXT_PLAIN_VALUE)
    public ResponseEntity< ? > greeting(@PathVariable String name) {
        String greeting = "Hello " + name;
        return new ResponseEntity<>(greeting, HttpStatus.OK);
    }
}
      

Spring пример 2


@RestController
public class GreetingController {
    @RequestMapping("/greeting")
    public Greeting greeting(@RequestParam(value="name", defaultValue="World") String name) {
        return new Greeting("Hello " + name);
    }
}
      

Spring пример. Клиент


public static void main(String... args) {
    RestTemplate restTemplate = new RestTemplate();
    String message = restTemplate.getForObject("http://localhost/greetings/Bob", Sting.class);
    log.info(message);
    Greeting greeting = restTemplate.getForObject("http://localhost/greeting?name=Bob", Greeting.class);
    // {"message": "Hello Bob"}
    log.info(greeting.getMessage());
}
      

HATEOAS

Hypermedia as the Engine of Application State

  • клиент обращается к фиксированному URL
  • клиент может ничего не знать о сервере, кроме входящего URL

HATEOAS пример


{
  "content":"Hello, User!",
  "_links":{
    "self":{
      "href":"http://localhost:8080/greeting/User"
    },
    "farewell":{
      "href":"http://localhost:8080/farewell/User"
    }
  }
}
      

gRPC

  • Google
  • Protocol Buffers v3
  • HTTP/2

Protocol Buffers

  • протокол сериализации
  • проще, быстрее, однозначнее XML
  • необходима реализация под каждый язык

HTTP/2

  • только HTTPS
  • одно соединение для всех запросов

gRPC пример описания


service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}

Типы gRPC

  • Unary RPC
  • Server streaming RPC
  • Client streaming RPC
  • Bidirectional streaming

Что есть еще в gRPC

  • балансировка
  • Interceptors

gRPC клиент


public class HelloWorldClient {
  public static void main(String[] args) throws Exception {
    ManagedChannel channel = ManagedChannelBuilder
        .forAddress("localhost", 50051).usePlaintext().build();
    GreeterGrpc.GreeterBlockingStub blockingStub = GreeterGrpc.newBlockingStub(channel);
    try {
      HelloRequest request = HelloRequest.newBuilder().setName(name).build();
      HelloReply response;
      try {
        response = blockingStub.sayHello("Magaz");
      } catch (StatusRuntimeException e) {
        System.err.println("RPC failed: " + e.getStatus());return;
      }
      System.out.println("Greeting: " + response.getMessage());
    } finally {
      channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
    }
  }
}
        

gRPC сервер


import io.grpc.*;
import io.grpc.stub.StreamObserver;
import java.io.IOException;

public class HelloWorldServer {
  public static void main(String[] args) throws IOException, InterruptedException {
    Server server = ServerBuilder.forPort(50051)
            .addService(new GreeterImpl()).build().start();
    server.awaitTermination();
  }

  static class GreeterImpl extends GreeterGrpc.GreeterImplBase {
    @Override
    public void sayHello(HelloRequest req, StreamObserver< HelloReply > responseObserver) {
      HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName()).build();
      responseObserver.onNext(reply);
      responseObserver.onCompleted();
    }
  }
}
        

JMS

  • Это не RPC
  • Является частью JDK
  • Топики
  • Очереди

JMS основа


import javax.jms.*;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
class ConsumerOrProducer {
    public static void main(String[] args) throws JMSException {
        ConnectionFactory connectionFactory 
          = new ActiveMQConnectionFactory(ActiveMQConnection.DEFAULT_BROKER_URL);
        connection.start();
        Session session = connection
                      .createSession(false, Session.AUTO_ACKNOWLEDGE);
        Destination destination = null;
        if("QUEUE".equalsIgnoreCase(System.getProperties("amq"))) {        	
        	destination = session.createQueue("LolQueue");	
        }else{        	
        	destination = session.createTopic("LolTopik");        	
        }
        /*
        ........................................
        */
        connection.close();
    }
}
        

JMS прием


MessageConsumer consumer = session.createConsumer(destination);
String body;
do {
    Message msg = consumer.receive();
    body = ((TextMessage) msg).getText();
    
    System.out.println("Received = "+body);
    
}while (!body.equalsIgnoreCase("GoHome!"));
        

JMS отправка


        MessageProducer producer = session.createProducer(destination);
Console c = System.console();
String response;
do {
    
    response = c.readLine("Enter message: ");
    
    TextMessage msg = session.createTextMessage(response);
    producer.send(msg);
    
} while (!response.equalsIgnoreCase("GoHome!"));
        

Конец

вопросы