復習: ソースコード分析

https://yanglinwei.blog.csdn.net/article/details/103869577

スプリング: 階層化されたJavaSE/EEフルスタック(ワンストップ)ライトマグニチュードです。オープン ソース フレームワークのコアは制御の反転 (IoC)アスペクト指向 (AOP) です。 。 JavaEE の 3 層構造に対して、Spring は各層に異なるソリューション テクノロジーを提供します。

  • WEB層:SpringMVC
  • ビジネス層: Spring の IoC
  • 永続層: Spring の JDBCTemplate (Spring の JDBC テンプレート、ORM テンプレートは、他の永続層フレームワークを統合するために使用されます)

AOP: アスペクト指向プログラミングにより、 コードに焦点を当てる および ビジネス コード の分離、AOP はテクノロジーではなく、実際にはプログラミングのアイデアです。主な機能: ロギング、パフォーマンス統計、セキュリティ制御、トランザクション処理、例外処理など。


AOP の重要な用語:

  • 懸念点: 繰り返されるコードは「懸念点」と呼ばれます。
  • アスペクト: フォーカスによって形成されるクラスはアスペクト (クラス) と呼ばれます。
  • アスペクト指向プログラミング: 多くの関数の繰り返しコード抽出を指し、実行時に「アスペクト クラス コード」をビジネス メソッドに動的に埋め込みます。
  • ポイントカット: ターゲット オブジェクト メソッドを実行し、アスペクト コードを動的に埋め込みます。ポイントカット式を使用して、どのクラスのどのメソッドをインターセプトするかを指定し、実行時に指定したクラスにアスペクト クラス コードを埋め込むことができます。

AOP の基礎となる実装: プロキシ モード。エージェントは次のように分類されます:

  • 静的プロキシ: プロキシ クラスのソース コードはプログラマによって作成されるか、ツールによって生成され、その後プロキシ クラスがコンパイルされます。いわゆる静的とは、プロキシ クラスのバイトコード ファイルがプログラムの実行前にすでに存在し、プロキシ クラスとデリゲート クラスの関係が実行前に決定されることを意味します。
  • jdk には動的プロキシが付属しています。プロキシ クラスはクラス ローダーとインターフェイスに基づいて作成されます (このプロキシ クラスが実装です)したがって、インターフェイスのプロキシを生成するには、java.lang.reflect パッケージの下にあるインターフェイスを使用する必要があります)。欠点はインターフェイス指向である必要があり、ターゲット ビジネス クラスはインターフェイスを実装する必要があります。
  • cglib ダイナミック プロキシ: asm オープン ソース パッケージを使用して、プロキシ オブジェクト クラスのクラス ファイルをロードし、そのクラス ファイルを変更して生成します。処理するバイトコードのサブクラス。

AOP プログラミングの使用法 (メモ):

@Aspect							指定一个类为切面类		

@Pointcut("execution(* com.ylw.service.UserService.add(..))")  指定切入点表达式

@Before("pointCut_()")		  前置通知: 目标方法之前执行

@After("pointCut_()")				后置通知:目标方法之后执行(始终执行)

@AfterReturning("pointCut_()")		 返回后通知: 执行方法结束前执行(异常不执行)

@AfterThrowing("pointCut_()")			 异常通知:  出现异常时候执行

@Around("pointCut_()")				环绕通知: 环绕目标方法执行

トランザクションの基本特性 (ACID):

  • 原子性: トランザクションに含まれるすべての操作が成功するか失敗してロールバックされるという事実を指します。したがって、トランザクションの操作が成功した場合は、完全に実行される必要があります。操作が失敗しても、データベースに影響を与えることはできません。
  • 整合性: トランザクションはデータベースをある整合性状態から別の整合性状態に変更する必要がある、つまり、トランザクションは実行の前後で整合性が保たれている必要があることを意味します。
  • 分離: 同じテーブルを操作する場合など、複数のユーザーがデータベースに同時にアクセスする場合、各ユーザーに対してデータベースによって開かれたトランザクションは、他のトランザクションの操作によって干渉されません。 . 、複数の同時トランザクションは互いに分離する必要があります。
  • 永続性: トランザクションが送信されると、データベース システムに障害が発生した場合でも、データベース内のデータへの変更が永続的に維持されることを指します。トランザクションをコミットする操作は次のとおりです。失われていません。

