Androidエミュレータから複数のローカルサイトにアクセスした際にRedis絡みのClassNotFoundExceptionが発生する

# 概要
凄まじくニッチな話
私がWindows10の開発PC上でAndroid Studioのエミュレータと複数のローカルサイトを利用して動作確認をする際に発生した問題点と対策について記載する。

## システムの構成要素
* 開発PCの環境
  * OS : Windows 10
  * IDE : Android Studio 3.4.1

* システム構成
  * クライアント : Android Studioのエミュレータで起動したアプリケーション
  * APIサーバ１ : Spring Bootアプリケーション（組込みTomcatで起動）
  * APIサーバ２ : Spring Bootアプリケーション（組込みTomcatで起動）
  * Key Value Store（Redis）

## とりあえず動かしてみる
APIサーバはそれぞれ認証情報、業務情報をSpring Sessionを用いてRedis上に格納する。
クライアントからAPIサーバ１、APIサーバ２にアクセスする必要があり、
クライアントアプリから以下の様に接続先設定している。  
　APIサーバ１：http://172.26.0.1:8080
　APIサーバ２：http://172.26.0.1:8090
　※ 172.26.0.1 はPCのローカルアドレス  

外部にAPIサーバ立てればいいじゃんって思う人もいるかもしれないが、
APIサーバをデバッグ起動で実行したい場合もあるし…

いざ、アプリケーションを起動して
動作確認を実施したところ、APIサーバ１、２の両方にアクセスした時点で
最後にアクセスしたのAPIサーバで以下のエラーが出力された。

~~~ 
2019-05-10 14:10:10,061 ERROR Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception  
    org.springframework.data.redis.serializer.SerializationException: Cannot deserialize; nested exception is  
    org.springframework.core.serializer.support.SerializationFailedException: Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer?; nested exception is  
    org.springframework.core.NestedIOException: Failed to deserialize object type; nested exception is java.lang.ClassNotFoundException: 
<<以降省略>>
~~~

## 調査  
APIサーバ１、２に対して同じドメイン（ここではPCのローカルアドレス）を指定しているため、
Redis上で同じドメインのセッションとして格納されるが、
JavaBeanなどオブジェクトを利用している箇所で整合性が合わないためClassNotFoundExceptionが発生していることが分かった。


## 対応方法
ドメインの重複を排除するためAndroid Emulatorのhostsに設定を追加してみることにした。

### Android Studio側の設定
* Android StudioのAndroid Virtual Device Managerで仮想マシンを作成。  
作成済みの場合でも以下の条件を満たしていない場合は再作成する。
  * System imageを選択する際に**必ずAndroid X.0(Google Play)ではなくAndroid X.0(Google APIs)を選択**  
  ※ 詳しく調べ切れていないがGoogle APIsで作らないとrootアクセスが出来ない模様。  
[Stack Overflow - ADB root is not working on emulator (cannot run as root in production builds)](https://stackoverflow.com/questions/43923996/adb-root-is-not-working-on-emulator-cannot-run-as-root-in-production-builds)

### PC側の設定（以下Git Bashのターミナル上で実行）

#### 1. 環境変数に以下のパラメータを追加（パス情報は個々の環境に合わせて）
~~~ console
$ export PATH="$PATH:$HOME/AppData/Local/Android/Sdk/platform-tools"
$ export PATH="$PATH:$HOME/AppData/Local/Android/Sdk/emulator"
~~~

ただし、この方法は一時的なものでターミナルを落とすと消えてしまう。
私の場合はこの作業をGit Bashでしか行わないため、~/.bash_profileに追記した。

#### 2. 利用可能なエミュレータの一覧表示し、確認
~~~ console
$ emulator -list-avds
Nexus_6_API_26
Pixel_2_API_26_64
~~~

#### 3.エミュレータを起動
* 上記、`-avd`のパラメータにはAndroid Studioの設定で作成したエミュレータを指定する。
* プロキシを設定している場合は`-no-audio -http-proxy <プロキシサーバのIP>:<プロキシサーバのport>`を指定する。

~~~ console
$ emulator -avd Pixel_2_API_26_64 -writable-system -no-audio -http-proxy <プロキシサーバのIP>:<プロキシサーバのport>
~~~

#### 4. ADBをroot権限で実行
~~~ console
$ adb root
~~~

#### 5. エミュレータ内の/systemディレクトリを書き込み可能でマウント
~~~ console
$ adb remount
remount succeeded
~~~

#### 6. エミュレータのhostsファイルの内容確認
~~~ console
$ adb shell "cat /system/etc/hosts"
127.0.0.1       localhost
::1             ip6-localhost
~~~

#### 7. エミュレータのhostsファイルにローカルアドレスに割り当てるホスト名を指定
（ここではホスト名:API1, API2 をIP:172.26.0.1に紐付け）

~~~ console
$ adb shell "echo 172.26.0.1 API1 API2 >> /system/etc/hosts"
~~~

#### 8. hostsに追加されていることを確認
~~~ console
$ adb shell "cat /system/etc/hosts"
127.0.0.1       localhost
::1             ip6-localhost
172.26.0.1 API1 API2
~~~

これで完了。
再度、動作確認したところ問題なく両APIサーバを利用出来るようになった。

## 気になる点
emulatorコマンドで起動してからAndroid Virtual Device Manager上でエミュレータが起動できなくなった。
コマンドで起動するのに慣れてしまったので、現時点では困っていないが、改めて原因は調べようと思う。