- 投稿日:2020-05-25T23:40:27+09:00
JavaでintとIntegerの違い
読者
- Java覚えたて
- Android開発者
- Javaの復習
JavaでintとIntegerの違い
intとIntegerの違い
について掘り下げます。
- intとは?
- -2147483648~2147483647の範囲にある整数値を保持するための32ビットの変数型
- nullは利用不可
- プリミティブ型
- Integerとは?
- –2147483648~2147483647の範囲にある整数値を保持する変数型
- nullは利用可能
- オブジェクト型(クラス型)
Integer型はint型のラッパーであり、int型を操作するためのメソッドが用意されている。
利用例
たとえば、int型からString型へキャスト(型変換)したい場合などで利用されます。
int price = 100; // int -> Integer Integer priceRap = price; // Integer -> String System.out.println("price : " + priceRap.toString()); // Doubleにしたい Double priceDouble = priceRap.doubleValue(); // Doubleにして税金計算とか? Double per = 1.1; System.out.println("Payment amount : " + (priceDouble * per));なぜ?
なぜ、intとIntegerなどが別れて存在しているのかというと、コンピューターはint型などのプリミティブ型を処理します。
WebAPIのJSONでもプリミティブ型を利用して、オブジェクト型は送信しません。
データを加工したり、保存したり、何かしら操作したい場合にInteger型が必要になってきますので、必要に応じて使い分けてください。
- 投稿日:2020-05-25T21:14:54+09:00
GoF javaデザインパターン ざっくり要約
この記事は「Java言語で学ぶ デザインパターン入門」を自分用に要約したものになっています
Iterater
目的
配列などの集合体を順に要素にアクセスする。
内容
hasNext()
は次の要素があるかbooleanで返す。次に要素があるかチェックし、next()を実行
next()
は次の要素のアクセスAdopter
目的
API間のズレをなくす
メリット
二つのAPIの間に入りズレをなくす部品を作ることで、再利用性が高くなる。
既存のクラスに調整を加えずに、目的のインターフェース(API)を実装することTemplate Method
目的
スーパークラスで処理の枠組みを決め、サブクラスで具体的な処理を記述する。
メリット
ロジックは共通化することができる。
注意
親クラスは抽象クラス(abstract)で定義。interfaceだと親クラスは処理を書くことはできない。
Factory Method
目的
インスタンス生成を親クラスで定義する(具体的なクラス名は定義しない)。子クラスでは肉付けを行う。
Singleton
目的
たった一つだけしか、インスタンス生成をしない
コンストラクタをprivateにすることで、クラス外でインスタンス生成ができないようにする。
インスタンスのアクセス方法は、getInstance()で唯一のインスタンスを返すだけにする。注意
private static Singleton singleton = null; if(singleton == null){ singleton = new Singleton; }という条件式だと複数スレッドで実行したときにマシンの状態によって複数インスタンスが作成されてしまうことがある。非同期にするか、事前に作成しておく。
Prototype
目的
コピーしてインスタンスを作る。
注意
cloneメソッドはshallow copy。インスタンスの中身までをコピーするdeep copyはオーバーライドして実装。
shallow copyはインスタンスのフィールドの内容をそのままコピーするだけ。
cloneメソッドは初期化はしないため別で初期化する必要ありBuilder
目的
全体の構造を親クラスで作り、段階を踏んで複雑な処理を積み上げていく
独立性を高めることで、修正箇所や追加箇所をわかりやすくする。Abstract Factory
目的
抽象的な工場と抽象的な部品を使用する。
注意
具体的な工場を追加するのは簡単。
新たに部品を追加するのは困難(具体的な工場全体に)Bridge
目的
機能と実装をわけ、橋渡しをする。
機能・・・処理など
実装・・・実装に使用する場合のクラス機能を増やすと実装クラスには全て機能が追加されるため、機能を増やしやすくなる。
注意
実装が複雑になってしまうことが多いため、実装の部分を頻繁に変える場合のみ使用する。例えば、OS依存に対する対応は、
機能は修正せずに、実装だけ変えることができる。Facade
目的
インターフェースを単純化する。
複雑な処理を隠蔽する。複雑な処理の窓口役になる。注意
packageのみだけしかアクセスできないようにするには、
//public public class Sample{ } // package内でしかアクセスできないようにする。 class Sample{ }Strategy
目的
アルゴリズムを変えることができる。
委譲を使うことで継承より弱い結びつきになり、アルゴリズムを簡単に変えることができる。Composite
目的
木構造にする。
容器と中身を同一視して、再帰的な構造にする。
composite -> 「混合物」「複合物」FileDirectory
ファイルディレクトリはファイルとディレクトリがある。
ファイルを順に見ていくとき、サブディレクトリかファイルかは同一視して見ていく。
DirectoryはEntryに再起的にアクセス可能。
Fileは木構造だとすると、葉
Directoryは枝。例
- HTML
- メニュー表
Decorator
目的
機能の核から、一皮一皮上から被せて、追加していく。
中身を追加せずに、機能を追加することができる。
委譲を使うことで、緩やかな結合をするため、動的な機能追加ができる。
透過的なインターフェース(API)を保ったまま、オブジェクトを被せて機能を追加していく。デメリット
小さいクラスが増えてしまう。
(番外編)継承と委譲
継承 -サブクラスは、スーパークラスと同一視することができる-
class Parent { ... void parentMethod(){ ... } }class Child extends Parent { ... void childMethod(){ ... } }Parent obj = new Child();
obj.parentMethod();
Childのインスタンスは、Parent型の変数にそのまま代入できる。Parentから継承しているメソッドを呼び出すことができる。
つまり、
ChildのインスタンスをあたかもParentのインスタンスであるかのように扱っている。
これはサブクラスをスーパークラスと見なす例
逆に
スーパークラスをサブクラスだと見なすにはキャストが必要Parent obj = new Child();
((Child)obj).childMethod();委譲 -自分と委譲先を同一視
委譲を使ってインターフェースが透過的になっている場合は、自分と委譲先の同一視をすることが可能
class Rose { Violet obj = ... void method(){ obj.method(); } }class Violet { void method(){ ... } }RoseとVioletは同じメソッドを持っていて、RoseはVioletに委譲している...が共通のメソッドと言うのが明記されていない。
abstract class Flower { abstract void method(); } interface Flower { abstract void method(); }上記のように明記することが可能
場合によって使い分ける。Visitor
目的
データ構造と処理を分ける。データ構造を訪問するvisitorクラスを作って、そのクラスに処理をしてもらう。
データ構造を保持している要素に特定の処理をする。
Visitorパターンは、 FileクラスやDirectoryクラスの 部品としての独立性を高めていることになる。 もし、 処理の内容をFileクラスや Directoryクラスのメソッドとしてプログラムしてしまうと、 新しい「処理」を追加して機能拡張したくなるたびに、 FileクラスやDirectoryクラスを修正しなければならなくなる。その他
LSP(リスコフの置換原則)
親クラスが関係式に対し真であれば、親クラスの派生した小クラスも真である。(置換可能性)
The Open-Closed Principle
特別な理由がない限り将来の拡張を禁止してはいけない。
しかし、拡張を行うたびに既存のクラスが修正しなくてはならないのはだめ。つまり、既存のクラスを修正せずに拡張できるようにせよ
ということ。再利用性の高いクラスは閉じられている。
Stringは再利用性が高い、また拡張すると効率が悪くなってしまうため、閉じられている。(finalクラスで定義されているため拡張できない)
- 投稿日:2020-05-25T19:02:44+09:00
SpringBoot中Property和Message的加载顺序问题
Spring boot中属性文件加载顺序
- spring.profiles.include=test1,test2 按照test1,test2的顺序进行加载
- 无论key定义在哪个文件中,最终生效的总是最后一次加载的key的值
Spring boot 中message文件加载顺序
- spring.messages.basename=messages1,messages2按照messages1,messages2的顺序进行文件加载
- 定义在同一个文件中的相同messageId,总是后加载的有效(覆盖)
- 定义在不同文件中的相同messageId,总是先加载的有效(之前property文件已存在则后续相同key不加载)
- 投稿日:2020-05-25T17:14:38+09:00
【初心者向け】コンパイル時にクラスが見つからない時、どこを見直すべきか
記事の対象読者
Javaコマンドを自分でタカタカして、コンパイルとか実行周りの勉強してみようと思った時、
ソースコード書いて、フォルダ階層作って、ソースコードを配置して、と手順を踏み、
いざ、javacコマンドでコンパイルする段になると「シンボルを見つけられません」
この1行のせいでいつまでたってもクラスファイルの作成ができないなんてことありませんか。
構文エラーって割と細かく情報が出るので、原因箇所の特定がしやすいのですが
ことクラスが見つからないってエラーに関しては実装内容ごとに修正点は違うので、
「ここをこう直せば直るよ!」というものはなかったりします。ですが、初学者に真に必要なのは
「どう直すか」という個別ケースにしか使えない情報ではなく、
「仕組み上、ここを見れば原因がわかる」という使い回しのきく
デバッグの知識なんじゃないかなと思います。この度、コンパイル周りの仕組みを勉強したら「シンボルを見つけられません」に対して
どのようにアプローチすればいいのか、というものがそれなりに見えてきたので、
現時点での私のデバッグ手順に関して、紹介したいなと思います。視点1:クラス名は合っているか
傷は浅いほうがいい。のちに紹介する観点で壮大な調査を行なった結果、
エラー原因がただのタイピングミスだった日にはつらすぎるので、
まずはTest.javaクラスの宣言がpublic class Tst
になってたりしないか(一例です)
タイピングミスを疑います。
クラスの宣言、パッケージの指定以外は、割と構文エラーに引っかかってくるので
私はそこまで深追いしません。視点2:クラスの種類は何か
ここでの種類とは、見つからないクラスが
ブートストラップクラスなのか、jarファイルに格納されたクラスなのか、
ユーザクラスなのかということです。ブートストラップクラス、ユーザクラスの詳細について知りたい方は、
Javaのクラスローダやコンパイル時の型の検索について調べてみてください。ここでは細かな話は抜きにして、ざっくりと紹介します。
- ブートストラップクラス
JDKのコアAPIなど、よく使うjava.langパッケージなどの中核機能はこちらに含まれます。- ユーザクラス
ユーザ(プログラマ)が独自に作成するクラスです。ユーザ定義クラスとも言います。- jarファイルに格納されたクラス
サードパーティライブラリ、ユーザが独自に定義したライブラリなどいろいろですが、
eclipseなんかでよくビルドパスに追加するアレです。ここで判断できることは何かというと、見つからないクラスが
ブートストラップクラスの場合には「JDKを指定してるJavaの環境変数」を
ユーザクラスの場合には「クラスパス変数」を疑おうぜっていうことです。ブートストラップクラスなのか判断できん。
という場合は、コアAPIドキュメントなどを参考に。ブートストラップクラスが見つからない場合
JDKが指定できていない、ということなので、環境変数「JAVA_HOME」が
きちんと設定できているか、見直してみましょう。
JAVA_HOMEの設定方法に関しては記事も多く出ているので割愛します。jarファイル内のクラスが見つからない場合
jarファイルのクラスパス指定は、クラスファイルのクラスパスの指定とは少し異なります。
とは行っても、指定するのがディレクトリなのか、jarファイルそのものなのかの違いだけです。
コマンドの文法が正しいか、確認してみましょう。# jarの場合 $ javac -classpath /lib/example-lib.jar Example.java # クラスファイルの場合 $ javac -classpath /lib Example.javaユーザクラスが見つからない場合
こっちのケースの場合には見るべき観点が少し増えます。
こちらに該当する場合は、以降の内容を読み進めてください。視点3:クラスパスは正しく指定されているか
ユーザクラス、サードパーティライブラリの読み込みは、
兎にも角にもクラスパスの指定が正しくなければなりませんし、
クラスパス指定の仕組みをきちんと理解しないとなんとなくでは動いてくれません。以下、クラスパスを見直す際の観点について紹介していきます。
なお、紹介順通りに調査しなければならないということはありません。視点3-1:パッケージルートを指定しているか
以外と他の説明に押しやられてさらっと無視されている、
「クラスパスにパッケージの階層を指定するとうまくimportされない」という事実。
というか当たり前すぎて書かれていないんだろうけど、私はここで引っかかりました。どういうことかというと、以下のようなフォルダ構成があり、UseCommons.javaでは
StrFactoryを使用したいのでcom.example.util
をインポートしているとします。
UseCommons.javapackage com.example.util;上記の場合、srcはパッケージルート、com〜appはパッケージ階層という風に認識されます。
これらをコンパイルする際、私が何をしたかというと# カレントディレクトリは/srcです $ javac -classpath /src/com/example/util com/example/app/UseCommons.java上記のように、クラスパスに
/src/com/example/util
を指定することで、
util配下のクラスを読み込んで、UseCommons.javaをコンパイルしたかったわけです。
ですが、Javaはクラスパスで指定したディレクトリを起点にパッケージ階層をたどるため、
上記のように設定すると、UseCommons.javaがStrFactory.javaを見に行く際に、
/src/com/example/util/com/example/util
を見に行ってしまうわけです。つまり、正しいクラスパスはパッケージルートであるsrcを指定した、以下になります。
# カレントディレクトリは/srcです $ javac -classpath /src com/example/app/UseCommons.java以上の観点から、-classpathオプションに指定したパッケージルートと
クラスファイルに宣言したimport文の内容を連結させた場所に、
読み込みたいクラスが配置されているかを確認してみましょう。視点3-2:デフォルト設定が無効になっていないか
これが一番の曲者だと思います。
デフォルトで設定していたものがオプションの指定などで上書きされ、
必要な設定まで無効になっていたりすると、普段は意識していない分、気づきづらいです。-classpathには通常、「.(カレントディレクトリ)」が設定されています。
それらを踏まえ、以下の例を見てください。
最初は、上記のような構成だったため、以下のコマンドで正常にコンパイルできます。
# カレントディレクトリは/srcです $ javac com/example/app/UseCommons.javaところがこの後、UseCommons.javaで外部のライブラリ「commons-lang3-3.10.jar」を
使用することになり、フォルダ構成を以下の通り変更しました。
そして、commonsのライブラリをクラスパスに追加し、以下のコマンドを実行したところ、
StrFactoryが見つからないというエラーが発生します。# カレントディレクトリは/srcです $ javac -classpath /lib/commons-lang3-3.10.jar com/example/app/UseCommons.javaこれは、classpathオプションのデフォルト設定である「.(例のカレントディレクトリは/src)」が
上書きされたことで、Javaがsrc配下のクラスを検索できなくなったためです。
よって、上記のコマンドを以下のように修正すると、エラーは解消されます。# カレントディレクトリは/srcです $ javac -classpath /lib/commons-lang3-3.10.jar:. com/example/app/UseCommons.java終わりに
以上が、現在の私が持ちうるコンパイル時のデバッグ観点です。
この他にも様々な見方があると思いますので、あくまでも初心者の方の勉強の
最初の一歩の手助けとして、認識していただければと思います。
観点は広い方がいいので、私自身もさらに学びを深めたいと思います。また、他の記事でJavaのコンパイルについても書いておりますので、
コンパイルの仕組みについて興味が出たという方は、以下の記事も参照してみてください。記事へのリンク:Javaコマンド入門 第3章 ソースコードをコンパイルする
- 投稿日:2020-05-25T16:31:10+09:00
[Quarkus]GCP Pub/Subサンプルをそのままコピペしても動かない罠
- 投稿日:2020-05-25T13:38:16+09:00
Javaのコンソールへの入力
コンソールへの入力
コンソールに値を入力し、その値をプログラム内で使うことです。
コンソールへの入力を受け取るにはScannerというライブラリを使います。
Scannerは「import java.util.Scanner」を使います。
【例】Main.javaimport java.util.Scanner; class Main { public static void main(String[]args) { Scanner scanner = new Scanner(System.in); //Scannerで初期化 String name = scanner.next(); //文字列の入力の受け取り } }new Scanner(System.in);で初期化します。
scanner.next();で文字列の入力を受け取ります。Scannerの使い方
まずScannerを初期化しscannerという変数にいれています。
Scannerではこの初期化したものを代入した変数を使ってメソッドを呼び出します。
scanner.next()で、コンソールに入力された文字列を受け取ります。
【例】Main.javaimport java.util.Scanner; class Main { public static void main (String[] args) { Scanner scanner = new Scanner(System.in); System.out.print("名前: "); String name = scanner.next(); System.out.println(name + "さん"); } }上記を実行すると「名前:」と出るので、そこで文字列を入力すれば、〇〇さんと出力されます。
数値の入力を受けとり方
先ほどと同様にScannerを使います。
整数を受け取るメソッドはnextIntメソッド、小数を受け取るメソッドはnextDoubleメソッドを使います。
【例】Main.javaimport java.util.Scanner; class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.print("名前:"); String firstName = scanner.next(); System.out.print("名字:"); String lastName = scanner.next(); System.out.print("年齢:"); int age = scanner.nextInt(); //nextIntメソッドで整数を受け取ります System.out.print("身長(m):"); double height = scanner.nextDouble(); //nextDoubleメソッドで少数を受け取ります System.out.print("体重(kg):"); double weight = scanner.nextDouble(); Person.printData(Person.fullName(firstName, lastName), age, height, weight); } }
- 投稿日:2020-05-25T11:55:31+09:00
JavaはWord文書にテーブルを作成します
Word文書では、表を使用することにより、テキストの内容をより簡潔かつ明確にすることができ、同時にデータの表示をより明確かつ直感的にすることができます。この記事では、Javaコードを使用してWord文書にテーブルを作成し、セルの背景色を設定する方法を紹介します。
使用ツール: Free Spire.Doc for Java(無料版)
JARファイルのインポート方法
方法1: Free Spire.Doc for Javaパッケージをダウンロードして解凍し、Spire.Doc.jarパッケージをlibフォルダーからJavaアプリケーションにインポートします。方法2: mavenを使用している場合は、pom.xmlファイルに次の依存関係を追加する必要があります。
<repositories> <repository> <id>com.e-iceblue</id> <name>e-iceblue</name> <url>http://repo.e-iceblue.com/nexus/content/groups/public/</url> </repository> </repositories> <dependencies> <dependency> <groupId>e-iceblue</groupId> <artifactId>spire.doc.free</artifactId> <version>2.7.3</version> </dependency> </dependencies>Javaコード例:
import com.spire.doc.*; import com.spire.doc.documents.*; import com.spire.doc.fields.TextRange; import java.awt.*; public class CreateTable { public static void main(String[] args) { //Word文書を作成する Document document = new Document(); //sectionを追加 Section section = document.addSection(); //表形式のデータ String[] header = {"名前", "性別", "部門", "ジョブ番号"}; String[][] data = { new String[]{"Winny", "女性", "会計士", "0109"}, new String[]{"Lois", "女性", "販売員", "0111"}, new String[]{"Jois", "男性", "技術スタッフ", "0110"}, new String[]{"Moon", "女性", "販売員", "0112"}, new String[]{"Vinit", "女性", "支援スタッフ", "0113"}, }; //テーブルを追加 Table table = section.addTable(true); //テーブルの行と列の数を設定する table.resetCells(data.length + 1, header.length); //最初の行をテーブルヘッダーとして設定し、データを追加する TableRow row = table.getRows().get(0); row.isHeader(true); row.setHeight(20); row.setHeightType(TableRowHeightType.Exactly); row.getRowFormat().setBackColor(Color.gray); for (int i = 0; i < header.length; i++) { row.getCells().get(i).getCellFormat().setVerticalAlignment(VerticalAlignment.Middle); Paragraph p = row.getCells().get(i).addParagraph(); p.getFormat().setHorizontalAlignment(HorizontalAlignment.Center); TextRange range1 = p.appendText(header[i]); range1.getCharacterFormat().setFontName("Arial"); range1.getCharacterFormat().setFontSize(12f); range1.getCharacterFormat().setBold(true); } //残りの行にデータを追加する for (int r = 0; r < data.length; r++) { TableRow dataRow = table.getRows().get(r + 1); dataRow.setHeight(25); dataRow.setHeightType(TableRowHeightType.Exactly); dataRow.getRowFormat().setBackColor(Color.white); for (int c = 0; c < data[r].length; c++) { dataRow.getCells().get(c).getCellFormat().setVerticalAlignment(VerticalAlignment.Middle); TextRange range2 = dataRow.getCells().get(c).addParagraph().appendText(data[r][c]); range2.getCharacterFormat().setFontName("Arial"); range2.getCharacterFormat().setFontSize(10f); } } //セルの背景色を設定する for (int j = 1; j < table.getRows().getCount(); j++) { if (j % 2 == 0) { TableRow row2 = table.getRows().get(j); for (int f = 0; f < row2.getCells().getCount(); f++) { row2.getCells().get(f).getCellFormat().setBackColor(new Color(173, 216, 230)); } } } //ドキュメントを保存します document.saveToFile("Table.docx", FileFormat.Docx_2013); } }
- 投稿日:2020-05-25T11:03:36+09:00
Macでインポートする際、Gradleビルドが止まってしまう時
発生している問題・エラーメッセージ
表題の通りSTSでSpringbootを使用したアプリケーションの作成時にインポートをする際、
ビルド中に固まってしまい、STSが完全に止まってしまった。
エラーメッセージを見てみるとorg.gradle.tooling.BuildException: Gradle distribution 'https://services.gradle.org/distributions/gradle-5.4.1-bin.zip' を使用してビルド・アクションを実行できませんでした。が出てくる。
結論
https://stackoverrun.com/ja/q/11329562
こちらの回答にある、ユーザーディレクトリの隠しフォルダにある.gradle/caches/5.4.1にある
「scripts」および「scripts-remapped」フォルダを移動し、STSを再起動→インポートでビルドが出来た。いろいろと試したこと
・Gradleのバージョンが原因だと思い、最新バージョンでビルド。
→STSが固まった。・Eclipseのメモリが原因?
https://qiita.com/crarrry/items/7601290c11f7a310913b
こちらを参考に、メモリを上げてみた。
→STSが固まった。・毎回同じところで固まるので、インポートの途中で変にファイルが作成されていることが原因と特定。
https://stackoverrun.com/ja/q/11329562原因
インポート中に予期せぬ動作終了が起きてしまい、Gradleビルド中に中途半端なファイルが作成されてしまった。
最後に
環境構築に時間を取られがちです。
STSよりもAndroid studioでこういったエラーの情報が多かったので、ご参考になればと思います。補足情報(FW/ツールのバージョンなど)
Mac Catalina バージョン10.15.4
JDK 14.0.1
STS 4.6.1参考
https://qiita.com/crarrry/items/7601290c11f7a310913b
https://stackoverrun.com/ja/q/11329562共に働くWebエンジニアを募集しています!
不動産SHOPナカジツでは自社サービスを作っていく仲間を募集しています。
詳しくはWantedlyからお問い合わせください。
- 投稿日:2020-05-25T10:04:59+09:00
DaprでRubyとJavaを連携させてみる
はじめに
マイクロサービス開発を容易にするDaprをJavaで利用してみたに引き続きDaprです。
チュートリアルのStep6に相当します。
コードは下記を参照
https://github.com/koduki/example-dapr/tree/v01構成概要
チュートリアルではPythonですが、趣味の問題でRubyを使っています。
この構成のポイントはRubyとJavaは直接通信しないどころはRubyはあくまで自分のサイドカーのDaprと話すのであってJavaを起動しているDaprとは直接話さないことです。テストがローカルなので実は直接話すこともできるのですが、分かりやすくJavaのDaprポートを3500, RubyのDaprポートを3600とします。
コード
今回は1秒に一度、対象APIにリクエストを投げるだけの超シンプルなコードです。
javaapp
はJavaアプリのappidです。こちらを使ってDparどうして適切なアプリを自動で発見します。APIが動いているIPとかポート番号の指定は不要です。
Rubyコード内で指定しているhttp://localhost:#{MY_DAPR_PORT}
はJava側のDaprではなくRuby側のDaprです。なので常にlocalhostですし、ポート番号も今回で言えば3500では無く3600です。require 'net/https' require "json" MY_DAPR_PORT=ARGV[0] n = 0 while true do n += 1 params = {data: {orderId: n}} url = "http://localhost:#{MY_DAPR_PORT}/v1.0/invoke/javaapp/method/neworder" uri = URI.parse(url) http = Net::HTTP.new(uri.host, uri.port) headers = { "Content-Type" => "application/json" } response = http.post(uri.path, params.to_json, headers) sleep 1 end実行&確認
では実行してみましょう。DaprはWebアプリだけでは無くコマンドも問題なくラッピングできるようです。
まず、API側を立ち上げます。$ dapr run --app-id javaapp --app-port 8080 --port 3500 ./mvnw quarkus:dev続いて別ターミナルでクライアント側を立ち上げます。
$ dapr run --app-id rubyapp --port 3600 ruby app.rb 3600Java側の実行結果を見ると以下のようになっています。
== APP == orderId: 1 == APP == orderId: 2 == APP == orderId: 3ちゃんと毎秒定期実行されてるのが分かりますね。
dapr list
を実行することで今起動しているDaprの一覧も確認できます。$dapr list APP ID HTTP PORT GRPC PORT APP PORT COMMAND AGE CREATED PID rubyapp 3600 55932 0 ruby app.rb 3600 28m 2020-05-24 21:08.13 44897 javaapp 3500 56777 8080 ./mvnw quarkus:dev 3d 2020-05-21 21:21.30 27471
まとめ
上手くRubyとJavaでDaprを経由して通信ができました。
このアーキテクチャの面白いところはRubyコードもJavaコードもあくまでDaprとしか会話してないのでその間はHTTPなりgRPCなりでセキュリティをさほど気にしなくて良いことです。
通信の暗号化とか認証とかはDapr同士がやれば問題ないのでセキュリティに関する部分を外だしできるのは大きいですね。分散トレーシングとかTwitter APIやKafkaなど他のコネクタもあるはずなのでそこら辺も試してみたいと思います。
同じマイクロサービス支援ということでKNativeと似たレイヤーかと最初は思ってたのですが、あちらはビルド環境やFaaS, Servelessと言ったインフラ観点よりなのに対し、こちらはかなりアプリより仕組みなのでCNCFにも採択されてますし今後が気になるツールなのは間違い無いですね。
- 投稿日:2020-05-25T09:36:27+09:00
StringBuilderメモ
可変な文字列であるStringBuilder。文字列を高速に連結するのに使うらしいです。
今回もStringBuilderのメソッドを使用して、使い方を学んでいきます。append
appendを使って文字列の追加処理が可能です。
boolean型、char型、String型、配列などいろんな型を文字列として追加することができます。StringBuilder sb = new StringBuilder("おはよう"); //boolean boolean bool = true; System.out.println(sb.append(bool)); //char char c = 'A'; System.out.println(sb.append(c)); StringBuilder sbr = new StringBuilder("Aさん"); //配列 String[] str = {"こんにちは","おやすみ"}; System.out.println(sbr.append(str[0])); System.out.println(sbr.append(str[1])); StringBuilder s = new StringBuilder("Aさん"); //int,double,float,long int i = 100; double d = 100; float f = 100; long l = 100; System.out.println(s.append(i)); System.out.println(s.append(d)); System.out.println(s.append(f)); System.out.println(s.append(l));//boolean おはようtrue //char おはようtrueA //配列 Aさんこんにちは Aさんこんにちはおやすみ //int Aさん100 //double Aさん100100.0 //float Aさん100100.0100.0 //long Aさん100100.0100.0100charAt(int index)
このシーケンス内の指定されたインデックスのchar値を返します。
StringBuilder sb = new StringBuilder("ABCDs"); System.out.println(sb.charAt(0)); System.out.println(sb.charAt(2)); System.out.println(sb.charAt(4));A C sdelete(int start, int end)
このシーケンスの部分文字列内の文字を削除します。
start - 開始インデックス(この値を含む)。
end - 終了インデックス(この値を含まない)。StringBuilder sb = new StringBuilder("ABCDs"); sb.delete(1, 3); System.out.println(sb);ADs
deleteCharAt(int index)
このシーケンス内の指定された位置にあるcharを削除します。
StringBuilder sb = new StringBuilder("ABCDs"); sb.deleteCharAt(2); System.out.println(sb.toString());ABDs
indexOf(String str)
この文字列内で、指定された部分文字列が最初に出現する位置のインデックスを返します。
StringBuilder sb = new StringBuilder("ABCDs"); System.out.println(sb.indexOf("C")); System.out.println(sb.indexOf("s"));2 4indexOf(String str, int fromIndex)
指定されたインデックス以降で、指定された部分文字列がこの文字列内で最初に出現する位置のインデックスを返します。
StringBuilder sb = new StringBuilder("ABCDsD"); System.out.println(sb.indexOf("D",2)); System.out.println(sb.indexOf("s",0));3 4lastIndexOf(String str)
この文字列内で、指定された部分文字列が一番右に出現する位置のインデックスを返します。
StringBuilder sb = new StringBuilder("ABCDssD"); System.out.println(sb.lastIndexOf("D")); System.out.println(sb.lastIndexOf("s"));6 5length()
長さ(文字数)を返します。
StringBuilder sb = new StringBuilder("ABCDssD"); System.out.println(sb.length());7
replace(int start, int end, String str)
このシーケンスの部分文字列内の文字を、指定されたString内の文字で置き換えます。
StringBuilder sb = new StringBuilder("ABCDssD"); System.out.println(sb.replace(2, 5, "r"));ABrsD
reverse()
この文字シーケンスを、シーケンスの順序を逆にしたもので置き換えます。
StringBuilder sb = new StringBuilder("ABCDssD"); System.out.println(sb.reverse());DssDCBA
setCharAt(int index, char ch)
指定されたインデックスの文字がchに設定されます。
StringBuilder sb = new StringBuilder("ABCDssD"); sb.setCharAt(1, 's'); System.out.println(sb.toString());AsCDssD
setLength(int newLength)
文字シーケンスの長さを設定します。
StringBuilder sb = new StringBuilder("ABCDssD"); System.out.println(sb.length()); sb.setLength(20); System.out.println(sb.length());7 20subSequence(int start, int end)
このシーケンスのサブシーケンスである新規文字シーケンスを返します。
start - 開始インデックス(この値を含む)。
end - 終了インデックス(この値を含まない)。StringBuilder sb = new StringBuilder("ABCDssD"); System.out.println(sb.subSequence(0, 2)); System.out.println(sb.subSequence(4, 5));AB ssubstring(int start), substring(int start, int end)
この文字シーケンスに現在含まれている文字の部分シーケンスを含む新しいStringを返します。
StringBuilder sb = new StringBuilder("ABCDssD"); System.out.println(sb.substring(2)); System.out.println(sb.substring(5)); System.out.println(sb.substring(5,6)); System.out.println(sb.substring(0,2));CDssD sD s ABinsert
指定インデックスに指定した値を挿入する
StringBuilder sb = new StringBuilder("ABCDssD"); //0番目に'P'を挿入する sb.insert(0, 'P'); System.out.println(sb.toString()); //8番目に23を挿入する sb.insert(8, 23); System.out.println(sb.toString()); int[] i = {10,20,30,40}; //0番目にi配列のインデックス2を挿入する sb.insert(0, i[2]); System.out.println(sb.toString());PABCDssD PABCDssD23 30PABCDssD23capacity()
現在の容量を返します。
StringBuilder s = new StringBuilder(); //初期容量が16文字 System.out.println(s.capacity()); //初期容量16 + 追加14文字で現在の容量が30文字 StringBuilder sb = new StringBuilder("ABCDssDAAAAAAA"); System.out.println(sb.capacity());16 30trimToSize()
この文字シーケンスで使用されているストレージの低減を試みます。
StringBuilder sb = new StringBuilder("A"); //初期容量16 + 追加1文字で現在の容量が17文字 System.out.println(sb.capacity()); //初期容量分の16文字が削除され、1文字 sb.trimToSize(); System.out.println(sb.capacity()); StringBuilder s = new StringBuilder("AAAAAAAAAA"); //初期容量16 + 追加10文字で現在の容量が26文字 System.out.println(s.capacity()); //初期容量分の16文字が削除され、10文字 s.trimToSize(); System.out.println(s.capacity());17 1 26 10
- 投稿日:2020-05-25T09:31:22+09:00
[Spring Boot] ページング処理簡単レシピ
環境
言語 : java 1.8
フレームワーク : spring boot 2.2.4.RELEASE (spring-boot-starter)
テンプレートエンジン : thymeleaf 2.2.4.RELEASE (spring-boot-starter)
データベース : H2 1.4.200 (spring-boot-starter)
orm : data-jpa 2.2.4.RELEASE (spring-boot-starter)ソースコード
Entity
import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; @Entity public class Board { @Id @GeneratedValue private String id; private String title; private String user; // Getter・Setter省略 }Pagination
public class Pagination { /** 1. ページことに表示する掲示物数 **/ private int pageSize = 10; /** 2. ページングした、ブロック数 **/ private int blockSize = 10; /** 3. 現在ページ **/ private int page = 1; /** 4. 現在ブロック **/ private int block = 1; /** 5. 総掲示物数 **/ private int totalListCnt; /** 6. 総ページ数 **/ private int totalPageCnt; /** 7. 総ブロック数 **/ private int totalBlockCnt; /** 8. ブロックスタートページ **/ private int startPage = 1; /** 9. ブロック最後ページ **/ private int endPage = 1; /** 10. DB接近スタートインデックス **/ private int startIndex = 0; /** 11. 以前ブロックの最後ページ **/ private int prevBlock; /** 12. 次のブロックの最後ページ **/ private int nextBlock; // Getter・Setter省略 public Pagination(int totalListCnt, int page) { // 総掲示物数と現在ページはコントローラーからもらう。 // 総掲示物数 - totalListCnt // 現在ページ - page /** 3. 現在ページ **/ setPage(page); /** 5. 総掲示物数 **/ setTotalListCnt(totalListCnt); /** 6. 総ページ数 **/ setTotalPageCnt((int) Math.ceil(totalListCnt * 1.0 / pageSize)); /** 7. 総ブロック数 **/ setTotalBlockCnt((int) Math.ceil(totalPageCnt * 1.0 / blockSize)); /** 4. 現在ブロック **/ setBlock((int) Math.ceil((page * 1.0)/blockSize)); /** 8. ブロックスタートページ **/ setStartPage((block - 1) * blockSize + 1); /** 9. ブロック最後ページ **/ setEndPage(startPage + blockSize - 1); /* === ブラック最後ページについてバリエーション ===*/ if(endPage > totalPageCnt){this.endPage = totalPageCnt;} /** 11. 以前ブロックの最後ページ **/ setPrevBlock((block * blockSize) - blockSize); /* === 以前ブロックについてバリエーション === */ if(prevBlock < 1) {this.prevBlock = 1;} /** 12. 次のブロックの最後ページ **/ setNextBlock((block * blockSize) + 1); /* === 次のブロックについてバリエーション ===*/ if(nextBlock > totalPageCnt) {nextBlock = totalPageCnt;} /** 10. DB接近スタートインデックス **/ setStartIndex((page-1) * pageSize); } }Controller
@GetMapping("/") public String home(Model model, @RequestParam(defaultValue = "1") int page) { // 総掲示物数 int totalListCnt = boardRepository.findAllCnt(); // 総掲示物数と現在ページ Pagination pagination = new Pagination(totalListCnt, page); // DB接近スタートインデックス int startIndex = pagination.getStartIndex(); // ページことに表示する掲示物最大数 int pageSize = pagination.getPageSize(); // 掲示物取得 List<Board> boardList = boardRepository.findListPaging(startIndex, pageSize); // モデルオブジェクトにオブジェクト格納 model.addAttribute("boardList", boardList); model.addAttribute("pagination", pagination); return "index"; }Repository
@Repository public class BoardRepository { @PersistenceContext private EntityManager em; public int findAllCnt() { return ((Number) em.createQuery("select count(*) from Board") .getSingleResult()).intValue(); } public List<Board> findListPaging(int startIndex, int pageSize) { return em.createQuery("select b from Board b", Board.class) .setFirstResult(startIndex) .setMaxResults(pageSize) .getResultList(); } }html
<!DOCTYPE html> <html lang="ja" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>paging</title> <link rel="stylesheet" th:href="@{/css/bootstrap.min.css}"> </head> <body> <table class="table table-striped"> <thead class="thead-dark"> <tr> <th scope="col" style="width: 10%">no</th> <th scope="col">title</th> <th scope="col" style="width: 15%">user</th> </tr> </thead> <tbody> <tr th:each="board : ${boardList}"> <th scope="row" th:text="${boardStat.index + 1}">1</th> <td th:text="${board.title}"></td> <td th:text="${board.user}"></td> </tr> </tbody> </table> // ページング <nav aria-label="Page navigation example "> <ul class="pagination"> <li class="page-item"> <a class="page-link" th:href="@{/?page=1}" aria-label="Previous"> <span aria-hidden="true"><<</span> </a> </li> <li class="page-item"> <a class="page-link" th:href="@{/?page={page} (page = ${pagination.prevBlock})}" aria-label="Previous"> <span aria-hidden="true"><</span> </a> </li> <th:block th:with="start = ${pagination.startPage}, end = ${pagination.endPage}"> <li class="page-item" th:with="start = ${pagination.startPage}, end = ${pagination.endPage}" th:each="pageButton : ${#numbers.sequence(start, end)}"> <a class="page-link" th:href="@{/?page={page} (page = ${pageButton})}" th:text=${pageButton}></a> </li> </th:block> <li class="page-item"> <a class="page-link" th:href="@{?page={page} (page = ${pagination.nextBlock})}" aria-label="Next"> <span aria-hidden="true">></span> </a> </li> <li class="page-item"> <a class="page-link" th:href="@{?page={page} (page = ${pagination.totalPageCnt})}" aria-label="Previous"> <span aria-hidden="true">>></span> </a> </li> </ul> </nav> </body> </html>備考
- Getter・Setterはlombokを使うと簡単に追加可能。(https://projectlombok.org/)
- 投稿日:2020-05-25T09:13:08+09:00
Ruby Python Java 大文字小文字を区別しないソート
はじめに
ソートと言えば、数値順・辞書順ですが、それ以外のソートについて調べてみました。
嵌った話
@jag_507 さんのAtCoderでRuby学習10【第一回アルゴリズム実技検定 DoubleCamelCase Sort】を読んで、AtCoder 第一回アルゴリズム実技検定 F - DoubleCamelCase Sortをやってみましたが、ソートがうまくいかないです。
sort.rba = ["FisH", "DoG", "CaT", "AA", "AaA", "AbC", "AC"] a.sort # => ["AA", "AC", "AaA", "AbC", "CaT", "DoG", "FisH"] # 実際の返り値 ["AA", "AaA", "AbC", "AC", "CaT", "DoG", "FisH"] # 期待する返り値この記事:sortコマンド、基本と応用とワナの様な
-f
オプションはないのか、ドラえもんGoogle先生助けてー。大文字小文字を区別しないソート
Ruby に限らず多くのプログラミング言語の
辞書順のソートはASCIIコード順での並び替え
になりますので、大文字と小文字では大文字が若くなります。
そこで、大文字小文字を区別しないソートが必要になります。Ruby
ruby.rba = ['a', 'b', 'c', 'd', 'e', 'A', 'B', 'C', 'D', 'E'] p a.sort # => ["A", "B", "C", "D", "E", "a", "b", "c", "d", "e"] p a # => ["a", "b", "c", "d", "e", "A", "B", "C", "D", "E"] p a.sort{|x, y| x.casecmp(y).nonzero? || x <=> y} # => ["A", "a", "B", "b", "C", "c", "D", "d", "E", "e"] p a.sort_by{ |s| [s.downcase, s] } # => ["A", "a", "B", "b", "C", "c", "D", "d", "E", "e"]casecomp が大文字小文字を区別しないメソッドになります。
追記
コメント欄よりsort_by
の解法をいただきました。
最優先s.downcase
と次優先s
の2つ条件でソートを行っています。Python
python.pya = ['a', 'b', 'c', 'd', 'e', 'A', 'B', 'C', 'D', 'E'] print(sorted(a)) # => ['A', 'B', 'C', 'D', 'E', 'a', 'b', 'c', 'd', 'e'] print(a) # => ['a', 'b', 'c', 'd', 'e', 'A', 'B', 'C', 'D', 'E'] print(sorted(sorted(a), key=str.lower)) # => ['A', 'a', 'B', 'b', 'C', 'c', 'D', 'd', 'E', 'e']ソート HOW TO に、大文字小文字を区別しない文字列比較の例が載っています。
Python のソートは安定なことが保証されていますので、2重にソートする方法が考えられます。Java
java.javaList<String> a = Arrays.asList("a", "b", "c", "d", "e", "A", "B", "C", "D", "E"); a.sort(Comparator.naturalOrder()); System.out.println(a); // [A, B, C, D, E, a, b, c, d, e] a.sort(String.CASE_INSENSITIVE_ORDER); System.out.println(a); // [A, a, B, b, C, c, D, d, E, e]Java の場合、
CASE_INSENSITIVE_ORDER
が準備されています。まとめ
- 大文字小文字を区別しないソート に詳しくなった
- Ruby に詳しくなった
- Python に詳しくなった
- Java に詳しくなった
- 自然順のソートまで手が回らなかった
参照したサイト
AtCoderでRuby学習10【第一回アルゴリズム実技検定 DoubleCamelCase Sort】
sortコマンド、基本と応用とワナ
casecomp
ソート HOW TO
[Java 8]コーディングテストで使えるアルファベット順、文字列長順のソート方法
- 投稿日:2020-05-25T07:48:08+09:00
OpenTracing チュートリアル 後半
OpenTracing チュートリアル 後半
上記の記事からの続きになります。
Lesson 3のソースをビルドして実行してみる
README.md を見つつ、ソースを編集
src/main/java/lesson03/exercise/Hello.javapackage lesson03.exercise; import java.io.IOException; import com.google.common.collect.ImmutableMap; import io.jaegertracing.internal.JaegerTracer; import io.opentracing.Scope; import io.opentracing.Span; import io.opentracing.Tracer; import io.opentracing.propagation.Format; import io.opentracing.tag.Tags; import lib.Tracing; import okhttp3.HttpUrl; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; public class Hello { private final Tracer tracer; private final OkHttpClient client; private Hello(Tracer tracer) { this.tracer = tracer; this.client = new OkHttpClient(); } private String getHttp(int port, String path, String param, String value) { try { HttpUrl url = new HttpUrl.Builder().scheme("http").host("localhost").port(port).addPathSegment(path) .addQueryParameter(param, value).build(); Request.Builder requestBuilder = new Request.Builder().url(url); Tags.SPAN_KIND.set(tracer.activeSpan(), Tags.SPAN_KIND_CLIENT); Tags.HTTP_METHOD.set(tracer.activeSpan(), "GET"); Tags.HTTP_URL.set(tracer.activeSpan(), url.toString()); tracer.inject(tracer.activeSpan().context(), Format.Builtin.HTTP_HEADERS, new RequestBuilderCarrier(requestBuilder)); Request request = requestBuilder.build(); Response response = client.newCall(request).execute(); if (response.code() != 200) { throw new RuntimeException("Bad HTTP result: " + response); } return response.body().string(); } catch (IOException e) { throw new RuntimeException(e); } } private void sayHello(String helloTo) { // Operation: tracer.buildSpan("operationName"); // Generating trace information: tracer.buildSpan(); // Trace start: .start(); Span span = tracer.buildSpan("say-hello").start(); try (Scope scope = tracer.scopeManager().activate(span)) { // Set span tags: span.setTag("key", value); span.setTag("hello-to", helloTo); String helloStr = formatString(helloTo); printHello(helloStr); } finally { span.finish(); // Trace end: span.finish } } private String formatString(String helloTo) { // Operation: tracer.buildSpan("operationName"); // Generating trace information: tracer.buildSpan(); // Trace start: .start(); Span span = tracer.buildSpan("formatString").start(); try (Scope scope = tracer.scopeManager().activate(span)) { // In order to pass its context over the HTTP request we need to call tracer. // inject before building the HTTP request in Hello#getHttp() String helloStr = getHttp(8081, "format", "helloTo", helloTo); // Set span logs: span.log(ImmutableMap.of("key1", "value1", "key2", "value2")); span.log(ImmutableMap.of("event", "string-format", "value", helloStr)); return helloStr; } finally { span.finish(); // Trace end: span.finish } } private void printHello(String helloStr) { // Operation: tracer.buildSpan("operationName"); // Generating trace information: tracer.buildSpan(); // Trace start: .start(); Span span = tracer.buildSpan("printHello").start(); try (Scope scope = tracer.scopeManager().activate(span)) { // In order to pass its context over the HTTP request we need to call tracer. // inject before building the HTTP request in Hello#getHttp() getHttp(8082, "publish", "helloStr", helloStr); // Set span logs: span.log(ImmutableMap.of("key1", "value1")); span.log(ImmutableMap.of("event", "println")); } finally { span.finish(); // Trace end: span.finish } } public static void main(String[] args) { if (args.length != 1) { throw new IllegalArgumentException("Expecting one argument"); } String helloTo = args[0]; // Service: Tracing.init("serviceName"); try (JaegerTracer tracer = Tracing.init("hello-world")) { new Hello(tracer).sayHello(helloTo); } } }src/main/java/lesson03/exercise/Formatter.javapackage lesson03.exercise; import com.google.common.collect.ImmutableMap; import io.dropwizard.Application; import io.dropwizard.Configuration; import io.dropwizard.setup.Environment; import io.opentracing.Scope; import io.opentracing.Span; import io.opentracing.Tracer; import lib.Tracing; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; public class Formatter extends Application<Configuration> { private final Tracer tracer; private Formatter(Tracer tracer) { this.tracer = tracer; } @Path("/format") @Produces(MediaType.TEXT_PLAIN) public class FormatterResource { @GET public String format(@QueryParam("helloTo") String helloTo, @Context HttpHeaders httpHeaders) { // Operation: Tracing.startServerSpan(tracer, httpHeaders, "operationName"); Span span = Tracing.startServerSpan(tracer, httpHeaders, "format"); try (Scope scope = tracer.scopeManager().activate(span)) { String helloStr = String.format("Hello, %s!", helloTo); // Set span logs: span.log(ImmutableMap.of("key1", "value1", "key2", "value2")); span.log(ImmutableMap.of("event", "string-format", "value", helloStr)); return helloStr; } finally { span.finish(); // Trace end: span.finish(); } } } @Override public void run(Configuration configuration, Environment environment) throws Exception { environment.jersey().register(new FormatterResource()); } public static void main(String[] args) throws Exception { System.setProperty("dw.server.applicationConnectors[0].port", "8081"); System.setProperty("dw.server.adminConnectors[0].port", "9081"); // Service: Tracing.init("serviceName"); new Formatter(Tracing.init("formatter")).run(args); } }src/main/java/lesson03/exercise/Publisher.javapackage lesson03.exercise; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import com.google.common.collect.ImmutableMap; import io.dropwizard.Application; import io.dropwizard.Configuration; import io.dropwizard.setup.Environment; import io.jaegertracing.internal.JaegerTracer; import io.opentracing.Scope; import io.opentracing.Span; import io.opentracing.Tracer; import lib.Tracing; public class Publisher extends Application<Configuration> { private final Tracer tracer; private Publisher(Tracer tracer) { this.tracer = tracer; } @Path("/publish") @Produces(MediaType.TEXT_PLAIN) public class PublisherResource { @GET public String format(@QueryParam("helloStr") String helloStr, @Context HttpHeaders httpHeaders) { // Operation: Tracing.startServerSpan(tracer, httpHeaders, "operationName"); Span span = Tracing.startServerSpan(tracer, httpHeaders, "publish"); try (Scope scope = tracer.scopeManager().activate(span)) { System.out.println(helloStr); // Set span logs: span.log(ImmutableMap.of("key1", "value1", "key2", "value2")); span.log(ImmutableMap.of("event", "println", "value", helloStr)); return "published"; } finally { span.finish(); //Trace end: span.finish(); } } } @Override public void run(Configuration configuration, Environment environment) throws Exception { environment.jersey().register(new PublisherResource()); } public static void main(String[] args) throws Exception { System.setProperty("dw.server.applicationConnectors[0].port", "8082"); System.setProperty("dw.server.adminConnectors[0].port", "9082"); // Service: Tracing.init("serviceName"); new Publisher(Tracing.init("publisher")).run(args); } }ビルド
[root@localhost java]# mvn clean package実行
Lesson3.log[root@localhost java]# ./run.sh lesson03.exercise.Formatter server [root@localhost java]# ./run.sh lesson03.exercise.Publisher server [root@localhost java]# curl 'http://localhost:8081/format?helloTo=Bryan' Hello, Bryan! [root@localhost java]# curl 'http://localhost:8082/publish?helloStr=hi%20there' published [root@localhost java]# ./run.sh lesson03.exercise.Hello Bryan 02:50:15.525 [main] DEBUG io.jaegertracing.thrift.internal.senders.ThriftSenderFactory - Using the UDP Sender to send spans to the agent. 02:50:15.628 [main] DEBUG io.jaegertracing.internal.senders.SenderResolver - Using sender UdpSender() 02:50:15.723 [main] INFO io.jaegertracing.Configuration - Initialized tracer=JaegerTracer(version=Java-1.1.0, serviceName=hello-world, reporter=CompositeReporter(reporters=[RemoteReporter(sender=UdpSender(), closeEnqueueTimeout=1000), LoggingReporter(logger=Logger[io.jaegertracing.internal.reporters.LoggingReporter])]), sampler=ConstSampler(decision=true, tags={sampler.type=const, sampler.param=true}), tags={hostname=localhost.localdomain, jaeger.version=Java-1.1.0, ip=127.0.0.1}, zipkinSharedRpcSpan=false, expandExceptionLogs=false, useTraceId128Bit=false) 02:50:17.020 [main] INFO io.jaegertracing.internal.reporters.LoggingReporter - Span reported: 364c6519897fe690:2b596be32a3c8e7d:364c6519897fe690:1 - formatString 02:50:17.091 [main] INFO io.jaegertracing.internal.reporters.LoggingReporter - Span reported: 364c6519897fe690:8506516ad419caaf:364c6519897fe690:1 - printHello 02:50:17.091 [main] INFO io.jaegertracing.internal.reporters.LoggingReporter - Span reported: 364c6519897fe690:364c6519897fe690:0:1 - say-helloJaeger UI でソース通りにトレース情報が生成できているかを確認
README.md で気になった箇所を抜粋
- The tracing instrumentation uses inject and extract to pass the span context through the RPC calls.
- トレーシングのインストルメンテーションでは、RPCコールを介してスパンコンテキストを渡すためにinjectとextractを使用しています。
- Instrumenting the Client In the Hello#formatString() function we already create a child span. In order to pass its context over the HTTP request we need to call tracer.inject before building the HTTP request in Hello#getHttp()
- クライアントのインストルメンテーション Hello#formatString() 関数では、すでに子スパンを作成しています。そのコンテキストを HTTP リクエストに渡すためには、Hello#getHttp() で HTTP リクエストをビルドする前に tracer.inject を呼び出す必要があります。
Inject and Extract に関しては、下記も読んで理解を深めておいたほうがよさそうです。
Lesson 4のソースをビルドして実行してみる
README.md を見つつ、ソースを編集
src/main/java/lesson04/exercise/Hello.javapackage lesson04.exercise; import java.io.IOException; import com.google.common.collect.ImmutableMap; import io.jaegertracing.internal.JaegerTracer; import io.opentracing.Scope; import io.opentracing.Span; import io.opentracing.Tracer; import io.opentracing.propagation.Format; import io.opentracing.tag.Tags; import lib.Tracing; import okhttp3.HttpUrl; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; public class Hello { private final Tracer tracer; private final OkHttpClient client; private Hello(Tracer tracer) { this.tracer = tracer; this.client = new OkHttpClient(); } private String getHttp(int port, String path, String param, String value) { try { HttpUrl url = new HttpUrl.Builder().scheme("http").host("localhost").port(port).addPathSegment(path) .addQueryParameter(param, value).build(); Request.Builder requestBuilder = new Request.Builder().url(url); Tags.SPAN_KIND.set(tracer.activeSpan(), Tags.SPAN_KIND_CLIENT); Tags.HTTP_METHOD.set(tracer.activeSpan(), "GET"); Tags.HTTP_URL.set(tracer.activeSpan(), url.toString()); //tracer.inject(tracer.activeSpan().context(), Format.Builtin.HTTP_HEADERS, new RequestBuilderCarrier(requestBuilder)); tracer.inject(tracer.activeSpan().context(), Format.Builtin.HTTP_HEADERS, Tracing.requestBuilderCarrier(requestBuilder)); Request request = requestBuilder.build(); Response response = client.newCall(request).execute(); if (response.code() != 200) { throw new RuntimeException("Bad HTTP result: " + response); } return response.body().string(); } catch (IOException e) { throw new RuntimeException(e); } } private void sayHello(String helloTo, String greeting) { // Operation: tracer.buildSpan("operationName"); // Generating trace information: tracer.buildSpan(); // Trace start: .start(); Span span = tracer.buildSpan("say-hello").start(); try (Scope scope = tracer.scopeManager().activate(span)) { // Set span tags: span.setTag("key", value); span.setTag("hello-to", helloTo); // Set Baggage: span.setBaggageItem("key", value); span.setBaggageItem("greeting", greeting); String helloStr = formatString(helloTo); printHello(helloStr); } finally { span.finish(); // Trace end: span.finish(); } } private String formatString(String helloTo) { // Operation: tracer.buildSpan("operationName"); // Generating trace information: tracer.buildSpan(); // Trace start: .start(); Span span = tracer.buildSpan("formatString").start(); try (Scope scope = tracer.scopeManager().activate(span)) { // In order to pass its context over the HTTP request we need to call tracer. // inject before building the HTTP request in Hello#getHttp() String helloStr = getHttp(8081, "format", "helloTo", helloTo); // Set span logs: span.log(ImmutableMap.of("key1", "value1", "key2", "value2")); span.log(ImmutableMap.of("event", "string-format", "value", helloStr)); return helloStr; } finally { span.finish(); // Trace end: span.finish(); } } private void printHello(String helloStr) { // Operation: tracer.buildSpan("operationName"); // Generating trace information: tracer.buildSpan(); // Trace start: .start(); Span span = tracer.buildSpan("printHello").start(); try (Scope scope = tracer.scopeManager().activate(span)) { // In order to pass its context over the HTTP request we need to call tracer. // inject before building the HTTP request in Hello#getHttp() getHttp(8082, "publish", "helloStr", helloStr); // Set span logs: span.log(ImmutableMap.of("key1", "value1")); span.log(ImmutableMap.of("event", "println")); } finally { span.finish(); // Trace end: span.finish(); } } public static void main(String[] args) { if (args.length != 2) { throw new IllegalArgumentException("Expecting two arguments, helloTo and greeting"); } String helloTo = args[0]; String greeting = args[1]; // Service: Tracing.init("serviceName"); try (JaegerTracer tracer = Tracing.init("hello-world")) { new Hello(tracer).sayHello(helloTo, greeting); } } }src/main/java/lesson04/exercise/Formatter.javapackage lesson04.exercise; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import com.google.common.collect.ImmutableMap; import io.dropwizard.Application; import io.dropwizard.Configuration; import io.dropwizard.setup.Environment; import io.jaegertracing.internal.JaegerTracer; import io.opentracing.Scope; import io.opentracing.Span; import io.opentracing.Tracer; import lib.Tracing; public class Formatter extends Application<Configuration> { private final Tracer tracer; private Formatter(Tracer tracer) { this.tracer = tracer; } @Path("/format") @Produces(MediaType.TEXT_PLAIN) public class FormatterResource { @GET public String format(@QueryParam("helloTo") String helloTo, @Context HttpHeaders httpHeaders) { // Operation: Tracing.startServerSpan(tracer, httpHeaders, "operationName"); Span span = Tracing.startServerSpan(tracer, httpHeaders, "format"); try (Scope scope = tracer.scopeManager().activate(span)) { // Get baggage: span.getBaggageItem(value); String greeting = span.getBaggageItem("greeting"); if (greeting == null) { greeting = "Hello"; } String helloStr = String.format("%s, %s!", greeting, helloTo); // Set span logs: span.log(ImmutableMap.of("key1", "value1", "key2", "value2")); span.log(ImmutableMap.of("event", "string-format", "value", helloStr)); return helloStr; } finally { span.finish(); //Trace end: span.finish(); } } } @Override public void run(Configuration configuration, Environment environment) throws Exception { environment.jersey().register(new FormatterResource()); } public static void main(String[] args) throws Exception { System.setProperty("dw.server.applicationConnectors[0].port", "8081"); System.setProperty("dw.server.adminConnectors[0].port", "9081"); // Service: Tracing.init("serviceName"); try (JaegerTracer tracer = Tracing.init("formatter")) { new Formatter(tracer).run(args); } } }src/main/java/lesson04/exercise/Publisher.javapackage lesson04.exercise; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import com.google.common.collect.ImmutableMap; import io.dropwizard.Application; import io.dropwizard.Configuration; import io.dropwizard.setup.Environment; import io.jaegertracing.internal.JaegerTracer; import io.opentracing.Scope; import io.opentracing.Span; import io.opentracing.Tracer; import lib.Tracing; public class Publisher extends Application<Configuration> { private final Tracer tracer; private Publisher(Tracer tracer) { this.tracer = tracer; } @Path("/publish") @Produces(MediaType.TEXT_PLAIN) public class PublisherResource { @GET public String format(@QueryParam("helloStr") String helloStr, @Context HttpHeaders httpHeaders) { // Operation: Tracing.startServerSpan(tracer, httpHeaders, "operationName"); Span span = Tracing.startServerSpan(tracer, httpHeaders, "publish"); try (Scope scope = tracer.scopeManager().activate(span)) { System.out.println(helloStr); // Set span logs: span.log(ImmutableMap.of("key1", "value1", "key2", "value2")); span.log(ImmutableMap.of("event", "println", "value", helloStr)); return "published"; } finally { span.finish(); //Trace end: span.finish(); } } } @Override public void run(Configuration configuration, Environment environment) throws Exception { environment.jersey().register(new PublisherResource()); } public static void main(String[] args) throws Exception { System.setProperty("dw.server.applicationConnectors[0].port", "8082"); System.setProperty("dw.server.adminConnectors[0].port", "9082"); // Service: Tracing.init("serviceName"); try (JaegerTracer tracer = Tracing.init("publisher")) { new Publisher(tracer).run(args); } } }ビルド
[root@localhost java]# mvn clean package実行
Lesson4.log[root@localhost java]# ./run.sh lesson04.exercise.Formatter server [root@localhost java]# ./run.sh lesson04.exercise.Publisher server [root@localhost java]# ./run.sh lesson04.exercise.Hello Bryan Bonjour 07:24:05.133 [main] DEBUG io.jaegertracing.thrift.internal.senders.ThriftSenderFactory - Using the UDP Sender to send spans to the agent. 07:24:05.263 [main] DEBUG io.jaegertracing.internal.senders.SenderResolver - Using sender UdpSender() 07:24:05.369 [main] INFO io.jaegertracing.Configuration - Initialized tracer=JaegerTracer(version=Java-1.1.0, serviceName=hello-world, reporter=CompositeReporter(reporters=[RemoteReporter(sender=UdpSender(), closeEnqueueTimeout=1000), LoggingReporter(logger=Logger[io.jaegertracing.internal.reporters.LoggingReporter])]), sampler=ConstSampler(decision=true, tags={sampler.type=const, sampler.param=true}), tags={hostname=localhost.localdomain, jaeger.version=Java-1.1.0, ip=127.0.0.1}, zipkinSharedRpcSpan=false, expandExceptionLogs=false, useTraceId128Bit=false) 07:24:07.408 [main] INFO io.jaegertracing.internal.reporters.LoggingReporter - Span reported: b31a103acb8be300:180478edc119febe:b31a103acb8be300:1 - formatString 07:24:08.217 [main] INFO io.jaegertracing.internal.reporters.LoggingReporter - Span reported: b31a103acb8be300:f1dcd8c815cb525a:b31a103acb8be300:1 - printHello 07:24:08.217 [main] INFO io.jaegertracing.internal.reporters.LoggingReporter - Span reported: b31a103acb8be300:b31a103acb8be300:0:1 - say-helloJaeger UI でソース通りにトレース情報が生成できているかを確認
最後に
以上でOpenTracing チュートリアルは完了です。
もっと詳しい使い方に関しては、下記を参照願います。opentracing.io/docs
- Spans | OpenTracing
- Scopes and Threading | OpenTracing
- Tags, logs and baggage | OpenTracing
- Tracers | OpenTracing
- Inject and extract | OpenTracing
opentracing.io/guides/java
- Spans | OpenTracing Guides Java
- Inject and Extract | OpenTracing Guides Java
- Tracers | OpenTracing Guides Java
- Scopes | OpenTracing Guides Java
- Contributions | OpenTracing Guides Java
参考URL
- Getting Started | OpenTracing
- What is Distributed Tracing? | OpenTacing
- Tutorials | OpenTracing
- OpenTracing Overview | OpenTracing
- Spans | OpenTracing
- Scopes and Threading | OpenTracing
- Tags, logs and baggage | OpenTracing
- Tracers | OpenTracing
- Inject and extract | OpenTracing
- Spans | OpenTracing Guides Java
- Inject and Extract | OpenTracing Guides Java
- Tracers | OpenTracing Guides Java
- Scopes | OpenTracing Guides Java
- Contributions | OpenTracing Guides Java
- Getting started | Jaeger
- Architecture | Jaeger
- OpenTracing Tutorial - Java
- Lesson 3 - Tracing RPC Requests
- Lesson 4 - Baggage
- Jaeger's Tracing Instrumentation Library for Java
- OpenTracingチュートリアルをやってみた(その2)