トランザクション制御方法:

  • プログラムによる: きめ細かいトランザクション制御。指定したメソッドおよび指定したメソッドの特定の行にトランザクション制御を追加できます。柔軟性は高くなりますが、開発はより面倒です。毎回開いて送信し、ロールバックする必要があります (begincommitrollback) 。
  • 宣言型: AOP に基づいた、粗粒度のトランザクション制御。トランザクションはメソッド全体にのみ適用でき、AOP はメソッドの特定の行に適用できません。インターセプトメソッド。

トランザクションの伝播動作: トランザクションの伝播動作とは、あるトランザクション メソッドが別のトランザクション メソッドを呼び出すときに、新しいトランザクションが既存のトランザクションとどのように対話するかに関するルールを指します。これらの伝播動作は、 **@Transactional アノテーションの propagation** 属性を通じて設定できます。 Spring では、次の 7 つのトランザクション伝播動作が定義されています。

  1. 必須 (デフォルト): トランザクションが現在存在する場合はトランザクションに参加し、現在のトランザクションが存在しない場合は新しいトランザクションを作成します。
  2. サポート: 現在トランザクションがある場合はトランザクションに参加し、現在トランザクションがない場合は非トランザクション方式で実行します。
  3. 必須: 現在トランザクションがある場合はトランザクションに参加し、現在トランザクションがない場合は例外をスローします。
  4. REQUIRES_NEW: 毎回新しいトランザクションを作成し、現在トランザクションが存在する場合は現在のトランザクションを一時停止します。
  5. NOT_SUPPORTED: 非トランザクション的な方法で操作を実行します。現在トランザクションが存在する場合は、現在のトランザクションを一時停止します。
  6. NEVER: 非トランザクション方式で実行します。現在トランザクションが存在する場合は、例外がスローされます。
  7. NESTED: トランザクションが現在存在する場合は、ネストされたトランザクション内で実行されます。現在トランザクションが存在しない場合は、REQUIRED のルールに従って新しいトランザクションが作成されます。 。ネストされたトランザクションは、既存のトランザクション内に新しいトランザクションをネストできるようにする比較的新しい機能です。

注意: コードの実際のロジックには影響しませんし、影響することはありません。サポート的な役割を果たすだけです。

注釈は次のように分類されます:

  • 組み込みアノテーション (メタ アノテーション、jdk 独自のアノテーションとも呼ばれます): 例: @SuppressWarnings"、"@Deprecated"、"@Overricle":
  • カスタム アノテーション (Spring フレームワーク):@Target では、アノテーションによって変更されるオブジェクトのスコープについて説明します。 @Retention注釈情報をどのレベルで保存する必要があるかを示し、注釈のライフ サイクルを記述するために使用されます。@Document 説明アノテーションは、javadoc などのツールで文書化できるように、アノテーションが付けられたプログラム メンバーのパブリック API として使用する必要があります。@Inherited使用する場合@Inherited 型アノテーションのアノテーションの保持は RetentionPolicy.RUNTIME であり、リフレクション API はこの継承を強化します。

XML解析方式

  • Dom4j: ファイルを一度にメモリにロードするため、メモリ オーバーフローが発生する可能性があるため、大きなファイルの解析には適していません。 XML ファイルに対して柔軟な (粗雑な) 操作を実行したい場合は、dom4j を使用します。
  • SAX: イベントに基づいて XML を解析するため、大きなファイルの XML を解析できます。
  • 引く

Spring IOC: 制御の反転を指します。IOC コンテナは、アプリケーション内のオブジェクトのインスタンス化、検索、構成、およびこれらのオブジェクト間の依存関係の確立を行い、Spring に任せます。これらを管理してデカップリングを実現します。


Spring IOC 原則:XML技术+发射技术。 ClassPathXmlApplicationContext は、読み取りを使用して XML クラスを解析し、リフレクションを使用してオブジェクトを初期化します。

ここに画像の説明を挿入します


SpringMVC 実行プロセス:

ここに画像の説明を挿入します

  1. ユーザーがフロントエンド コントローラー DispatcherServlet にリクエストを送信します。
  2. DispatcherServlet はリクエストを受信し、HandlerMapping プロセッサ マッパーを呼び出します。
  3. プロセッサ マッパーは、リクエスト URL に従って特定のプロセッサを見つけ、プロセッサ オブジェクトとプロセッサ インターセプタ (存在する場合) を生成し、それを DispatcherServlet に返します。
  4. DispatcherServlet は、HandlerAdapter プロセッサ アダプタを通じてハンドラを呼び出します。
  5. 実行プロセッサ (コントローラー、バックエンド コントローラーとも呼ばれます)。
  6. コントローラーは実行を完了し、ModelAndView に戻ります
  7. HandlerAdapter はコントローラーの実行結果 ModelAndView を DispatcherServlet に返します
  8. DispatcherServlet は ModelAndView を ViewReslover ビュー リゾルバーに渡します
  9. ViewReslover は解析後に特定の View を返します
  10. DispatcherServlet はビューをレンダリングします (つまり、モデル データをビューに埋め込みます)。
  11. DispatcherServlet がユーザーに応答します。

サーブレット: Web ブラウザまたは他の HTTP クライアント、および HTTP サーバー上のデータベースまたはアプリケーションからのリクエストとして Web サーバーまたはアプリケーション サーバー上で実行されるプログラム。間の層。

サーブレットライフ サイクル: サーブレットの読み込み -> インスタンス化 -> サービス -> 破棄。

  • init メソッド: サーブレットのライフサイクルにおいて、init メソッドは 1 回だけ実行されます。
  • **サービス メソッド:** サーブレットの中核であり、顧客のリクエストに応答する役割を果たします。クライアントが HttpServlet オブジェクトを要求するたびに、オブジェクトの Service() メソッドが呼び出され、「要求」 (ServletRequest) オブジェクトと「応答」 (ServletResponse) オブジェクトがパラメータとしてこのメ​​ソッドに渡されます。
  • destroy メソッド: 1 回だけ実行されます。このメソッドは、サーバーが停止し、サーブレットがアンインストールされるときに実行されます。サーブレット オブジェクトがライフ サイクルを終了すると、占有されていたリソースを解放する必要があります。

SpringMVC の基本原理: XML テクノロジー + リフレクション + アノテーション + サーブレットに基づいて実装されます。

初期化フェーズ:

  • 設定ファイルをロードする
  • ユーザー構成パッケージの下のすべてのクラスをスキャンします。
  • スキャンされたクラスを取得し、リフレクション メカニズムを通じてインスタンス化します。そして、それを ioc コンテナに入れます (キーと値のペア beanName-bean をマップ) beanName は、デフォルトで最初の文字が小文字になります。
  • HandlerMapping の初期化: これは実際には、URL とメソッドを k-v マップにマップし、実行フェーズ中にそれらを取り出します。 mvcBeanUrl.put(requestBaseUrl + httpRequestUrl, mvcObject)

実行フェーズ: URL リクエストに従って HandlerMapping の対応するメソッドを照合し、リフレクションController内のURLに対応するメソッドを呼び出し、結果を返す仕組みです。

ここに画像の説明を挿入します


データベース接続プール: 原則は、内部オブジェクト プールで一定数のデータベース接続を維持し、データベース接続の取得メソッドと返却メソッドを外部に公開することです。その機能には、リソースの再利用、システム応答の高速化、新しいリソース割り当て手段、統合された接続管理、データベース接続漏洩の回避などがあります。


データベース接続プールの分類:

  • DBCP: 古い接続プールの実装。場合によっては、特に同時実行性の高い環境では、パフォーマンスが低下することがあります。
  • C3P0: もう 1 つの古い接続プールで、DBCP と比較すると、C3P0 はいくつかの点でパフォーマンスが優れていますが、負荷が非常に高い場合には依然としてパフォーマンスが低下する可能性があります。
  • HikariCP: 優れたパフォーマンスを備えた比較的新しい接続プールです。軽量でパフォーマンスが高いように設計されており、多くの場合、スループットと応答時間の点で他の接続プールよりも優れています。

