[Java] ์๋ฐ ์ง๋ ฌํ (Serialization)
๐ค 1. ์๋ฐ ์ง๋ ฌํ๋?
์๋ฐ ์ง๋ ฌํ(Java Serialization)์, ๊ฐ์ฒด์ ์ํ๋ฅผ ์์ํ ํ๋ ๋งค์ปค๋์ฆ์ ๋๋ค.
์์ํ๋, ์๊ตฌ์ ์ผ๋ก ์์ฑ์ ์ ์ฅํ๋ ๊ฒ์ ์๋ฏธํ๋ฏ๋ก, ์ฝ๊ฒ ํ์ด์ ์ค๋ช ํ๋ฉด ๊ฐ์ฒด๋ฅผ ๋ค๋ฅธ ํ๊ฒฝ์ ์ ์ฅํ๋ค๊ฐ ๋์ค์ ์ฌ๊ตฌ์ฑํ ์ ์๋ ๊ฒ์ด ๊ณง ์๋ฐ ์ง๋ ฌํ์ ์๋ฏธ์ ๋๋ค.
๋จ์ํ ์ ์ฅ์ด๋ผ๊ณ ํํํ์ง๋ง, ์ผ๋ฐ์ ์ผ๋ก ์ฐ๋ฆฌ๊ฐ ์๊ฐํ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ ์ฅ, ํ์ผ์ ํํ๋ก ์ ์ฅ๋ ํด๋น์ด ๋์ง๋ง, ๋ฉ๋ชจ๋ฆฌ ๋ฐ ์บ์์ ์ ์ฅํ๋ ๊ฒ ์ญ์ ์ง๋ ฌํ๋ผ๊ณ ํํํ ์ ์์ต๋๋ค.
์๋ฐ ์ง๋ ฌํ๋ฅผ ํตํด ๊ฐ์ฒด๋ฅผ ์จ์ ํ ๋ค๋ฅธ ๊ณณ์ ์ ์ฅํ๊ณ , ๋ค์ ์จ์ ํ ๊ฐ์ฒด๋ก ์ฌ๊ตฌ์ฑํ ์ ์์ต๋๋ค. ์ด๋ฅผ ํตํด ์ฝ๊ฒ ๋ถ์ฐ ๊ฐ์ฒด ์์ฑ์ด ๊ฐ๋ฅํด์ก์ต๋๋ค. ์๋ฐ ์ง๋ ฌํ์์ ์ ์ฅํ๋ ๋ฐฉ์์, ๊ฐ์ฒด๋ฅผ ๋ฐ์ดํธ ์คํธ๋ฆผ์ ํํ๋ก ๋ง๋ค์ด ์ด๋ฅผ ์ ์ฅํฉ๋๋ค.
๐ค 2. ์๋ฐ ์ง๋ ฌํ๋ ์ธ์ ์ฐ๋์?
๊ฐ์ฒด์ ์ํ๋ฅผ ์์(์ด๋๊ฐ์ ์๊ตฌ์ ์ผ๋ก ์ ์ฅ)ํด์ผ ํ ๋ ์ฌ์ฉํฉ๋๋ค.
๊ฐ์ฒด๋ก ์ฌ๊ตฌ์ฑํ ์ ์๋ค๋ ์ ์์, ๋ค๋ฅธ VM์๊ฒ ๊ฐ์ฒด์ ์ ๋ณด๋ฅผ ์ ๋ฌํด์ผ ํ ๋ ์ฌ์ฉํ๊ธฐ๋ ํฉ๋๋ค. (Remote Method Invocation ํน์ Socket์ ์ฌ์ฉํด์.)
์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋จ์ํฉ๋๋ค.
package java.io;
public interface Serializable {}
public class MyObject implemets Serializable{
public int value;
public MyObject(final int value){
this.value = value;
}
}
์์ ์ฝ๋์์ ๋ณผ ์ ์๋ฏ์ด Serializable ์ธํฐํ์ด์ค๋ ๊ณต๊ฐ API๊ฐ ์๋ ๋จ์ํ ๋ง์ปค ์ธํฐํ์ด์ค์ ๋๋ค.
ํ์ง๋ง ์ด Serializable ์ธํฐํ์ด์ค๋ฅผ implements ํด์ฃผ๋ ๊ฒ๋ง์ผ๋ก๋ ํด๋น ๊ฐ์ฒด๋ ์ง๋ ฌํ ๊ฐ๋ฅํ ๊ฐ์ฒด๋ก ๋ณ์ ํ๊ฒ ๋ฉ๋๋ค!
๋ง์ฝ Serializable ์ธํฐํ์ด์ค๋ฅผ implementsํ์ง ์๋ ๊ฐ์ฒด๋ฅผ ์ง๋ ฌํ ํ๋ ค๊ณ ํ๋ค๋ฉด, NotSerializableException์ด ๋ฐ๋ฐํ๊ฒ ๋๋ฏ๋ก ์ฃผ์๊ฐ ํ์ํฉ๋๋ค!
byte[] serailizedObject;
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream)) {
MyObject myObject = new MyObject(1);
objectOutputStream.writeObject(myObject);
serializedObject = byteArrayOutputStream.toByteArray();
}
์ง๋ ฌํ๋ฅผ ํ๋ ๊ฒ์ java.io.ObjectOutputStream์ ์ฌ์ฉํฉ๋๋ค. try-with-resource ๋ฌธ์ ์ฌ์ฉํด byteArrayOutputStream๊ณผ ObjectOutputStream์ ์์ฑํ ๋ค, writeObject ๋ฉ์๋์ toByteArray ๋ฉ์๋๋ฅผ ์ฌ์ฉํด ์ง๋ ฌํ๋ฅผ ํ ์ ์์ต๋๋ค.
๋ฐ๋๋ก ์ญ์ง๋ ฌํ๋ java.io.ObjectInputStream๋ฅผ ์ฌ์ฉํฉ๋๋ค.
์ญ์ง๋ ฌํ๋, ๋ฐ์ดํธ ์คํธ๋ฆผ์ผ๋ก ์ ์ฅ๋ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ฒด๋ก ์ฌ๊ตฌ์ฑํ๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค.
byte[] serializedObject = getSerializedObject();
try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(serializedObject);
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream)){
MyObject myObject = (MyObject) objectInputStream.readObject();
}
๊ทธ๋ฆฌ๊ณ ObjectInputStream์ readObject ๋ฉ์๋์ ํ์ ์บ์คํ ์ ํตํด ์ญ์ง๋ ฌํ๋ฅผ ์งํํด ๊ฒฐ๊ตญ, ๊ฐ์ฒด๋ฅผ ์จ์ ํ ์ฌ๊ตฌ์ฑํ ์ ์๊ฒ ๋ฉ๋๋ค.
์ ์ฒด์ ์ธ ํ๋ก์ฐ๋ ์์ ๊ฐ์ต๋๋ค.
๐ค 3. SerialVersionUID์ ์ฉ๋๋ ๋ฌด์์ผ๊น?
Serialization์ implementsํ๋ ๊ฐ์ฒด๋ค์, ํด๋์ค์ ๋ฒ์ ๊ด๋ฆฌ๋ฅผ ์ํด serialVersionUID ๋ณ์๋ฅผ ์ฌ์ฉํ๊ฒ ๋ฉ๋๋ค.
์ด serialVersionUID ๋ณ์๋ ๊ฐ๋ฐ์๊ฐ ์ง์ ์ ์ํ์ง ์์ผ๋ฉด, ์ปดํ์ผ๋ฌ๊ฐ ์์์ ๋ถ์ฌํ๊ฒ ๋ฉ๋๋ค.
์ด serialVersionUID๋ ์ง๋ ฌํ ํ ๋ ๊ฐ์ด ์ ์ฅ๋๊ฒ ๋๊ณ , ์ญ์ง๋ ฌํ๋ฅผ ํ ๋์๋ ๊ทธ ๊ฐ์ ์ฒดํฌํ๋ ์ฉ๋๋ก ์ฌ์ฉํ๊ฒ ๋ฉ๋๋ค.
์๋ฅผ ๋ค์ด serialVersionUID ๊ฐ์ 1L๋ก ์ค์ ํ ํ ์ง๋ ฌํ๋ฅผ ํ์ต๋๋ค. ๊ทธ ์ดํ, ํด๋น ํด๋์ค์ serialVersionUID ๊ฐ์ 2L๋ก ๋ณ๊ฒฝํ ๋ค, ์ญ์ง๋ ฌํ๋ฅผ ์๋ํ๋ฉด invalidClassException์ด ๋ฐ์ํ๊ฒ ๋ฉ๋๋ค. ์ฆ ๋ฒ์ ๊ด๋ฆฌ๋ฅผ ๊ฐ๋ฅ์ผ ํ๋ ๊ฒ์ด์ฃ .
SerialVersionUID๋ ๊ฐ๋ฐ์๊ฐ ์ง์ ์ค์ ํ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค. ๊ทธ ์ด์ ๋ ์ปดํ์ผ๋ฌ์ ์์ ๋ถ์ฌ์ ์์ต๋๋ค. JVM์ ๋ด๋ถ ์๊ณ ๋ฆฌ์ฆ์ ์ํด ํด๋น ๊ฐ์ด ๊ฒฐ์ ๋๊ฒ ๋๋๋ฐ, ๋ฌธ์ ๋ ์ด๋ค JVM์ ์ฌ์ฉํ๋์ง์ ๋ฐ๋ผ์ ์ด ๊ฐ์ด ๋ฌ๋ผ์ง๊ฒ ๋ฉ๋๋ค.
๋ฐ๋ผ์ Client๊ฐ Windows, ์๋ฒ๊ฐ Linux์ธ ๊ฒฝ์ฐ ์๋ก ๋ค๋ฅธ JVM์ ์ฌ์ฉํ๊ฒ ๋์ด ์ด ๊ฐ์ด ๋ฌ๋ผ์ ธ ์ญ์ง๋ ฌํ๋ฅผ ์งํํ ๋ Exception์ด ๋ฐ์ํ ์ฌ์ง๊ฐ ์์ต๋๋ค.
๐ค 4. ์ ์๋ฐ ์ง๋ ฌํ๋ ์ ์ ์ฐ๊ฒ ๋๋ ๊ฑธ๊น?
์ด ์ง๋ ฌํ๋ผ๋ ๊ฐ๋ ์ ๋ง์ด ๋ค์ด๋ณด๊ธด ํ์ผ๋ ์ค๋ฌด ๊ฒฝํ์ด ๋ถ์กฑํ ๋ด๊ฒ๋ ์ ์ฐ์ด์ง ์๋๋ค๋ ๋๋์ ๋ฐ์์ต๋๋ค.
์ง๋ ฌํ๋ฅผ ๊ธฐํผํ๋ ์ด์ ๋ ๋ณด์ ๋ฌธ์ , ์ ์ง ๋ณด์์ฑ, ํ ์คํธ ๋ฑ์์ ๋ณต์กํจ์ด ์์ด์ ๊ทธ๋ ๋ค๊ณ ํฉ๋๋ค.
์๋ฅผ ๋ค์ด ํ์ธํด๋ด ์๋ค.
1) ๋ณด์ ๋ฌธ์
์ง๋ ฌํ๋ ๋ฐ์ดํธ ์คํธ๋ฆผ์ ์ญ์ง๋ ฌํ ํ ๋์๋ readObject ๋ฉ์๋๊ฐ ํธ์ถ๋๊ฒ ๋ฉ๋๋ค. ๊ทผ๋ฐ ์ด๊ฒ ์์ฒด๊ฐ ํ๋์ ์์ฑ์์ ๋ค๋ฅผ๊ฒ ์์ต๋๋ค. ์ฆ, ๋ณด์ด์ง ์๋ ์์ฑ์์ ๋ฌธ์ ๊ฐ ์๊ธฐ๊ฒ ๋ฉ๋๋ค.
์ด๊ฒ ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋๋ฉด, ๋ฐ์ดํธ ์คํธ๋ฆผ์ ๋ฐฐ์ด ๋ด๋ถ์ ๊ฐ์ ์ง์ ์ ๊ทผํด ์์ ์ด ๊ฐ๋ฅํฉ๋๋ค.
์ด ์ํ๋ก objectInputStream์ ์์ฑํ๊ณ , readObject๋ฅผ ํ๋ค๋ฉด ๊ทธ๋๋ก ์์ฑ์ด ๋ฉ๋๋ค. ๊ธฐ์กด์ ์์ฑ์์์๋ validation๋ก์ง์ ๋ฃ์ด์ ๊ฐ์ ์ ํจ์ฑ์ ํ๋จํ์ง๋ง, readObject๋ฅผ ํตํด ๋ง๋ค์ด์ง ๊ฐ์ฒด๋ ๋ณด์ด์ง ์๋ ๋ค๋ฅธ ์์ฑ์๋ฅผ ์ฌ์ฉํ๊ฒ ๋์ด๋ฒ๋ฆฝ๋๋ค.
์ด๋ฅผ ๋ฐฉ์ดํ๋ ๋ฐฉ๋ฒ์ผ๋ก๋, ์ปค์คํ ์ง๋ ฌํ๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค. readObject๋ฅผ ์๋กญ๊ฒ ์ ์ํ๋ ๋ฐฉ์์ผ๋ก, ๊ธฐ์กด์ objectInputStream.defaultReadObject() ๋ฉ์๋๋ฅผ ํตํด ๊ธฐ์กด์ ์ญ์ง๋ ฌํ ๊ณผ์ ์ ์ํค๊ณ , ์ถ๊ฐ์ ์ธ validation ์ฝ๋๋ฅผ ์ฌ๊ธฐ์ ์ฝ์ ํด์ฃผ๋ฉด ์ด๋ฌํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์ต๋๋ค.
private void readObject(ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException {
objectInputStream.defaultReadObject(); // ๊ธฐ๋ณธ์ ์ธ ์ญ์ง๋ ฌํ ๊ณผ์
// ์๋ต, ์ถ๊ฐ์ ์ธ validation ์ฝ๋.
}
2) ์ฑ๊ธํค ๋ฌธ์
์ฑ๊ธํค ํจํด์ผ๋ก ์ด๋ ํ ํด๋์ค๋ฅผ ๋ง๋ค๊ณ , ์ด๋ฅผ ์ง๋ ฌํ ๊ฐ๋ฅํ๋๋ก Serializable ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋ค๊ณ ํฉ์๋ค.
์ฑ๊ธํค ๊ฐ์ฒด๋ฅผ ๋ค์ ์ญ์ง๋ ฌํ ํ๋ฉด, ์ฑ๊ธํค์ ํน์ฑ์ ์์ด๋ฒ๋ฆฌ๊ฒ ๋ฉ๋๋ค. readObject๊ฐ ํธ์ถ๋๋ฉด ๋ค๋ฅธ ๊ฐ์ฒด๊ฐ ์์ฑ๋๊ฒ ๋ฉ๋๋ค. ์ฑ๊ธํค์ ๋จ ํ๋์ ๊ฐ์ฒด๋ง ์กด์ฌํด์ผ ํ๋ค๋ ๊ฒ์ ํญ์ ์ ์งํ๋๋ฐ ์ด๋ฅผ ๊นจ๋ฒ๋ฆฌ๊ฒ ๋๋ค๋ ๊ฒ์ด์ฃ .
์ด๋ฌํ ์ฑ๊ธํค ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ค๋ฉด readResolve()๋ฅผ ์ ์ํ๋ฉด ๋ฉ๋๋ค. readResolve() ๋ฉ์๋๋ readObject()๊ฐ ํธ์ถ๋ ์ดํ์ ํธ์ถ๋๊ฒ ๋ฉ๋๋ค. ์ญ์ง๋ ฌํ๋ฅผ ๊ฑฐ์น ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ์ง ์๊ณ , readResolve()์์ ๋ฐํํ๋ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ๊ฒ ๋๊ธฐ ๋๋ฌธ์, ์ฑ๊ธํค ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์ฃ .
๋ค๋ง ์ด ๊ฒฝ์ฐ, ํด๋์ค์ ํ๋ ์ค์, ์ธ์คํด์ค ๋ณ์๊ฐ ์กด์ฌํ๋ ๊ฒฝ์ฐ์๋ ์ง๋ ฌํ/์ญ์ง๋ ฌํ๊ฐ ๋์ง ์ํ ๋ก transient ํค์๋๋ฅผ ๋ถ์ฌ์ผ ํฉ๋๋ค. ๊ทธ๋์ผ ์ฐธ์กฐํ๋์ ์์ญ๊ฐ์ ํ์ณ์ค๋ ํ์๋ฅผ ๋ง์ ์ ์๋ค๊ณ ํฉ๋๋ค. ์ด ๋ถ๋ถ์ ์ถํ์ ๊ณต๋ถ๋ฅผ ๋ ํด๋ด์ผ๊ฒ ์ต๋๋ค.
๋ชจ๋ ์ธ์คํด์ค ๋ณ์์ ์ฌ์ฉํด์ผ ํ๊ณ , ์ด๋ฅผ ๊ฐ๊ณผํ๋ค๋ฉด ๋ณด์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
์ฑ๊ธํค๊ฐ์ด ๊ฐ์ฒด ๊ฐฏ์ ํต์ ํด์ผ ํ๋ ์ํฉ์๋ readResolve๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ๊ต์ฅํ ๋ถํธํ๊ฒ ๋ฉ๋๋ค.
์๋ฐ ์ง๋ ฌํ๋ ์๊ฐํ ๊ฒ์ด ๋ง์ ๊ธฐ์ ์ด์์ต๋๋ค. ์๋ฌด๋ฐ ์๊ฐ ์์ด ์ฌ์ฉํ๋ค๊ฐ๋ ์ฌ๋ฌ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ฌ์ง๊ฐ ์์์ต๋๋ค.
๊ทธ๋์ 10๋ถ ํ ์ฝํก์์๋ ์ฌ๋งํ๋ฉด ์ฌ์ฉํ์ง ์๋ ๊ฒ์ ๊ถ์ฅํ์ต๋๋ค. ์๋ก์ด ์์คํ ์ ๋ฐ์ดํธ ์คํธ๋ฆผ์ผ๋ก ๋ณํํ๋ ์ข์ ๋งค์ปค๋์ฆ์ด ๋ง๊ธฐ ๋๋ฌธ์ ๋๋ค.
์๋ฅผ ๋ค์ด, ํฌ๋ก์ค ํ๋ซํผ์ ์ ํฉํ ๋ฐ์ดํฐ ํํ์ผ๋ก JSON, CSV, ํ๋กํ ์ฝ ๋ฒํผ ๋ฑ์ ์ฌ์ฉํ๋ ๊ฒ์ ๊ถ์ฅํ๋ค๊ณ ํ๋ค์.
์ดํํฐ๋ธ ์๋ฐ์์๋ ์ง๋ ฌํ ํํธ์์ ๋ง์ ๋ด์ฉ์ ๋ค๋ฃจ๊ณ ์๋ค๋, ์ถ๊ฐ ํ์ต์ ํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
๐ ์ถ์ฒ
[๋งํฌ] https://blog.naver.com/kkson50/220564273220 (SerialVersionUID)
[๋งํฌ] https://www.youtube.com/watch?v=3iypR-1Glm0 (10๋ถ ํ ์ฝํก : ์๋ฐ ์ง๋ ฌํ)