blog

2020 Java技術に関する質問

Javaにおけるリフレクション\nJavaのリフレクション・メカニズムは実行状態にあり、どのクラスに対しても、クラスのすべてのプロパティとメソッドを取得することができます。実行時に情報へのこの動的なア...

Jul 25, 2020 · 11 min. read
シェア

、Javaのリフレクション

Javaのリフレクション・メカニズムは実行状態にあり、任意のクラスに対して、このクラスのすべてのプロパティとメソッドを取得することができ、任意のオブジェクトに対して、そのプロパティとメソッドのいずれかを呼び出すことができます。このように実行時に情報に動的にアクセスし、オブジェクトのメソッドを動的に呼び出す機能は、Javaのリフレクション機構として知られています。クラスクラスとjava.lang.reflectライブラリが一緒になってリフレクションの概念をサポートし、ライブラリにはField、Method、Constructorクラスが含まれています。

反省の役割

1), オブジェクトが属するクラスを実行時に決定します。

2), 実行時に任意のクラスのオブジェクトを構築する場合

3) クラスが持つメンバ変数とメソッドを実行時に決定します。

4), 実行時にオブジェクトのメソッドを呼び出す場合

利点:動的にオブジェクトを作成し、コンパイルすることができます。

短所:パフォーマンスに影響があります。リフレクションの使用は基本的に、JVMに何をすべきか、どのような要件を満たすべきかを指示するインタプリタ操作であり、そのような操作はJavaコードを直接実行するよりも常に遅くなります。

Javaのリフレクションの使い方

a. 完全修飾クラス名からのオブジェクトの作成

1) Class.forName("完全な制限付きクラス名");

<?> 2) クラス名.class; クラス clazz オブジェクトの取得

3) Object.getClass();

b. コンストラクタのオブジェクトを取得し、コンストラクタを通してオブジェクトを新規作成します。

1) Clazz.getConstructor([String.class]);

2) Con.newInstance([パラメータ]);

c. 参照コンストラクタを使用しないクラスオブジェクトによるインスタンスオブジェクトの作成)

1) Clazz.newInstance();

d. クラス・オブジェクトを介した属性オブジェクトの取得

1) Field c=clazz.getFields(); 親クラスのものも含めて、クラスのすべてのパブリック・フィールドを取得します。

2) Field c=clazz.getDeclaredFields(); クラスのすべての宣言されたフィールドを取得します。

e. クラスオブジェクトを介したメソッドオブジェクトの取得

1) Clazz.getMethod("メソッド名",class.....parameaType);

2) Clazz.getDeclareMethod("メソッド名");

M.setAccessible(true); f. メソッドを実行させます。

Method.invoke(objインスタンスオブジェクト、obj変数パラメータ)。

Springソースコードの解析と実装

Springはオープンソースの軽量Java開発フレームワークです。しかし、Springの用途はサーバーサイドの開発に限定されません。シンプルさ、テスト容易性、疎結合の観点から、大半のJavaアプリケーションはSpringの恩恵を受けることができます。Springの中核は、コントロールとカット指向の反転です。

IOCとは何ですか?

春のIOCアーキテクチャ:

Spring Beanの作成は、典型的なファクトリパターン、この一連のビーンファクトリ、つまり、開発者のためのIOCコンテナは、オブジェクト間の依存関係を管理するために多くの利便性と基本的なサービスを提供し、ユーザーが選択し、使用するためのSpringのIOCコンテナの多くの実装があり、それらの相互関係は次のとおりです:


publicinterfaceBeanFactory {
 //Beanの名前を使用してFactoryBeanを取り出すと,工場で生成されたオブジェクトを得るので,FactoryBeanの定義は逃げる。
 //ファクトリー自体を取得する必要がある場合は 
 StringFACTORY_BEAN_PREFIX ="&";
 //Beanの名前に基づいて,IOCコンテナ内のBeanインスタンスを取得する。 
 ObjectgetBean(Stringname) throws BeansException;
 //Beanの名前及びBeanインスタンスを取得するClass型に従って,型安全検証機構を追加する。
 ObjectgetBean(Stringname, Class requiredType) throws BeansException;
 //IOCコンテナにこの名前のBeanがあるかどうかを調べるために,Beanの検索を提供する。
 beanbooleancontainsBean(Stringname);
 //Bean名に基づいてBeanインスタンスを取得し,Beanがシングルトンであるかどうかを決定する。 
 booleanisSingleton(Stringname) throws NoSuchBeanDefinitionException;
 //ビーンインスタンスのクラス型を取得する 
 Class.getType(Stringname) throws NoSuchBeanDefinitionException;
 //Beanの別名を取得し,別名に基づいて取得される場合は,元の名前も取得する。 
 String[] getAliases(Stringname);}

BeanFactoryでは、IOCコンテナの基本的な動作を定義するだけで、Beanがどのように定義され、ロードされるかは気にしません。ファクトリーだけがオブジェクトの生成物を取得することを気にするように、ファクトリーはこれらのオブジェクトを生成する方法ですが、この基本的なインターフェイスは気にしません。

そして、ファクトリーがどのようにオブジェクトを生成するかを知るには、特定のIOCコンテナの実装を見る必要があります。XmlBeanFactory、ClasspathXmlApplicationContextなどです。XmlBeanFactoryは、IOCコンテナの実装のための最も基本的なIOCコンテナは、BeanDefinitionのXMLファイルの定義を読み取ることができる場合、XmlBeanFactoryは敗者のコンテナは、ApplicationContextは、豊かでハンサムでコンテナとしてカウントする必要があります。

ApplicationContextはSpringが提供する先進的なIoCコンテナで、IoCコンテナの基本的な機能に加え、ユーザーのために以下の追加サービスを提供することができます。ApplicationContextインターフェイスの実装から、その機能を参照してください:

1.国際化できる情報源のサポート。.;

2.リソースへのアクセス.;

3.アプリケーションイベントのサポート.;

春のAOP

AOP(カッター指向プログラミング)は、OOPを補完し、完成させるものです。OOPは、カプセル化、継承、ポリモーフィズムなどの概念を導入し、パブリックな振る舞いのコレクションをモデル化するオブジェクトの階層を作成します。AOP技術は、「クロスカット」と呼ばれる技法を使用して、カプセル化されたオブジェクトの内部を分解し、複数のクラスに影響を与えるパブリックな振る舞いを「アスペクト」、つまりファセットという名前の再利用可能なモジュールにカプセル化します。アスペクトいわゆる "アスペクト "は、簡単に言えば、ビジネスとは何の関係もない人が、共通の呼び出しロジックや責任のビジネスモジュールのためにカプセル化されたシステムコードの重複の削減を容易にし、モジュール間の結合を減らし、将来の操作性と保守性に資するということです。

AOPでは、ソフトウェアシステムを「中核的な関心事」と「横断的な関心事」の2つに分けます。業務処理の主要なプロセスが中核的な関心事であり、それとはあまり関係のない部分が横断的な関心事です。AOPの役割は、システム内のさまざまな関心事を分離し、中核的関心事と横断的関心事を分離することです。

春のAOPサポート

1)、通常のビジネスコンポーネントの定義2)、エントリポイントの定義、エントリポイントは、ビジネスコンポーネントの数にまたがってカットすることができます3)、処理の強化の定義は、処理の強化は、通常のビジネスコンポーネントのAOPフレームワークは、処理アクションに織り込まれています。

つまり、AOPプログラミングの鍵は、エントリーポイントを定義し、処理の拡張を定義することであり、適切なエントリーポイントと処理の拡張が定義されれば、AOPフレームワークは自動的にAOPプロキシを生成します。

以下に示すのは、Spring AOP .xmlファイルのテンプレートです。名前はaop.xmlで、それ以降はすべてaop.xmlを継承しています:

3, ダイナミック・エージェント

JDKの動的プロキシは、特定のメソッドを呼び出す前に、プロキシのインターフェイスを実装する匿名クラスを生成するために反射メカニズムを使用することですInvokeHandlerに対処するために呼び出します。cglibの動的プロキシは、asmのオープンソースパッケージの使用は、プロキシオブジェクトのクラスファイルをロードし、そのバイトコードを変更することで、サブクラスを生成するために対処することです。

1 の場合、ターゲット・オブジェクトがインターフェイスを実装していれば、デフォルトでは JDK のダイナミック・プロキシを使用して AOP を実装します;

2.対象のオブジェクトがインターフェースを実装している場合、CGLIBを強制的に使用してAOPを実装することができます;

3、ターゲットオブジェクトがインターフェイスを実装していない場合は、CGLIBライブラリを使用する必要があります、春は自動的にJDKのダイナミックエージェントとCGLIBの間で変換されます;

CGLIBでAOPを強制するには?

1)、CGLIBライブラリをSPRING_HOME/cglib/*.jarに追加します。

JDKダイナミック・エージェントとCGLIBバイトコード生成の違い?

1) では、JDK の動的プロキシが生成できるのは、インターフェイスを実装するクラスのプロキシだけで、クラスのプロキシは生成できません;

2)、CGLIBは、プロキシを実装するクラスは、主に指定されたクラスのサブクラスを生成するために、メソッドをオーバーライドするため、継承なので、クラスやメソッドは、finalとして宣言されていない方がよいです;

分散ロックの実装方式

分散ロックは一般的に3つの方法で実装されます:

  1. データベースのロック;

  2. Redisベースの分散ロック;

  3. ZooKeeperに基づく分散ロック。

データベースロックの実装に基づく

プログラム1:

CREATE TABLE `methodLock` (`id`
 int(11) NOT NULL AUTO_INCREMENT COMMENT ' ', `method_name`
 varchar(64) NOT NULL DEFAULT ''
 COMMENT 'ロックされたメソッド名', `desc`
 varchar(1024) NOT NULL DEFAULT '備考', `update_time`
 timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'データ時間の節約、自動生成', PRIMARY KEY(`id`), UNIQUE KEY `uidx_method_name` (`method_name `) USING BTREE) ENGINE = InnoDB DEFAULT CHARSET = utf8 COMMENT = 'ロックされたメソッド';

メソッドをロックしたい場合は、以下のSQLを実行します:

deletefrommethodLockwheremethod_name = 'method_name'; オプション 2:

CREATE TABLE `method_lock` (
 `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT ' ',
 `method_name` varchar(64) NOT NULL COMMENT 'ロックされたメソッド名',
 `state` tinyint NOT NULL COMMENT '1:未割り当て; 2: 割り当て',
 `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
 `version` int NOT NULL COMMENT ' ',
 `PRIMARY KEY (`id`),
 UNIQUE KEY `uidx_method_name` (`method_name`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='ロックされたメソッド';
ロックを取得する:
selectid, method_name, state,versionfrommethod_lockwherestate=1andmethod_name='methodName';
ポゼッションロック:
update t_resoure set state=2, version=2, update_time=now() where method_name='methodName' and state=1 and version=2;
 

1、このロックが強く、データベースの可用性に依存している、データベースがハングアップすると、単一のポイントは、ビジネスシステムにつながる使用できません。

2、このロックは有効期限がない、一度ロック解除操作に失敗すると、それはロックレコードがデータベースにされているにつながる、他のスレッドがロックにアクセスすることはできません。

3は、ロックは、データの挿入操作は、一度挿入の失敗が直接エラーを報告するため、ノンブロッキングすることができます。いいえロックスレッドは再びロック操作をトリガするために再びロックを取得するために、キューキューに入力されません。

4は、このロックは、非再入可能です、リリースロックの不在で同じスレッドが再びロックを取得することはできません。データはすでにデータに存在するため。

解決策

1、データベースは、単一のポイントですか?2つのデータベース、双方向のデータ同期を従事。ハングアップしたら、すぐにバックアップデータベースに切り替えます。

2、有効期限はないのですか?一定時間ごとにデータベースのタイムアウトデータをクリーンアップする時限タスクを作成するだけです。

3、ノンブロッキング?whileループに入り、挿入が成功したら成功を返します。

4、非再入力?データベースのテーブルに現在ロックを取得しているマシンのホスト情報とスレッド情報を記録するフィールドを追加し、次にロックを取得するときは、まずデータベースに照会、現在のマシンのホスト情報とスレッド情報がデータベースで見つけることができれば、あなたは直接彼にロックを割り当てることができます。

redisに基づく分散ロック

達成プログラム:

try{
 lock = redisTemplate.opsForValue().setIfAbsent(lockKey, LOCK);
 logger.info("cancelCouponCodeロックを取得するかどうか:"+lock);
 if (lock) {
 // TODO
 redisTemplate.expire(lockKey,1, TimeUnit.MINUTES); //有効期限の設定に成功する
 return res;
 }else {
 logger.info("cancelCouponCodeロックの取得なし、タスクなし!");
 }
}finally{
 if(lock){ 
 redisTemplate.delete(lockKey);
 logger.info("cancelCouponCodeタスクを終了し、ロックを解除する!"); 
 }else{
 logger.info("cancelCouponCodeロックは獲得されず、ロックは解放されない。!");
 }
}

欠点:

このシナリオでは、底辺への競争は明らかです。

クライアントAはマスターからロックを取得します。

マスターがスレーブにロックを同期した後、マスターは停止します。

スレーブノードがマスターノードに昇格します。

クライアントBが、クライアントAが既に取得した同じリソースの別のロックを取得。セキュリティの失敗!

zookeeperの実装に基づく

オプション: リエントラントロックサービスをカプセル化した zookeeper サードパーティライブラリ Curator クライアントを直接使用できます。

欠点:

ZKのノードの作成と削除は、Leaderサーバを経由してのみ行うことができます。ZKのノードの作成と削除はLeaderサーバを通してのみ行うことができ、その場合、データはすべてのFollowerマシンと共有されません。

3つのプログラムの比較

上記の方法はどれも完璧ではありません。CAPと同じように、複雑さ、信頼性、パフォーマンスを同時に満たすことはできないので、さまざまなアプリケーションのシナリオに応じて最適なものを選択するのが方法です。

データベース > キャッシュ > Zookeeper

実装の複雑さの観点から: Zookeeper >= キャッシュ > データベース

パフォーマンスの観点から:キャッシュ > Zookeeper >= データベース

信頼性の観点から: Zookeeper > キャッシュ > データベース

5、面白い解釈のJavaデザインパターンの一部

1.工場出荷モデル。

おかしな解釈: - MMを追いかけることは避けられない、食べてください、マクドナルドの手羽先とKFCの手羽先は、味は異なりますが、あなたがマクドナルドやKFCにMMを取るに関係なく、物事を食べるのが大好きですが、ちょうどウェイターに "4チキンウィングに来る "と言ったライン上。マクドナルドとKFCは手羽先を生産する工場です。

ファクトリーパターン:顧客クラスとファクトリークラスを分離。消費者が特定の製品を必要とするときはいつでも、ファクトリーに要求するだけです。消費者は修正なしで新しい製品を受け入れることができます。欠点は、製品が変更されると、ファクトリクラスもそれに応じて変更しなければならないことです。例えば、どのように作成し、どのようにクライアントに提供するかです。

2、シングルトン・パターン

面白い読み方:私には6人の美しい妻がいますが、彼らの夫は私です。

シングルトンパターンは、クラスのインスタンスが1つしかないこと、そしてクラス自身がインスタンス化され、そのインスタンスがシステム全体から利用可能になることを保証します。シングルトンパターンは、「単一のインスタンス」が本当に必要な場合にのみ使うべきです。

3 のアダプター モード

面白い解釈:パーティーで非常に美しいウクライナ人のMMに会ったが、ウクライナ語を話すことができない、彼女はまた、北京語を話すことができない、ウクライナ人になる友人に回さなければならなかった、彼はアダプターの間として、お互いに話すことができるように。

アダプタ・パターン: あるクラスのインターフェイスを、クライアントが期待する別のインターフェイスに変換します。アダプタクラスは、パラメータに基づいて適切なインスタンスをクライアントに返すことができます。

4、エージェントモデル

プロキシパターン:プロキシパターンは、オブジェクトにプロキシオブジェクトを提供し、プロキシオブジェクトがソースオブジェクトへの参照を制御します。プロキシとは、他の人や組織に代わって行動する人や組織のことです。クライアントはオブジェクトを直接参照したくない、あるいは参照できない場合があり、プロキシはクライアントとターゲットオブジェクトの仲介役として振る舞います。クライアントはプロキシ対象オブジェクトと本当の対象オブジェクトの 違いを見分けることができません。プロキシパターンはプロキシの本当のサブジェクトを知らないかもし れませんが、単にプロキシへのインターフェースを保持します。

Read next

Mybatisの4つの成果物 Executor Executor

エクゼキュータの継承構造\n\nエクゼキュータ・インターフェイス: には2つの実装クラスがあります、\nの "アダプタ・パターン" の現れとしてインタフェースを実装する抽象クラスです。

Jul 25, 2020 · 3 min read