ここに画像の説明を挿入します


MyBatis: データベースと対話するには 2 つの方法があります。1 つは API を直接使用する方法、もう 1 つは Mapper インターフェースを使用する方法です。 Mappr インターフェースと Mapper.xml の対応関係は次のとおりです。

ここに画像の説明を挿入します


MyBatis の基礎となる実装: MyBatis は、対応するインターフェイスによって宣言されたメソッド情報に基づいて、動的プロキシ メカニズムを通じて Mapper インスタンスを生成します。Mapper インターフェイスのメソッドを使用する場合、 MyBatis は、このメソッドのメソッド名とパラメーターの型に従って、ステートメント ID が決定されます。最下層は、SqlSession.select("statementId",parameterObject) または SqlSession.update("statementId",パラメータオブジェクト); など。

public class MyInvocationHandlerMbatis implements InvocationHandler {
    
    
	private Object object;

	public MyInvocationHandlerMbatis(Object object) {
    
    
		this.object = object;
	}

	// proxy 代理对象 method拦截方法 args方法上的参数值
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
		System.out.println("使用动态代理技术拦截接口方法开始");
		// 使用白话问翻译,@ExtInsert封装过程
		// 1. 判断方法上是否存在@ExtInsert
		ExtInsert extInsert = method.getDeclaredAnnotation(ExtInsert.class);
		if (extInsert != null) {
    
    
			return extInsert(extInsert, proxy, method, args);
		}
		// 2.查询的思路
		// 1. 判断方法上是否存 在注解
		ExtSelect extSelect = method.getDeclaredAnnotation(ExtSelect.class);
		if (extSelect != null) {
    
    
			// 2. 获取注解上查询的SQL语句
			String selectSQL = extSelect.value();
			// 3. 获取方法上的参数,绑定在一起
			ConcurrentHashMap<Object, Object> paramsMap = paramsMap(proxy, method, args);
			// 4. 参数替换?传递方式
			List<String> sqlSelectParameter = SQLUtils.sqlSelectParameter(selectSQL);
			// 5.传递参数
			List<Object> sqlParams = new ArrayList<>();
			for (String parameterName : sqlSelectParameter) {
    
    
				Object parameterValue = paramsMap.get(parameterName);
				sqlParams.add(parameterValue);
			}
			// 6.将sql语句替换成?
			String newSql = SQLUtils.parameQuestion(selectSQL, sqlSelectParameter);
			System.out.println("newSQL:" + newSql + ",sqlParams:" + sqlParams.toString());

			// 5.调用jdbc代码底层执行sql语句
			// 6.使用反射机制实例对象### 获取方法返回的类型,进行实例化
			// 思路:
			// 1.使用反射机制获取方法的类型
			// 2.判断是否有结果集,如果有结果集,在进行初始化
			// 3.使用反射机制,给对象赋值

			ResultSet res = JDBCUtils.query(newSql, sqlParams);
			// 判断是否存在值
			if (!res.next()) {
    
    
				return null;
			}
			// 下标往上移动移位
			res.previous();
			// 使用反射机制获取方法的类型
			Class<?> returnType = method.getReturnType();
			Object object = returnType.newInstance();
			while (res.next()) {
    
    
				// 获取当前所有的属性
				Field[] declaredFields = returnType.getDeclaredFields();
				for (Field field : declaredFields) {
    
    
					String fieldName = field.getName();
					Object fieldValue = res.getObject(fieldName);
					field.setAccessible(true);
					field.set(object, fieldValue);
				}
				// for (String parameteName : sqlSelectParameter) {
    
    
				// // 获取参数值
				// Object resultValue = res.getObject(parameteName);
				// // 使用java的反射值赋值
				// Field field = returnType.getDeclaredField(parameteName);
				// // 私有方法允许访问
				// field.setAccessible(true);
				// field.set(object, resultValue);
				// }
			}
			return object;
		}

		return null;
	}

	private Object extInsert(ExtInsert extInsert, Object proxy, Method method, Object[] args) {
    
    
		// 方法上存在@ExtInsert,获取他的SQL语句
		// 2. 获取SQL语句,获取注解Insert语句
		String insertSql = extInsert.value();
		// System.out.println("insertSql:" + insertSql);
		// 3. 获取方法的参数和SQL参数进行匹配
		// 定一个一个Map集合 KEY为@ExtParamValue,Value 结果为参数值
		ConcurrentHashMap<Object, Object> paramsMap = paramsMap(proxy, method, args);
		// 存放sql执行的参数---参数绑定过程
		String[] sqlInsertParameter = SQLUtils.sqlInsertParameter(insertSql);
		List<Object> sqlParams = sqlParams(sqlInsertParameter, paramsMap);
		// 4. 根据参数替换参数变为?
		String newSQL = SQLUtils.parameQuestion(insertSql, sqlInsertParameter);
		System.out.println("newSQL:" + newSQL + ",sqlParams:" + sqlParams.toString());
		// 5. 调用jdbc底层代码执行语句
		return JDBCUtils.insert(newSQL, false, sqlParams);
	}

	private List<Object> sqlParams(String[] sqlInsertParameter, ConcurrentHashMap<Object, Object> paramsMap) {
    
    
		List<Object> sqlParams = new ArrayList<>();
		for (String paramName : sqlInsertParameter) {
    
    
			Object paramValue = paramsMap.get(paramName);
			sqlParams.add(paramValue);
		}
		return sqlParams;
	}

	private ConcurrentHashMap<Object, Object> paramsMap(Object proxy, Method method, Object[] args) {
    
    
		ConcurrentHashMap<Object, Object> paramsMap = new ConcurrentHashMap<>();
		// 获取方法上的参数
		Parameter[] parameters = method.getParameters();
		for (int i = 0; i < parameters.length; i++) {
    
    
			Parameter parameter = parameters[i];
			ExtParam extParam = parameter.getDeclaredAnnotation(ExtParam.class);
			if (extParam != null) {
    
    
				// 参数名称
				String paramName = extParam.value();
				Object paramValue = args[i];
				// System.out.println(paramName + "," + paramValue);
				paramsMap.put(paramName, paramValue);
			}
		}
		return paramsMap;
	}

	public Object extInsertSQL() {
    
    
		return object;
	}
}

MyBatis の階層構造:

ここに画像の説明を挿入します


ArrayList の基本的な実装原則: 配列の実装に基づき、デフォルトの配列初期化サイズは 10 個のオブジェクト配列です。現在の配列の長さを超える要素を追加すると、その容量は配列の長さを減らすために拡張されます。元の配列を半分に増やします。


Vector と ArrayList の違い: Vector はスレッドセーフです。ArrayList と Vector はどちらも線形連続ストレージ スペースを使用します。ストレージ スペースが不十分な場合、ArrayList は元の 50 に増加します。 %、ベクトルはデフォルトで 2 倍になります。


配列コピー方法:

  • Arrays.copyOf: この関数は配列をコピーし、コピーされた配列を返します。パラメータは、コピーされる配列とコピーの長さです。
  • System.arraycopy: 配列が比較的大きい場合は、メモリ コピーを使用し、多くの配列アドレス指定を省略できるため、System.arraycopy を使用する方が有利です。アクセスと指定されたソース配列 src を宛先配列 dest にコピーするまで待ちます。

実装プロセス: まず、length の長さの一時配列を生成し、fun 配列の srcPos と srcPos+length-1 の間のデータを一時配列にコピーします。 System.arraycopy(一時配列,0,fun,3,3) を実行します。

int[] fun ={
    
    0,1,2,3,4,5,6}; 
System.arraycopy(fun,0,fun,3,3);

LinkedList の基礎となる原理: 基礎となるデータ構造は、双方向ループリンク リスト

  • 配列 (スタックからスペースを割り当てる): アプリケーションがデータへの高速アクセスを必要とし、要素の挿入と削除をほとんど行わない場合は、配列を使用する必要があります。固定長(要素数)はあらかじめ定義しておく必要があり、動的なデータの増減には対応できません。
  • リンク リスト (ヒープから領域を割り当てる): アプリケーションで要素の挿入と削除を頻繁に行う必要がある場合は、リンク リストを使用する必要があります。動的なストレージ割り当てにより、データの動的な増減に適応でき、データ項目の挿入と削除が簡単に行えます。

ここに画像の説明を挿入します


HashMap の基本原理: 配列 + リンク リスト (配列 (紫): ハッシュ配列(バケット) )、配列要素は各リンク リストのヘッド ノードです。リンク リスト (緑色): ハッシュの競合を解決し、異なるキーがマッピングされます。配列の同じインデックス)

ここに画像の説明を挿入します

put方法过程

  • 追加されたキー値が null の場合、キーと値のペアは配列インデックス 0 でリンク リストに追加されますが、これは必ずしもリンク リストの最初のノードである必要はありません。
  • 追加されたキーが null でない場合は、キーに基づいて配列インデックスの位置を計算します。
    ----- 配列インデックスにリンクされたリストがあるため、リンクされたリストを調べて、キーがすでに存在していることが判明した場合は、古い値を新しい値に置き換えます。
    ----- 配列インデックスにリンク リストがありません。ここにキーと値を追加してヘッド ノードになります。

getメソッドの処理:

  • キーが null の場合は、配列インデックス table[0] のリンク リストを走査して、キーが null の値を見つけます。
  • キーが null でない場合は、キーに基づいて配列インデックス位置にあるリンク リストを検索し、走査してキーの値を検索し、見つかった場合はその値を返します。見つからない場合は、null を返します。

拡張メカニズム: 実際の容量 = 初期容量 × 負荷率 (例: 16×0.75=12、つまり、実際の容量が 12 を超えると、この HashMap は拡張されます)。 )

  • 初期容量: ハッシュマップを構築するとき、初期容量は指定された容量の 2 のべき乗以上の数値に設定されます (new HashMap(5)、指定された容量が 5 の場合、実際の初期容量は 8 (2^3=8>5) となり、最大値は 2 の 30 乗を超えることはできません。
  • 負荷率 : 負荷率は、ハッシュ配列の容量が自動的に増加する前にハッシュ配列がどの程度いっぱいになるかを示す尺度です。 (時間とスペースのトレード) ハッシュ配列内のエントリの数が負荷係数と初期容量の積を超える場合、ハッシュ配列を拡張する(つまり、サイズを変更する)必要があります。
  • HashMap が拡張されると、新しい配列の容量は元の配列の 2 倍になります。容量の変化により、元の各配列は要素 配列インデックス インデックスを再計算して、新しい配列に保存する必要があります。これは再ハッシュと呼ばれます。

eqauls メソッドと hashCode メソッド:

  • hashCode: Object クラスで定義されていますが、デフォルトの実装ではオブジェクトのメモリ アドレスのハッシュ コードが返されます。実際のアプリケーションでは、特にハッシュ テーブル (HashMap、HashSet など) を使用する場合、オブジェクトを適切に分散し、ハッシュの競合を回避するために、 hashCode メソッドをオーバーライドする必要があります。
  • eqauls メソッド: 2 つのオブジェクトの参照が等しいかどうか、つまり、メモリ内の同じオブジェクトを指しているかどうかを比較します。
  • 2 つのオブジェクトが同じである場合、それらの hashCode 値は同じでなければなりません。また、equals メソッドを書き換えるときは、hashCode メソッドを書き換える必要があることもわかります。つまり、hashCode 値がクラス内のメンバー変数にリンクされている必要があります。オブジェクトは同じです -> メンバー変数は同じです -> hashCode 値は同じである必要があります。
  • 2 つのオブジェクトの hashCode が同じである場合、それらは必ずしも同じであるとは限りません。ここでオブジェクトが同じとは、eqauls メソッドを使用した比較を指します。 オブジェクトの参照ではなく、オブジェクトの内容を比較する場合は、このメソッドをオーバーライドする必要があります。

おすすめ

転載: blog.csdn.net/qq_20042935/article/details/134588173