Improvements to the Jetty server documentation.
Added section on the components architecture. Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
This commit is contained in:
parent
72cb9bf3d8
commit
13094fa912
|
@ -0,0 +1,101 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under
|
||||
// the terms of the Eclipse Public License 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// This Source Code may also be made available under the following
|
||||
// Secondary Licenses when the conditions for such availability set
|
||||
// forth in the Eclipse Public License, v. 2.0 are satisfied:
|
||||
// the Apache License v2.0 which is available at
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
[[eg-arch-bean]]
|
||||
=== Jetty Component Architecture
|
||||
|
||||
Applications that use the Jetty libraries (both client and server) create objects from Jetty classes and compose them together to obtain the desired functionalities.
|
||||
|
||||
A client application creates a `ClientConnector` instance, a `HttpClientTransport` instance and an `HttpClient` instance and compose them to have a working HTTP client that uses to call third party services.
|
||||
|
||||
A server application creates a `ThreadPool` instance, a `Server` instance, a `ServerConnector` instance, a `Handler` instance and compose them together to expose an HTTP service.
|
||||
|
||||
Internally, the Jetty libraries create even more instances of other components that also are composed together with the main ones created by applications.
|
||||
|
||||
The end result is that an application based on the Jetty libraries is a _tree_ of components.
|
||||
In server application the root of the component tree is a `Server` instance, while in client applications the root of the component tree is an `HttpClient` instance.
|
||||
|
||||
Having all the Jetty components in a tree is beneficial in a number of use cases.
|
||||
It makes possible to register the components in the tree as JMX MBeans (TODO: xref the JMX section) so that a JMX console can look at the internal state of the components.
|
||||
It also makes possible to dump the component tree (and therefore each component's internal state) to a log file or to the console for troubleshooting purposes (TODO: xref troubleshooting section).
|
||||
|
||||
[[eg-arch-bean-lifecycle]]
|
||||
==== Jetty Component Lifecycle
|
||||
|
||||
Jetty components typically have a life cycle: they can be started and stopped.
|
||||
The Jetty components that have a life cycle implement the `org.eclipse.jetty.util.component.LifeCycle` interface.
|
||||
|
||||
Jetty components that contain other components extend the `org.eclipse.jetty.util.component.ContainerLifeCycle` class.
|
||||
`ContainerLifeCycle` can contain these type of components, also called __bean__s:
|
||||
|
||||
* _managed_ beans, `LifeCycle` instances whose life cycle is tied to the life cycle of their container
|
||||
* _unmanaged_ beans, `LifeCycle` instances whose life cycle is _not_ tied to the life cycle of their container
|
||||
* _POJO_ (Plain Old Java Object) beans, instances that do not implement `LifeCycle`
|
||||
|
||||
`ContainerLifeCycle` uses the following logic to determine if a bean should be _managed_, _unmanaged_ or _POJO_:
|
||||
|
||||
* the bean implements `LifeCycle`
|
||||
** the bean is not started, add it as _managed_
|
||||
** the bean is started, add it as _unmanaged_
|
||||
* the bean does not implement `LifeCycle`, add it as _POJO_
|
||||
|
||||
When a `ContainerLifeCycle` is started, it also starts recursively all its managed beans (if they implement `LifeCycle`); unmanaged beans are not started during the `ContainerLifeCycle` start cycle.
|
||||
Likewise, stopping a `ContainerLifeCycle` stops recursively and in reverse order all its managed beans; unmanaged beans are not stopped during the `ContainerLifeCycle` stop cycle.
|
||||
|
||||
Components can also be started and stopped individually, therefore activating or deactivating the functionalities that they offer.
|
||||
|
||||
Applications should first compose components in the desired structure, and then start the root component:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::{doc_code}/embedded/ComponentDocs.java[tags=start]
|
||||
----
|
||||
|
||||
The component tree is the following:
|
||||
|
||||
[source,screen]
|
||||
----
|
||||
Root
|
||||
├── Monitor (MANAGED)
|
||||
└── Service (MANAGED)
|
||||
└── ScheduledExecutorService (POJO)
|
||||
----
|
||||
|
||||
When the `Root` instance is created, also the `Monitor` instance is created and added as bean, so `Monitor` is the first bean of `Root`.
|
||||
`Monitor` is a _managed_ bean, because it has been explicitly added to `Root` via `ContainerLifeCycle.addManaged(...)`.
|
||||
|
||||
Then, the application creates a `Service` instance and adds it to `Root` via `ContainerLifeCycle.addBean(...)`, so `Service` is the second bean of `Root`.
|
||||
`Service` is a _managed_ bean too, because it is a `LifeCycle` and at the time it was added to `Root` is was not started.
|
||||
|
||||
The `ScheduledExecutorService` within `Service` does not implement `LifeCycle` so it is added as a _POJO_ to `Service`.
|
||||
|
||||
It is possible to stop and re-start any component in a tree, for example:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::{doc_code}/embedded/ComponentDocs.java[tags=restart]
|
||||
----
|
||||
|
||||
`Service` can be stopped independently of `Root`, and re-started.
|
||||
Starting and stopping a non-root component does not alter the structure of the component tree, just the state of the subtree starting from the component that has been stopped and re-started.
|
||||
|
||||
[[eg-arch-bean-listener]]
|
||||
==== Jetty Component Listeners
|
||||
|
||||
// TODO: LifeCycle.Listener
|
||||
// TODO: Container.Listener + InheritedListener
|
|
@ -16,14 +16,13 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
[appendix]
|
||||
[[eg-io-arch]]
|
||||
== Jetty I/O Architecture
|
||||
[[eg-arch-io]]
|
||||
=== Jetty I/O Architecture
|
||||
|
||||
Jetty libraries (both client and server) use Java NIO to handle I/O, so that at its core Jetty I/O is completely non-blocking.
|
||||
|
||||
[[eg-io-arch-selector-manager]]
|
||||
=== Jetty I/O: `SelectorManager`
|
||||
[[eg-arch-io-selector-manager]]
|
||||
==== Jetty I/O: `SelectorManager`
|
||||
|
||||
The core class of Jetty I/O is link:{JDURL}/org/eclipse/jetty/io/SelectorManager.html[`SelectorManager`].
|
||||
|
||||
|
@ -51,8 +50,8 @@ This example shows how a server accepts a client connection:
|
|||
include::{doc_code}/embedded/SelectorManagerDocs.java[tags=accept]
|
||||
----
|
||||
|
||||
[[eg-io-arch-endpoint-connection]]
|
||||
=== Jetty I/O: `EndPoint` and `Connection`
|
||||
[[eg-arch-io-endpoint-connection]]
|
||||
==== Jetty I/O: `EndPoint` and `Connection`
|
||||
|
||||
``SocketChannel``s that are passed to `SelectorManager` are wrapped into two related components: an link:{JDURL}/org/eclipse/jetty/io/EndPoint.html[`EndPoint`] and a link:{JDURL}/org/eclipse/jetty/io/Connection.html[`Connection`].
|
||||
|
||||
|
@ -85,8 +84,8 @@ On the server-side, the component that aggregates a `SelectorManager` with a set
|
|||
|
||||
On the client-side, the components that aggregates a `SelectorManager` with a set of ``ClientConnectionFactory``s are link:{JDURL}/org/eclipse/jetty/client/HttpClientTransport.html[`HttpClientTransport`] subclasses, see xref:eg-client-io-arch[].
|
||||
|
||||
[[eg-io-arch-endpoint]]
|
||||
=== Jetty I/O: `EndPoint`
|
||||
[[eg-arch-io-endpoint]]
|
||||
==== Jetty I/O: `EndPoint`
|
||||
|
||||
The Jetty I/O library use Java NIO to handle I/O, so that I/O is non-blocking.
|
||||
|
||||
|
@ -100,10 +99,10 @@ In order to be notified when a `SocketChannel` uncongests and it is therefore wr
|
|||
In the Jetty I/O library, you can call `EndPoint.write(Callback, ByteBuffer...)` to write the ``ByteBuffer``s and the `Callback` parameter is the object that is notified when the whole write is finished (i.e. _all_ ``ByteBuffer``s have been fully written, even if they are delayed by TCP congestion/uncongestion).
|
||||
|
||||
The `EndPoint` APIs abstract out the Java NIO details by providing non-blocking APIs based on `Callback` objects for I/O operations.
|
||||
The `EndPoint` APIs are typically called by `Connection` implementations, see xref:eg-io-arch-connection[this section].
|
||||
The `EndPoint` APIs are typically called by `Connection` implementations, see xref:eg-arch-io-connection[this section].
|
||||
|
||||
[[eg-io-arch-connection]]
|
||||
=== Jetty I/O: `Connection`
|
||||
[[eg-arch-io-connection]]
|
||||
==== Jetty I/O: `Connection`
|
||||
|
||||
`Connection` is the abstraction that deserializes incoming bytes into objects, for example a HTTP request object or a WebSocket frame object, that can be used by more abstract layers.
|
||||
|
||||
|
@ -123,10 +122,13 @@ The example below shows a typical implementation that extends `AbstractConnectio
|
|||
include::{doc_code}/embedded/SelectorManagerDocs.java[tags=connection]
|
||||
----
|
||||
|
||||
[[eg-arch-io-connection-listener]]
|
||||
===== Jetty I/O: `Connection.Listener`
|
||||
|
||||
// TODO: Introduce Connection.Listener
|
||||
|
||||
[[eg-io-arch-echo]]
|
||||
=== Jetty I/O: Network Echo
|
||||
[[eg-arch-io-echo]]
|
||||
==== Jetty I/O: Network Echo
|
||||
|
||||
With the concepts above it is now possible to write a simple, fully non-blocking, `Connection` implementation that simply echoes the bytes that it reads back to the other peer.
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under
|
||||
// the terms of the Eclipse Public License 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// This Source Code may also be made available under the following
|
||||
// Secondary Licenses when the conditions for such availability set
|
||||
// forth in the Eclipse Public License, v. 2.0 are satisfied:
|
||||
// the Apache License v2.0 which is available at
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
[[eg-arch-listener]]
|
||||
=== Jetty Listeners
|
||||
|
||||
The Jetty architecture is based on xref:eg-arch-bean[components], typically organized in a component tree.
|
||||
These components have an internal state that varies with the component life cycle (that is, whether the component is started or stopped), as well as with the component use at runtime.
|
||||
The typical example is a thread pool, whose internal state -- such as the number of pooled threads or the job queue size -- changes as the thread pool is used by the running client or server.
|
||||
|
||||
In many cases, the component state change produces an event that is broadcast to listeners.
|
||||
Applications can register listeners to these components to be notified of the events they produce.
|
||||
|
||||
This section lists the listeners available in the Jetty components, but the events and listener APIs are discussed in the component specific sections.
|
||||
|
||||
* xref:eg-arch-bean-listener[]
|
||||
* xref:eg-arch-io-connection-listener[]
|
||||
* xref:eg-server-http-channel-events[]
|
|
@ -0,0 +1,25 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under
|
||||
// the terms of the Eclipse Public License 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// This Source Code may also be made available under the following
|
||||
// Secondary Licenses when the conditions for such availability set
|
||||
// forth in the Eclipse Public License, v. 2.0 are satisfied:
|
||||
// the Apache License v2.0 which is available at
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
[appendix]
|
||||
[[eg-arch]]
|
||||
== Jetty Architecture
|
||||
|
||||
include::arch-bean.adoc[]
|
||||
include::arch-listener.adoc[]
|
||||
include::arch-io.adoc[]
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
The Jetty client libraries provide the basic components and APIs to implement a network client.
|
||||
|
||||
They build on the common xref:eg-io-arch[Jetty I/O Architecture] and provide client specific concepts (such as establishing a connection to a server).
|
||||
They build on the common xref:eg-arch-io[Jetty I/O Architecture] and provide client specific concepts (such as establishing a connection to a server).
|
||||
|
||||
There are conceptually two layers that compose the Jetty client libraries:
|
||||
|
||||
|
@ -31,7 +31,7 @@ There are conceptually two layers that compose the Jetty client libraries:
|
|||
[[eg-client-io-arch-network]]
|
||||
==== Client Libraries Network Layer
|
||||
|
||||
The Jetty client libraries use the common I/O design described in link:#eg-io-arch[this section].
|
||||
The Jetty client libraries use the common I/O design described in link:#eg-arch-io[this section].
|
||||
The main client-side component is the link:{JDURL}/org/eclipse/jetty/io/ClientConnector.html[`ClientConnector`].
|
||||
|
||||
The `ClientConnector` primarily wraps the link:{JDURL}/org/eclipse/jetty/io/SelectorManager.html[`SelectorManager`] and aggregates other four components:
|
||||
|
@ -88,7 +88,7 @@ Please refer to the `ClientConnector` link:{JDURL}/org/eclipse/jetty/io/ClientCo
|
|||
|
||||
The protocol layer builds on top of the network layer to generate the bytes to be written to the network and to parse the bytes read from the network.
|
||||
|
||||
Recall from link:#eg-io-arch-connection[this section] that Jetty uses the `Connection` abstraction to produce and interpret the network bytes.
|
||||
Recall from link:#eg-arch-io-connection[this section] that Jetty uses the `Connection` abstraction to produce and interpret the network bytes.
|
||||
|
||||
On the client side, a `ClientConnectionFactory` implementation is the component that creates `Connection` instances based on the protocol that the client wants to "speak" with the server.
|
||||
|
||||
|
|
|
@ -59,4 +59,4 @@ endif::[]
|
|||
include::.asciidoctorconfig[]
|
||||
include::client/client.adoc[]
|
||||
include::server/server.adoc[]
|
||||
include::io-arch.adoc[]
|
||||
include::arch.adoc[]
|
||||
|
|
|
@ -31,13 +31,13 @@ include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=configur
|
|||
----
|
||||
|
||||
The _acceptors_ are threads (typically only one) that compete to accept TCP connections on the listening port.
|
||||
When a connection is accepted, `ServerConnector` wraps the accepted `SocketChannel` and passes it to the xref:eg-io-arch-selector-manager[`SelectorManager`].
|
||||
When a connection is accepted, `ServerConnector` wraps the accepted `SocketChannel` and passes it to the xref:eg-arch-io-selector-manager[`SelectorManager`].
|
||||
Therefore, there is a little moment where the acceptor thread is not accepting new connections because it is busy wrapping the just accepted one to pass it to the `SelectorManager`.
|
||||
Connections that are ready to be accepted but are not accepted yet are queued in a bounded queue (at the OS level) whose capacity can be configured with the `ServerConnector.acceptQueueSize` parameter.
|
||||
|
||||
If your application must withstand a very high rate of connections opened, configuring more than one acceptor thread may be beneficial: when one acceptor thread accepts one connection, another acceptor thread can take over accepting connections.
|
||||
|
||||
The _selectors_ are components that manage a set of connected sockets, implemented by xref:eg-io-arch-selector-manager[`ManagedSelector`].
|
||||
The _selectors_ are components that manage a set of connected sockets, implemented by xref:eg-arch-io-selector-manager[`ManagedSelector`].
|
||||
Each selector requires one thread and uses the Java NIO mechanism to efficiently handle the set of connected sockets.
|
||||
As a rule of thumb, a single selector can easily manage up to 1000-5000 sockets, although the number may vary greatly depending on the application.
|
||||
|
||||
|
@ -56,7 +56,7 @@ include::../../{doc_code}/embedded/server/http/HTTPServerDocs.java[tags=configur
|
|||
[[eg-server-http-connector-protocol]]
|
||||
==== Configuring Protocols
|
||||
|
||||
For each accepted TCP connection, `ServerConnector` asks a `ConnectionFactory` to create a `Connection` object that handles the network traffic on that TCP connection, parsing and generating bytes for a specific protocol (see xref:eg-io-arch[this section] for more details about `Connection` objects).
|
||||
For each accepted TCP connection, `ServerConnector` asks a `ConnectionFactory` to create a `Connection` object that handles the network traffic on that TCP connection, parsing and generating bytes for a specific protocol (see xref:eg-arch-io[this section] for more details about `Connection` objects).
|
||||
|
||||
A `ServerConnector` can be configured with one or more ``ConnectionFactory``s.
|
||||
If no `ConnectionFactory` is specified then `HttpConnectionFactory` is implicitly configured.
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
The Jetty server libraries provide the basic components and APIs to implement a network server.
|
||||
|
||||
They build on the common xref:eg-io-arch[Jetty I/O Architecture] and provide server specific concepts.
|
||||
They build on the common xref:eg-arch-io[Jetty I/O Architecture] and provide server specific concepts.
|
||||
|
||||
The main I/O server-side class is `org.eclipse.jetty.server.ServerConnector`.
|
||||
|
||||
|
|
|
@ -33,8 +33,6 @@ The Jetty server-side libraries provide:
|
|||
* HTTP/2 low-level support, for applications that want to explicitly handle low-level HTTP/2 _sessions_, _streams_ and _frames_, via the xref:eg-server-http2[HTTP/2 libraries]
|
||||
* WebSocket support, for applications that want to embed a WebSocket server, via the xref:eg-server-websocket[WebSocket libraries]
|
||||
|
||||
// TODO: add a section on lifecycle and the component tree.
|
||||
|
||||
include::http/server-http.adoc[]
|
||||
include::http2/server-http2.adoc[]
|
||||
include::websocket/server-websocket.adoc[]
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under
|
||||
// the terms of the Eclipse Public License 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// This Source Code may also be made available under the following
|
||||
// Secondary Licenses when the conditions for such availability set
|
||||
// forth in the Eclipse Public License, v. 2.0 are satisfied:
|
||||
// the Apache License v2.0 which is available at
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package embedded;
|
||||
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class ComponentDocs
|
||||
{
|
||||
public void start() throws Exception
|
||||
{
|
||||
// tag::start[]
|
||||
class Monitor extends AbstractLifeCycle
|
||||
{
|
||||
}
|
||||
|
||||
class Root extends ContainerLifeCycle
|
||||
{
|
||||
// Monitor is an internal component.
|
||||
private final Monitor monitor = new Monitor();
|
||||
|
||||
public Root()
|
||||
{
|
||||
// The Monitor life cycle is managed by Root.
|
||||
addManaged(monitor);
|
||||
}
|
||||
}
|
||||
|
||||
class Service extends ContainerLifeCycle
|
||||
{
|
||||
// An instance of the Java scheduler service.
|
||||
private ScheduledExecutorService scheduler;
|
||||
|
||||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
// Java's schedulers cannot be restarted, so they must
|
||||
// be created anew every time their container is started.
|
||||
scheduler = Executors.newSingleThreadScheduledExecutor();
|
||||
// Even if Java scheduler does not implement
|
||||
// LifeCycle, make it part of the component tree.
|
||||
addBean(scheduler);
|
||||
// Start all the children beans.
|
||||
super.doStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStop() throws Exception
|
||||
{
|
||||
// Perform the opposite operations that were
|
||||
// performed in doStart(), in reverse order.
|
||||
super.doStop();
|
||||
removeBean(scheduler);
|
||||
scheduler.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
// Create a Root instance.
|
||||
Root root = new Root();
|
||||
|
||||
// Create a Service instance.
|
||||
Service service = new Service();
|
||||
|
||||
// Link the components.
|
||||
root.addBean(service);
|
||||
|
||||
// Start the root component to
|
||||
// start the whole component tree.
|
||||
root.start();
|
||||
// end::start[]
|
||||
}
|
||||
|
||||
public void restart() throws Exception
|
||||
{
|
||||
// tag::restart[]
|
||||
class Root extends ContainerLifeCycle
|
||||
{
|
||||
}
|
||||
|
||||
class Service extends ContainerLifeCycle
|
||||
{
|
||||
// An instance of the Java scheduler service.
|
||||
private ScheduledExecutorService scheduler;
|
||||
|
||||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
// Java's schedulers cannot be restarted, so they must
|
||||
// be created anew every time their container is started.
|
||||
scheduler = Executors.newSingleThreadScheduledExecutor();
|
||||
// Even if Java scheduler does not implement
|
||||
// LifeCycle, make it part of the component tree.
|
||||
addBean(scheduler);
|
||||
// Start all the children beans.
|
||||
super.doStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStop() throws Exception
|
||||
{
|
||||
// Perform the opposite operations that were
|
||||
// performed in doStart(), in reverse order.
|
||||
super.doStop();
|
||||
removeBean(scheduler);
|
||||
scheduler.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
Root root = new Root();
|
||||
Service service = new Service();
|
||||
root.addBean(service);
|
||||
|
||||
// Start the Root component.
|
||||
root.start();
|
||||
|
||||
// Stop temporarily Service without stopping the Root.
|
||||
service.stop();
|
||||
|
||||
// Restart Service.
|
||||
service.start();
|
||||
// end::restart[]
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue