1
1
[[databuffers]]
2
2
= Data Buffers and Codecs
3
3
4
-
5
-
6
-
7
- == Introduction
8
-
9
4
The `DataBuffer` interface defines an abstraction over byte buffers.
10
- The main reason for introducing it, and not use the standard `java.nio.ByteBuffer` instead, is Netty.
11
- Netty does not use `ByteBuffer`, but instead offers `ByteBuf` as an alternative.
5
+ The main reason for introducing it ( and not using the standard `java.nio.ByteBuffer` instead) is Netty.
6
+ Netty does not use `ByteBuffer` but instead offers `ByteBuf` as an alternative.
12
7
Spring's `DataBuffer` is a simple abstraction over `ByteBuf` that can also be used on non-Netty
13
- platforms (i.e. Servlet 3.1+).
14
-
8
+ platforms (that is, Servlet 3.1+).
15
9
16
10
17
11
18
12
== `DataBufferFactory`
19
13
20
- The `DataBufferFactory` offers functionality to allocate new data buffers, as well as to wrap
14
+ The `DataBufferFactory` offers functionality to allocate new data buffers as well as to wrap
21
15
existing data.
22
- The `allocate ` methods allocate a new data buffer, with a default or given capacity.
23
- Though `DataBuffer` implementation grow and shrink on demand, it is more efficient to give the
16
+ The `allocateBuffer ` methods allocate a new data buffer with a default or given capacity.
17
+ Though `DataBuffer` implementations grow and shrink on demand, it is more efficient to give the
24
18
capacity upfront, if known.
25
19
The `wrap` methods decorate an existing `ByteBuffer` or byte array.
26
- Wrapping does not involve allocation: it simply decorates the given data with a `DataBuffer`
20
+ Wrapping does not involve allocation. It decorates the given data with a `DataBuffer`
27
21
implementation.
28
22
29
- There are two implementation of `DataBufferFactory`: the `NettyDataBufferFactory` which is meant
30
- to be used on Netty platforms, such as Reactor Netty.
31
- The other implementation, the `DefaultDataBufferFactory`, is used on other platforms, such as
32
- Servlet 3.1+ servers.
33
-
23
+ There are two implementation of `DataBufferFactory`: the `NettyDataBufferFactory`
24
+ (for Netty platforms, such as Reactor Netty) and
25
+ `DefaultDataBufferFactory` (for other platforms, such as
26
+ Servlet 3.1+ servers).
34
27
35
28
36
29
37
- == The `DataBuffer` interface
30
+ == The `DataBuffer` Interface
38
31
39
- The `DataBuffer` interface is similar to `ByteBuffer`, but offers a number of advantages.
32
+ The `DataBuffer` interface is similar to `ByteBuffer` but offers a number of advantages.
40
33
Similar to Netty's `ByteBuf`, the `DataBuffer` abstraction offers independent read and write
41
34
positions.
42
- This is different from the JDK's `ByteBuffer`, which only exposes one position for both reading and
43
- writing, and a separate `flip()` operation to switch between the two I/O operations.
35
+ This is different from the JDK's `ByteBuffer`, which exposes only one position for both reading and
36
+ writing and a separate `flip()` operation to switch between the two I/O operations.
44
37
In general, the following invariant holds for the read position, write position, and the capacity:
45
38
39
+ ====
46
40
[literal]
47
41
[subs="verbatim,quotes"]
48
42
--
49
43
0 <= read position <= write position <= capacity
50
44
--
45
+ ====
51
46
52
47
When reading bytes from the `DataBuffer`, the read position is automatically updated in accordance with
53
48
the amount of data read from the buffer.
54
49
Similarly, when writing bytes to the `DataBuffer`, the write position is updated with the amount of
55
50
data written to the buffer.
56
- Also, when writing data, the capacity of a `DataBuffer` is automatically expanded, just like `StringBuilder`,
51
+ Also, when writing data, the capacity of a `DataBuffer` is automatically expanded, in the same fashion as `StringBuilder`,
57
52
`ArrayList`, and similar types.
58
53
59
54
Besides the reading and writing functionality mentioned above, the `DataBuffer` also has methods to
60
- view a (slice of a) buffer as `ByteBuffer`, `InputStream`, or `OutputStream`.
55
+ view a (slice of a) buffer as a `ByteBuffer`, an `InputStream`, or an `OutputStream`.
61
56
Additionally, it offers methods to determine the index of a given byte.
62
57
63
- There are two implementation of `DataBuffer `: the `NettyDataBuffer` which is meant to be used on
64
- Netty platforms, such as Reactor Netty.
65
- The other implementation, the `DefaultDataBuffer`, is used on other platforms, such as Servlet 3.1+
66
- servers.
58
+ As mentioned earlier, there are two implementation of `DataBufferFactory `: the `NettyDataBufferFactory`
59
+ (for Netty platforms, such as Reactor Netty) and
60
+ `DefaultDataBufferFactory` (for other platforms, such as
61
+ Servlet 3.1+ servers) .
67
62
68
63
69
64
70
65
=== `PooledDataBuffer`
71
66
72
67
The `PooledDataBuffer` is an extension to `DataBuffer` that adds methods for reference counting.
73
68
The `retain` method increases the reference count by one.
74
- The `release` method decreases the count by one, and releases the buffer's memory when the count
69
+ The `release` method decreases the count by one and releases the buffer's memory when the count
75
70
reaches 0.
76
- Both of these methods are related to _reference counting_ , a mechanism that is explained below .
71
+ Both of these methods are related to reference counting , a mechanism that we explain <<databuffer-reference-counting,later>> .
77
72
78
73
Note that `DataBufferUtils` offers useful utility methods for releasing and retaining pooled data
79
74
buffers.
80
- These methods take a plain `DataBuffer` as parameter, but only call `retain` or `release` if the
75
+ These methods take a plain `DataBuffer` as a parameter but only call `retain` or `release` if the
81
76
passed data buffer is an instance of `PooledDataBuffer`.
82
77
83
78
84
79
[[databuffer-reference-counting]]
85
80
==== Reference Counting
86
81
87
- Reference counting is not a common technique in Java; it is much more common in other programming
88
- languages such as Object C and C++.
89
- In and of itself, reference counting is not complex: it basically involves tracking the number of
82
+ Reference counting is not a common technique in Java. It is much more common in other programming
83
+ languages, such as Object C and C++.
84
+ In and of itself, reference counting is not complex. It basically involves tracking the number of
90
85
references that apply to an object.
91
86
The reference count of a `PooledDataBuffer` starts at 1, is incremented by calling `retain`,
92
- and decremented by calling `release`.
93
- As long as the buffer's reference count is larger than 0 the buffer will not be released.
94
- When the number decreases to 0, the instance will be released.
95
- In practice, this means that the reserved memory captured by the buffer will be returned back to
87
+ and is decremented by calling `release`.
88
+ As long as the buffer's reference count is larger than 0, the buffer is not released.
89
+ When the number decreases to 0, the instance is released.
90
+ In practice, this means that the reserved memory captured by the buffer is returned back to
96
91
the memory pool, ready to be used for future allocations.
97
92
98
- In general, _the last component to access a `DataBuffer` is responsible for releasing it_ .
93
+ In general, the last component to access a `DataBuffer` is responsible for releasing it .
99
94
Within Spring, there are two sorts of components that release buffers: decoders and transports.
100
- Decoders are responsible for transforming a stream of buffers into other types (see <<codecs>> below ),
101
- and transports are responsible for sending buffers across a network boundary, typically as an HTTP message.
102
- This means that if you allocate data buffers for the purpose of putting them into an outbound HTTP
103
- message (i.e. client-side request or server-side response), they do not have to be released.
95
+ Decoders are responsible for transforming a stream of buffers into other types (see <<codecs>>),
96
+ and transports are responsible for sending buffers across a network boundary, typically as an HTTP message.
97
+ This means that, if you allocate data buffers for the purpose of putting them into an outbound HTTP
98
+ message (that is, a client-side request or server-side response), they do not have to be released.
104
99
The other consequence of this rule is that if you allocate data buffers that do not end up in the
105
- body, for instance because of a thrown exception, you will have to release them yourself.
100
+ body ( for instance, because of a thrown exception) , you have to release them yourself.
106
101
The following snippet shows a typical `DataBuffer` usage scenario when dealing with methods that
107
102
throw exceptions:
108
103
104
+ ====
109
105
[source,java,indent=0]
110
106
[subs="verbatim,quotes"]
111
107
----
@@ -130,46 +126,49 @@ throw exceptions:
130
126
131
127
<1> A new buffer is allocated.
132
128
<2> A boolean flag indicates whether the allocated buffer should be released.
133
- <3> This example method loads data into the buffer. Note that the method can throw an `IOException`,
134
- and therefore a `finally` block to release the buffer is required.
135
- <4> If no exception occurred, we switch the `release` flag to `false` as the buffer will now be
129
+ <3> This example method loads data into the buffer. Note that the method can throw an `IOException`.
130
+ Therefore, a `finally` block to release the buffer is required.
131
+ <4> If no exception occurred, we switch the `release` flag to `false` as the buffer is now
136
132
released as part of sending the HTTP body across the wire.
137
- <5> If an exception did occur, the flag is still set to `true`, and the buffer will be released
133
+ <5> If an exception did occur, the flag is still set to `true`, and the buffer is released
138
134
here.
135
+ ====
139
136
140
137
141
138
142
- === DataBufferUtils
139
+ === ` DataBufferUtils`
143
140
144
- `DataBufferUtils` contains various utility methods that operate on data buffers.
141
+ The `DataBufferUtils` class contains various utility methods that operate on data buffers.
145
142
It contains methods for reading a `Flux` of `DataBuffer` objects from an `InputStream` or NIO
146
- `Channel`, and methods for writing a data buffer `Flux` to an `OutputStream` or `Channel`.
143
+ `Channel` and methods for writing a data buffer `Flux` to an `OutputStream` or `Channel`.
147
144
`DataBufferUtils` also exposes `retain` and `release` methods that operate on plain `DataBuffer`
148
145
instances (so that casting to a `PooledDataBuffer` is not required).
149
146
150
147
Additionally, `DataBufferUtils` exposes `compose`, which merges a stream of data buffers into one.
151
148
For instance, this method can be used to convert the entire HTTP body into a single buffer (and
152
- from that, a `String`, or `InputStream`).
149
+ from that, a `String` or `InputStream`).
153
150
This is particularly useful when dealing with older, blocking APIs.
154
151
Note, however, that this puts the entire body in memory, and therefore uses more memory than a pure
155
152
streaming solution would.
156
153
157
- [codecs]
154
+
155
+
156
+ [[codecs]]
158
157
== Codecs
159
158
160
159
The `org.springframework.core.codec` package contains the two main abstractions for converting a
161
- stream of bytes into a stream of objects, or vice-versa.
160
+ stream of bytes into a stream of objects or vice-versa.
162
161
The `Encoder` is a strategy interface that encodes a stream of objects into an output stream of
163
162
data buffers.
164
- The `Decoder` does the reverse: it turns a stream of data buffers into a stream of objects.
165
- Note that a decoder instance needs to consider <<databuffer-reference-counting, reference counting>>.
163
+ The `Decoder` does the reverse: It turns a stream of data buffers into a stream of objects.
164
+ Note that a decoder instance needs to consider <<databuffer-reference-counting,reference counting>>.
166
165
167
- Spring comes with a wide array of default codecs, capable of converting from/ to `String`,
168
- `ByteBuffer`, byte arrays, and also codecs that support marshalling libraries such as JAXB and
166
+ Spring comes with a wide array of default codecs (to convert from and to `String`,
167
+ `ByteBuffer`, and byte arrays) and codecs that support marshalling libraries such as JAXB and
169
168
Jackson (with https://github.com/FasterXML/jackson-core/issues/57[Jackson 2.9+ support for non-blocking parsing]).
170
169
Within the context of Spring WebFlux, codecs are used to convert the request body into a
171
- `@RequestMapping` parameter, or to convert the return type into the response body that is sent back
170
+ `@RequestMapping` parameter or to convert the return type into the response body that is sent back
172
171
to the client.
173
- The default codecs are configured in the `WebFluxConfigurationSupport` class, and can easily be
174
- changed by overriding the `configureHttpMessageCodecs` when inheriting from that class.
175
- For more information about using codecs in WebFlux, see <<web-reactive#webflux-codecs, this section >>.
172
+ The default codecs are configured in the `WebFluxConfigurationSupport` class. You can
173
+ change them by overriding the `configureHttpMessageCodecs` when you inherit from that class.
174
+ For more information about using codecs in WebFlux, see <<web-reactive#webflux-codecs>>.
0 commit comments