- 投稿日:2021-01-29T22:57:43+09:00
【SpringBoot:Maven】Elastic Beanstalkでデプロイするまでの流れ
前提
- MySQLに接続したアプリケーションが既にある。
- awsのアカウントを発行済である。
対象者
- デプロイをとりあえずしたい人。
- Elastic Beanstalkでデプロイする流れをサクッと知りたい人。
- AWSについて詳しくない人。
注意
- くれぐれもくるくるしている間に触らない。1つ1つ読み込み長いです。
- インフラ系は戻るボタンを使わない。
ざっくりElastic Beanstalkって何?
AWSでデプロイに必要な
- Elastic Load Balancing (ロードバランサー)
- アプリケーションのデータ量を自動で分散してくれる。
- Amazon Elastic Compute Cloud (Amazon EC2)
- 仮想サーバーを構築してくれる。これですばやくデプロイできる。
- Amazon Relational Database Service (Amazon RDS)
- クラウド上に作る性能の高いDB。今回はデータベースエンジンにMySQLを選択。
をセットで構築してくれて、簡単にデプロイできるようにするためのサービス。
(簡単に、と言っていますが初心者の筆者は1週間悩みましたw)Elastic Beanstalkの準備
- Elastic Beanstalkにログイン
- リージョンを東京にしておく。
- いますぐ始めるを押す
各項目を入力してアプリケーションの作成
作成まで結構時間がかかります。
DBの作成
編集を押したら、
- エンジン→mysql
- ユーザー名→好きな名前(今回はadmin)
- パスワード→好きなパスワード
そのほかは触らない。- 適用を押す
DBの作成も時間がかかります。
application.propertiesをYAML形式に変更
MySQLに接続していたこの状態のapplication.propertiesを
#MySQLのDBのURL spring.datasource.url=jdbc:mysql://localhost:3306/mydb?serverTimezone=JST #name、パス指定。 spring.datasource.username=root spring.datasource.password=xxxxxxxx #SpringBootを起動したときに実行したいSQL文を記述したパス spring.datasource.schema=classpath:schema.sql spring.datasource.data=classpath:data.sqlRDSに接続できるようにapplication.ymlに変更
spring: profiles: active: dev datasource: initialization-mode: always url: jdbc:mysql://確認したエンドポイント/ebdb username: admin password: 設定したパスワード server: port: 5000
- プロファイル名dev(今回は開発と本番環境を分ける前提でdevと名前を付ける)
- MySQLでschema.sqlやdatasqlを実行したい場合はinitialization-mode: alwaysにする
- YAMLは:の後に設定がある場合1マスブランクを入れます。
- YAMLは一段下がると、前に2マスブランクを入れます。(必ず偶数になる)
- ebdbは標準で作成するDB名
- port: 5000は重要です。(いつも8080だったのであまり重要視していませんでした。)
application.propertiesではまったこと
dev書き方
参考にしていた書籍では
config: activate: on-profile: devとなっていたのですが、これだとRDSと接続エラーとなりました。
Description:
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
Reason: Failed to determine a suitable driver class
Action:
Consider the following:
If you want an embedded database (H2, HSQL or Derby), please put it on the classpath.
If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active).公式リファレンスを見てみると書き方が違ったため、
profiles: active: devに変更したらいけました~!
リファレンスURLポート番号
最初はポート番号を8080にしており、localhostでは正常な挙動なのにawsのURLだと「502 Bad Gateway」になるという現象に悩まされました。
Elastic Beanstalkのデフォルトのポートは5000です。aws公式サイト
nginxがTomcatの5000番を参照しに行くので、5000以外だとRDSに接続できなくなります。ビルド
pom.xmlのversionを指定しておく。
今後アプリケーションがバージョンアップして、デプロイし直す度にここを変えていく。
アプリを選択して実行→Mavenビルド
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.22.2:test (default-test) on project Qiita210129: There are test failures.
※テストができていないと上記のエラーがでるので、最初からあるcom.example.demoパッケージ内も含めて一旦すべて消してください。
ビルドがうまくできたら、jarファイルがtargetの中にできるので、格納場所を確認しておく。
デプロイ
このバージョンはpomで指定したversionと同じにしておく。
デプロイはとても時間がかかります。Elastic Beanstalkにdevを設定する
Elastic BeanstalkでYAMLに書いたdevの設定をする。
設定→ソフトウエア(一番上)編集
画面が自動転送されるとき(loginなど)
今回のアプリケーションの仕様にはないですが、最初のページに自動転送されるという仕様があるときに設定が必要になります。
(例えば、/hogeをurlに入力しても、ログインしていないので/loginにリダイレクトされるようなとき)
設定→ロードバランサー→ヘルスチェックパスを最初の画面(/login)にする。
デフォルトでは/になっている。※何故設定するかというと、ロードバランサーがHTTPのステータスコードが成功だと思って「200」が返ってくると思っているのに、リダイレクトの「301」「302」「303」が返ってきてくるからです。
こちらを参考にしました。
基礎からのネットワーク&サーバー構築デプロイできているか確認
Elastic Beanstalk
環境に移動
awsのページに飛ぶので、最初のページ(/todos)を末尾に付け足します。(今回はawsのURL/todosが最初のページに指定されているため)
controllerの指定が最初から/なのであれば「環境に移動」を選択すればすぐに表示されるので付け足し不要です。
最後に
お疲れさまでした!!
こんなに色々やってくれるElastic Beanstalkすごいですね!
RDSは課金されるので、必要でないときは消すのがよいかと思います。Elastic Beanstalkは簡単にデプロイできるらしい、便利じゃないかと思いやってみましたが、難しかったです。
これをきっかけにインフラ・ネットワークの仕組みを学習していこうと思います。
- 投稿日:2021-01-29T22:32:02+09:00
Ubuntu 20.04 で Java をインストール
Ubuntu において Java を使おうとするといろいろ選択肢がある。
一番安直にしようとするとどうしたらいいかな・・・環境
- Ubuntu Linux 20.04
- openjdk-11 (デフォルト設定)
何があるかな?
$ apt-cache search openjdk | grep jreとすると、以下が得られた。
default-jre - 標準的な Java または Java 互換のランタイム default-jre-headless - 標準的な Java または Java 互換のランタイム (ヘッドレス) openjdk-11-jre - OpenJDK Java ランタイム - Hotspot JIT 版 openjdk-11-jre-headless - OpenJDK Java ランタイム - Hotspot JIT 版 (ヘッドレス) openjdk-11-jre-zero - Alternative JVM for OpenJDK, using Zero openjdk-8-jre - OpenJDK Java ランタイム - Hotspot JIT 版 openjdk-8-jre-headless - OpenJDK Java ランタイム - Hotspot JIT 版 (ヘッドレス) openjdk-8-jre-zero - Zero/Shark を用いた OpenJDK 用の代替 JVM openjdk-11-jre-dcevm - Alternative VM for OpenJDK 11 with enhanced class redefinition openjdk-13-jre - OpenJDK Java runtime, using Hotspot JIT openjdk-13-jre-headless - OpenJDK Java runtime, using Hotspot JIT (headless) openjdk-13-jre-zero - Alternative JVM for OpenJDK, using Zero openjdk-14-jre - OpenJDK Java runtime, using Hotspot JIT openjdk-14-jre-headless - OpenJDK Java runtime, using Hotspot JIT (headless) openjdk-14-jre-zero - Alternative JVM for OpenJDK, using ZeroJava をインストール
jre でいい場合
# sudo apt install default-jdkjdk が必要な場合
# sudo apt install default-jdk今回は、jdk が必要だったため後者を使いました。
$ sudo apt install default-jdk パッケージリストを読み込んでいます... 完了 依存関係ツリーを作成しています 状態情報を読み取っています... 完了 ・ ・ ・ 以下のパッケージが新たにインストールされます: default-jdk default-jdk-headless default-jre libice-dev libpthread-stubs0-dev libsm-dev libx11-dev libxau-dev libxcb1-dev libxdmcp-dev libxt-dev openjdk-11-jdk openjdk-11-jdk-headless x11proto-core-dev x11proto-dev xorg-sgml-doctools xtrans-dev アップグレード: 0 個、新規インストール: 17 個、削除: 0 個、保留: 66 個。 235 MB のアーカイブを取得する必要があります。 この操作後に追加で 251 MB のディスク容量が消費されます。 続行しますか? [Y/n] yopenjdk-11 が入った。かなりダウンロードする必要があるので、時間を十分に見積もろう。
確認
$ java --version openjdk 11.0.9.1 2020-11-04 OpenJDK Runtime Environment (build 11.0.9.1+1-Ubuntu-0ubuntu1.20.04) OpenJDK 64-Bit Server VM (build 11.0.9.1+1-Ubuntu-0ubuntu1.20.04, mixed mode, sharing)となりました。(2020/01/29現在)
- 投稿日:2021-01-29T18:50:37+09:00
DB上でTimestamp型のカラムはSqlResultSetMappingするとjava.util.Date型にマッピングされる件
DB検索結果がオブジェクトにマッピングされない
SpringbootでNativeQueryでDBにアクセスする時、Entityと素直にマッピングされない結果が欲しかったため、以下の方法で独自クラスにマッピング定義をして結果を格納するようにしました。
- 結果セット格納用POJO
ForMapping.java@Data @AllArgsConstructor public class ForMapping { private Long id, private String name, private Timestamp created }※コンストラクタやsetter/getterはlombokでやってます。
- Entityクラス
SomeEntity.java@SqlResultSetMapping(name = "MappingDef", classes = { @ConstructorResult(targetClass = ForMapping.class, columns = { @ColumnResult(name = "id", type = Long.class), @ColumnResult(name = "name", type = String.class), @ColumnResult(name = "created", type = Timestamp.class), }) })テーブル上は、idはlong、nameはTEXT、createdはTIMESTAMP型だったので、それぞれ対応するJavaのクラスを型に指定してマッピングを試みます。
これでSQLを実行して結果を取得しようとした所、結果が1件も取得できませんでした。地道にデバッグしてみると、SQLの実行自体は成功していましたが、結果セットのPOJOへのマッピングのあたりで失敗しているようでした。こんなエラーメッセージが。
Could not locate appropriate constructor on classエラーメッセージはHibernateの以下の部分で出ていることが分かりました。やはり、SQLの結果セットをPOJOにマッピングするところのようです。
ConstructorResultColumnProcessor.javaprivate static Constructor resolveConstructor(Class targetClass, List<Type> types) { for ( Constructor constructor : targetClass.getConstructors() ) { final Class[] argumentTypes = constructor.getParameterTypes(); if ( argumentTypes.length != types.size() ) { continue; } boolean allMatched = true; for ( int i = 0; i < argumentTypes.length; i++ ) { if ( ! areAssignmentCompatible( argumentTypes[i], types.get( i ).getReturnedClass() ) ) { allMatched = false; break; } } if ( !allMatched ) { continue; } return constructor; } throw new IllegalArgumentException( "Could not locate appropriate constructor on class : " + targetClass.getName() ); }原因はマッピング定義の型誤り
デバッグで分かりましたが原因は単純で、createdという項目をjava.sql.Timestamp型で指定しているのがNGだったようです。これにより、マッピングしようとしてもマッチするコンストラクタが見つからん!ということで、先のエラーメッセージでした。
公式の情報が見つけられなかったのですが、ネイティブクエリの結果セットをマッピングする時にDB上のTIMESTAMP型をjava.util.Dateにマッピングする、という情報を以下URL内で見つけました。
マッピングの定義部分とPOJOの型をjava.util.Dateに変更したところ、無事結果を取得できるようになりました。
- 投稿日:2021-01-29T17:56:35+09:00
関連エンティティがあるときのJPQLの書き方
環境
Spring boot
参考にしたサイト
Spring DATA JPAでデータ検索
JPQLの内部テーブル結合を試してみるエラーメッセージ
MySQL server version for the right syntax to use near '' at line 1
もうこし長かったけど、構文エラーがあるよってエラー。
原因
JPQLの書き方が間違っていた!というか、MySQLのNativeQueryとはちょっと書き方がちがうんだなぁ~くらいの認識でしたけど、結構違う感じでしたね。
特に
@OneToOne
とかの関連エンティティがある場合の扱い方が間違っていました。外部キーで結合するので、
LEFT JOIN
とか書いていたけど、それが原因でした。application.propertiesに次のように書いて、SQLを参考にしました。コンソールに大量に表示されるようになります。
application.propertiesspring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect spring.jpa.show-sql=trueけど、MySQLのSQL文とはなんかが違うみたいですね。
Hibernateってなに?
wikiによると
Java のためのオブジェクト関係マッピング (ORM) ライブラリであり、オブジェクト指向のドメインモデルを関係データベースにマッピングするためのフレームワークを提供する。
初心者には難しいですけど、多分の解釈でいうと、
データベースから取得してきたデータを、オブジェクトとかインスタンスのフィールドに代入して、以降はオブジェクトとして扱えるようにするためにHibernateっていうのがよしなにやってくれる
って認識で良さそうです。
PHPの学習をしているときには、
1. DB接続
2. レコード取得
3. カラムを取得
4. 配列に格納
5. DB切断って言う流れをそのまま書いてましたね。オブジェクトとかクラスをまだ知らないときです。
Javaをやりだして、早速クラスを勉強して、便利さもわかってきたところでなんとデーブルをそのままクラスと対応させることができるということもできることを理解しだしたのが最近です。
JPQLってなに?
JPAでDB(正確にはエンティティ)からデータを取得するSQLをJPQLと言います。
RepositoryでJPAが出てきてたな。これでデータベースから取得してクラスに格納できるようになるんだなと、なんとなく理解。
Repositoryでも@Queryアノテーションを付けてfindBy~みたいなメソッドを定義したことあったけど、なんのこっちゃわかっていませんでした。
でも今日わかったことが。
// 普通のSQL文を自分で書く @Query(value="select * from なんちゃら~", nativeQuery = true)// これがJPQLで、テーブルと紐付けたエンティティでSQL文を書ける的な @Query("select エイリアス from オブジェクト エイリアス ~")確かにわかりやすい記述ができるから便利だな~
エンティティの中に別のエンティティがあったらどうするの?
spring.jpa.show-sql=true
としていると、
jpaで発行されたSQLがコンソールに出力されるので、それを見ると、結合しているテーブルがある場合はleft outer join
って書いてました。ちょっと複雑な条件の場合は生のSQL文を書いて、結合の部分は
left outer join
って書けばいいんだなとあいまいに考えていましたが、ちゃいましたね。@OneToOneや@OneToManyなどのアノテーションで関連を記述していたら、そのエンティティを含むオブジェクトをデータベースから取得する際にjpaが勝手に中のエンティティのデータも持ってきてくれる。
イメージ
Book.javapublic class Book { private Integer id; private String name; @OneToOne( fetch = FetchType.EAGER ,cascade = CascadeType.ALL) @JoinColumn(name="buyer_id") private Buyer buyer; }Buyer.javapublic class Buyer { private name; private address; }こんなイメージの関係性で、この場合は、
@Query("select b from Book b")とするだけで、Buyerもちゃんと取ってきてくれる。
Joinとか書いてたら永遠に構文エラーが発生する
@Query("select b from Book b JOIN Buyer")って書いてたら永遠に構文エラーになります。
しかもどこがおかしいっていうメッセージも、なんか場所がちがうんですよね。
near '' at line 1 `` ってどこ??`''`の中におかしいところがあるよってメッセージだけど、なんかちゃんと教えてくれませんでした。 ###結論! JPQLとSQLは違うよっていう明確な、強い意志と理念が必要!!
- 投稿日:2021-01-29T13:54:48+09:00
RPCとは何かを友達に説明する方法
RPCとは友達も理解できる説明方法
1.基本的なPRCモジュール
RPCとは何か?RPCとRESTの区別
2.概念
RPC(Remote Procedure Call)主にクライアントノードとサービスノード間に呼び出し方式です。
ローカルでよびだしの場合はsetName(String name)のようなローカル関数を呼び出して、データをメモリに渡し、関数ポインタでsetName();を呼び出して、データを処理します。
RPCの場合は以下のstepを実現されます
1.まず、クライアント端はさーばサーバーに保存したの関数のプロセスIDを見つけ、そして関数を実行する
2.クライアントはローカルデータがサーバーに伝送する必要があります。そのため、クライアントはデータをバイトストリームに変換してサーバー側に送り、サーバー側はバイトスクリームをデシナリオして、クライアントからのデータと関数IDを取得ます。
3.サーバー側に関数を実行して、結果がシナリオとデシナリオを通ってクライアント側に返送します。
![]()
- 分散システムでは、サーバーaがサーバーbにアクセスする場合。http restを用いてデータを伝送し、データもシナリオ化を処理する。
HTTPはアプリケーション層のプロトコールです、Headerの内容が重いので、通信のコストが高いです。
RPCは主にSocketを依頼して通信効率は向上することができますが下層の実装はRESTよりもっと複雑である。
この文章は個人の学習記録です,指摘を歓迎する。
- 投稿日:2021-01-29T09:49:57+09:00
Gradle - How to Import Local .jar Files when Building?
If you need manual import .jar from local when building gradle project, you can add this in the build.gradle file.
Gradle Version : 6.8.1
dependencies { ... ... ... implementation fileTree('your/local/libs/folder') { include '*.jar' } ... ... ... }