10. ์ง๋ ฌํ
by JiwonDev2021.08.04 - [๐๊ธฐ๋ณธ ์ง์/Java ๊ธฐ๋ณธ์ง์] - ์๋ฐ์ ์ง๋ ฌํ(Serialization)๋?
# ์ง๋ ฌํ์ ๋์์ ์ฐพ์๋ผ.
์ง๋ ฌํ๋ ๋ณด์์ ์ทจ์ฝํ๊ณ , ๊ณต๊ฒฉํ ์์๊ฐ ๋๋ฌด ๋ง๋ค.
์ด๋ ์๋ ์์ ์ด์ผ๊ธฐ๊ฐ ์๋๋ค. 2016๋ 11์ ์ํ๋์์ค์ฝ ๊ตํต๊ตญ์์๋ ์ง๋ ฌํ๋ก ์ธํ ์ฝ๋ ์ฝ์ ๋๋ฌธ์ ๋์ฌ์จ์ด ๊ณต๊ฒฉ์ ๋ฐ์ ์๊ธ ์ง์ ์์คํ ์ด ์ดํ๊ฐ ๋ง๋น๋๊ธฐ๋ ํ์๋ค.
์ง๋ ฌํ์ ๊ทผ๋ณธ์ ์ธ ๋ฌธ์ ๋ ๊ณต๊ฒฉ ๋ฒ์๊ฐ ๋๋ฌด ๋๊ณ , ๋ฐฉ์ดํ๊ธฐ ์ด๋ ต๋ค๋๋ฐ์ ์๋ค. ์ญ์ง๋ ฌํ๋ฅผ ์ด์ฉํ๋ฉด ๊ฑฐ์ ๋ชจ๋ ํ์ ์ ๊ฐ์ฒด๋ฅผ ์์ฑํด๋ผ ์ ์๋ ๋ง๋ฒ์ ํด๋์ค๊ฐ ๋๋ฉฐ, ์ด๋ฅผ ๋ง๋๋ค๊ณ ํ๋ค ์ญ์ง๋ ฌํ๋ฅผ ์งํํ๋ ๊ฐ์ฒด ์ฒด์ธ์ ๋ฌดํ๋ฐ๋ณตํ๊ฒ ๋ง๋ค์ด ์์คํ ์ ๋ป์ด๋ฒ๋ฆฌ๊ฒ ๋ง๋ค ์๋ ์๋ค.
// ์ญ์ง๋ ฌํ ํญํ(deserialization bomb), hashCode ๋ฉ์๋๋ฅผ 2^100๋ฒ์ ๋ ํธ์ถํ๊ฒ ๋๋ค.
static byte[] bomb() {
Set<Object> root = new HashSet<>();
Set<Object> s1 = root;
Set<Object> s2 = new HashSet<>();
for (int i=0; i < 100; i++) {
Set<Object> t1 = new HashSet<>();
Set<Object> t2 = new HashSet<>();
t1.add("foo"); // t1์ t2๊ณผ ๋ค๋ฅด๊ฒ ๋ง๋ ๋ค.
s1.add(t1); s1.add(t2);
s2.add(t1); s2.add(t2);
s1 = t1; s2 = t2;
}
return serialize(root);
}
์ด์ธ์๋ ์์ฑ์๋ ์๋ฉธ์(finalizer)๋ฅผ ์ฝ์ ํ๋ ๊ณต๊ฒฉ, ๊ฐ์ฒด์ ํ๋์์๊ฐ ๋ฐ๋๋ฉด ์ง๋ ฌํ๊ฐ ๊นจ์ง๋ ๋ฌธ์ ๋ฑ์ด ์๋ค.
์ง๋ ฌํ์ ์ํ์ฑ์ ํผํ๋ ๊ฐ์ ์ข์ ๋ฐฉ๋ฒ์ '์๋ฌด ๊ฒ๋ ์ญ์ง๋ ฌํ ํ์ง ์๋ ๊ฒ' ์ด๋ค. ๊ผญ ํ์ํ๋ค๋ฉด ์ ๋ขฐํ ์ ์๋ ๋ฐ์ดํฐ๋ง ์ง๋ ฌํ ํ ์ ์๋๋ก [Java9์ ์ถ๊ฐ๋ ๊ฐ์ฒด ์ญ์ง๋ ฌํ ํํฐ๋ง]๋ฑ์ ์ฌ์ฉํด๋ณด์. ๋ฐ์ดํฐ ์คํธ๋ฆผ์ด ์ง๋ ฌํ ๋๊ธฐ์ ์ ํน์ ํด๋์ค๋ง ์์ฉ/ ์ ์ธํ๋๋ก ํ ์ ์๋ค.
์ง๋ ฌํ๊ฐ ํ์ํ๋ค๋ฉด JSON ๊ฐ์ ์ง๋ ฌํ ๋ฐ์ดํฐ๋, ๋ง์ฝ ์ฑ๋ฅ์ด ํ์ํ๋ค๋ฉด ํ๋กํ ์ฝ ๋ฒํผ๊ฐ์ ๋์์ด ์๋ค.
๋ค๋ง [JSON, ํ๋กํ ์ฝ ๋ฒํผ, Java9]์ ํํฐ๋ง์ ๋ค ์ฌ์ฉํ๋ค๊ณ ํ๋๋ผ๋ ๋ชจ๋ ์ง๋ ฌํ ๊ณต๊ฒฉ์ ์์ ํ๋ค๊ณ ๋งํ ์๋ ์๋ค. ๊ฐ๋ฅํ๋ฉด ํด๋์ค๊ฐ ์ง๋ ฌํ๋ฅผ ์ง์ํ์ง ์๋๋ก ๋ง๋ค์ด์ผํ๊ณ ๊ผญ ํ์ํ๋ค๋ฉด ์ ๊ฒฝ์จ์ ์ค๊ณํ๋๋ก ํ์.
# Serializable์ ๊ตฌํํ ์ง๋ ์ ์คํ ๊ฒฐ์ ํ๋ผ.
์๋ฐ์์๋ extends Serializable ํ๋๋ง์ผ๋ก ์ฝ๊ฒ ์ง๋ ฌํ๋ฅผ ๊ตฌํํ ์์๋ค. ํ์ง๋ง ๊ทธ๋ก ์ธํ๋๊ฐ๋ ์๋นํ๋ค.
๊ตฌํํ ์๊ฐ๋ถํฐ ์ฝ๋๋ฅผ ์์ ํ์ ๋ ์ง๋ ฌํ ๋ฒ์ ์ด ๊นจ์ ธ ํ์ฅ์ฑ์ ์๊ฒ๋๊ณ , ์์์ ์ธ๊ธํ ์ํ์ฑ์ ๊ฐ์ง๊ฒ ๋๋ค.
์๋ฐ์์๋ ๊ฐ์ฒด๋ฅผ ์์ฑ์๋ฅผ ์ด์ฉํด ๋ง๋ ๋ค. ์ง๋ ฌํ๋ ์ด๋ฌํ ์์ฑ์ ๊ธฐ๋ฅ์ ์ฐํํ์ฌ ๊ฐ์ฒด๋ฅผ ์์ฑํ์ฌ ๋ถ๋ณ์์ด ๊นจ์ง ์ํ์ฑ์ด ์๊ณ , ์บก์ํ๊ฐ ๊นจ์ง๋ค. ํนํ ์์์ ๋ชฉ์ ์ผ๋ก ์ค๊ณ๋ ํด๋์ค๋ Serializable์ ์ฌ์ฉํ๋ค๊ฐ ํฐ์ผ ๋ ์ ์๋ค. ๋ด๊ฐ ์ง๋ ฌํํ์ง ์ฌ๋ถ๋ ๋ชจ๋ฅธ์ฑ ์ง๋ ฌํ๋ ์ฝ๋๋ฅผ ๋ณ๊ฒฝํ๊ณ ์์ผ๋๊น ๋ง์ด๋ค.
๋ํ ๋ด๋ถํด๋์ค๋ ์ง๋ ฌํ ํด์ ์๋๋ค. JVM ์ปดํ์ผ๋ฌ๋ ๋ด๋ถ ํด๋์ค์ outer ํด๋์ค์ ์ฐธ์กฐ์ ์ค์ฝํ๋ฅผ ์ ์ฅํ๊ธฐ ์ํด ํ๋๋ฅผ ํ์๋กํด์, ์ปดํ์ผ๋ฌ์์ ์๋์ผ๋ก ์ถ๊ฐํ๋๋ฐ. ์ด ์๋์ผ๋ก ์ถ๊ฐ๋๋ ํ๋ ๋ํ ์ง๋ ฌํ ๋๊ธฐ ๋๋ฌธ์ ๊ฐ๋ฐ์๊ฐ ์์ธกํ ์ ์๋ค. (static inner ํด๋์ค๋ก ๋ง๋ค์ด์ผํ๋ ์ด์ ๊ธฐ๋ ํ๋ค. ์ด๋ฌ๋ฉด ๋ฌธ์ ํด๊ฒฐ)
# ์ปค์คํ ์ง๋ ฌํ ํํ๋ฅผ ๊ณ ๋ คํด๋ณด๋ผ
๊ฐ์ฒด๋ฅผ ํต์ผ๋ก ์ง๋ ฌํํ์ง๋ง๊ณ , ์ปค์คํ ํด์ ์ฌ์ฉํด๋ผ
์ด์์ ์ธ ์ง๋ ฌํ ํํ๋ผ๋ฉด, ์ค์ ๊ฐ์ฒด์ ๋ฌผ๋ฆฌ์ ์ธ ๋ชจ์ต๊ณผ๋ ์์ ํ ๋ ๋ฆฝ๋ ๋ ผ๋ฆฌ์ ์ธ ๋ชจ์ต๋ง์ ํํํด์ผ ํ๋ค.
public final class StringList implements Serializable {
private int size = 0;
private Entry head = null;
private static class Entry implements Serializable {
String data;
Entry next;
Entry previous;
}
// ... ์๋ต
}
์์ ์ฝ๋๋ ๋ฌผ๋ฆฌ์ ์ผ๋ก ๋ฌธ์์ด๋ค์ ์ด์ค ์ฐ๊ฒฐ๋ฆฌ์คํธ๋ก ํํํ๋ค.
์ด ๋ฐ์ดํฐ๋ฅผ ์๊ฐ์์ด ๋ฌผ๋ฆฌ์ ์ผ๋ก ์ง๋ ฌํํ๋ค๊ฐ๋, ์๋์ ๊ฐ์ ๋ฌธ์ ๊ฐ ์๊ธด๋ค.
- ์ง๋ ฌํ์ ๋ฒ์ ์ด ์๊ธด๋ค. ๋ด๋ถ ํํ์ ์ข ์์ ์ด๊ฒ ๋๋ค. (์ ๊ฑฐ ๋ถ๊ฐ๋ฅ)
- ์ง๋ ฌํ ๋ฐ์ดํฐ์ ์ฌ์ด์ฆ๊ฐ ์ธ๋ชจ์์ด ํฌ๋ค
- ์ง๋ ฌํ ์๊ฐ์ด ๋ง์ด๊ฑธ๋ฆฌ๊ณ , ๊ฐ์ฒด ๊ทธ๋ํ๋ฅผ ์ํํ๋ฉฐ ์คํ์ค๋ฒํ๋ก๋ฅผ ๋ฐ์์ํค๊ธฐ ์ฝ๋ค.
์ง๋ ฌํ๋ฅผ ์ปค์คํ ํ์.
transient ํค์๋๊ฐ ๋ถ์ ํ๋๋ ๊ธฐ๋ณธ ์ง๋ ฌํ ํํ์ ํฌํจ๋์ง ์๋๋ค. ์ฐธ๊ณ ๋ก [transient ํค์๋๊ฐ ๋ถ์ ํ๋๋ฅผ ์ฌ์ฉํ๋ ๋ฉ์๋]๋ ์ ์์ ์ผ๋ก ์ง๋ ฌํ ๋๋ค. ๊ทธ๋์ผ ์์/ํ์ํธํ์ด ๊ฐ๋ฅํ๋๊น.
public final class StringList implements Serializable {
private transient int size = 0;
private transient Entry head = null;
// ์ด๋ฒ์๋ ์ง๋ ฌํ ํ์ง ์๋๋ค.
private static class Entry {
String data;
Entry next;
Entry previous;
}
// ๋ฌธ์์ด์ ๋ฆฌ์คํธ์ ์ถ๊ฐํ๋ค.
public final void add(String s) { ... }
/**
* StringList ์ธ์คํด์ค๋ฅผ ์ง๋ ฌํํ๋ค.
*/
private void writeObject(ObjectOutputStream stream)
throws IOException {
stream.defaultWriteObject();
stream.writeInt(size);
// ๋ชจ๋ ์์๋ฅผ ์์๋๋ก ๊ธฐ๋กํ๋ค.
for (Entry e = head; e != null; e = e.next) {
s.writeObject(e.data);
}
}
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException {
stream.defaultReadObject();
int numElements = stream.readInt();
for (int i = 0; i < numElements; i++) {
add((String) stream.readObject());
}
}
// ... ์๋ต
}
# ์ง๋ ฌํ(readObject)์์ ๋ฐฉ์ด์ ์ผ๋ก ๋ณต์ฌํ๊ณ , ์ ํจ์ฑ ๊ฒ์ฌ๋ ํด๋ผ
# ์ง๋ ฌํ ๋ฒ์ (SUID) ๋ฅผ ๋ช ์ํด๋ผ
# ์ง๋ ฌํ ํ๋ก์๋ฅผ ์ฌ์ฉํ๋ผ. ์ค์ ๊ฐ์ฒด์ ๋ฐ๋ก ์ญ์ง๋ ฌํ ํ์ง ๋ชปํ๊ฒ ๋ง์ด๋ฒ๋ ค๋ผ.
# ์ฑ๊ธํค์ enum์ผ๋ก ๋ง๋ค์ด๋ฒ๋ ค๋ผ. ์์ ๐
https://madplay.github.io/post/effectivejava-chapter12-serialization
์ถ๊ฐ๋ด์ฉ ์์ฑ์์ .
https://hyperconnect.github.io/2019/10/28/jackson-serialize-for-global-caching.html
'๐ฑBackend > Effective-Java' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
9. ์์ธ(Exception) ์ ๋์์ฑ(๋ฉํฐ์ค๋ ๋) (0) | 2021.10.06 |
---|---|
8. ์ผ๋ฐ์ ์ธ ํ๋ก๊ทธ๋๋ฐ ์์น (0) | 2021.10.06 |
7. ๋๋ค์ ์คํธ๋ฆผ, ๋ฉ์๋ (0) | 2021.10.06 |
6-1 Enum๊ณผ @์ ๋ํ ์ด์ ์ ์ฌ์ฉํ๋ผ. (0) | 2021.10.06 |
5-2 ์ ๋ค๋ฆญ, ๋ฐฐ์ด๋ณด๋ค๋ ๋ฆฌ์คํธ๋ฅผ ์ฌ์ฉํ๋ผ, (+์ํผํ์ ๊ตฌํ๋ฐฉ๋ฒ) (0) | 2021.09.15 |
๋ธ๋ก๊ทธ์ ์ ๋ณด
JiwonDev
JiwonDev