Spring依存注入の実現原理--java反射とASMフレームワーク
26889 ワード
依存注入はspringの特性であり、構成面からプログラム結合、依存問題を解決し、springは構造関数依存注入、Setter方法依存注入、自動組立依存注入、@autowired注釈依存注入など多くの実現方式を提供している.
では、依存注入はどのように実現されますか?最初の反応はjava反射歌です.たとえば、コンストラクション関数注入では、Beanクラスのコンストラクション関数、パラメータ個数、パラメータタイプを反射で読み取ることができます.したがって、xmlプロファイルでパラメータタイプまたはパラメータ順序を指定すれば、反射によってBeanのインスタンスを簡単に作成できます.しかし、実際にはxmlプロファイルでname=パラメータ名を指定しても依存注入を実現できることが分かった.これはjava反射が実現しにくい少なくともjdk 1.8以下では実現できない.jdk 1.8以下では反射によって具体的なパラメータ名が得られないためだ.ケースを見てください.
Student.java
xmlプロファイルioc-di-asm.xml
テストクラスDIAsmApp.java
出力結果
ケース・ノート
1、student 1、反射で実現可能
xmlには3つのconstructor-argが構成されており、type、index、nameなどの他の装飾はありません.この場合、java反射によりインスタンスを正常に作成できます.すなわち、3つのパラメータの構造関数、Student(String name、String gender、Integer age)を探し、constructor-argの出現順に構造関数パラメータに値を割り当て、インスタンスを作成します.
2、student 2、反射で実現可能
xmlは3つのconstructor-argを構成しています.1番目のパラメータはIntegerタイプとしてマークされ、残りの2つはvalue値のみで、他の識別はありません.この場合、java反射によってインスタンスを作成することができます.は3つのパラメータの構造関数、Student(String name、String gender、Integer age)を見つけた. 1 1番目のconstructor-arg type=「java.lang.Integer」を読み込み、コンストラクション関数でIntegerタイプのパラメータを見つけ、3番目のパラメータであることを発見するとarg 2=22 を設定するは2番目のconstructor-argを読み出し、構造関数はarg 0であり、arg 1は設定されず、前後順に値を付与し、arg 0=student 2 3番目のconstructor-argを読み込み、arg 1は設定されていません.arg 1=male
3、student 3、java反射は実現できない
xmlには3つのconstructor-argが配置されています.1番目のパラメータはIntegerタイプと表記され、2番目のパラメータはnameが設定されています.3番目のパラメータには特別な識別はありません.java反射で実現できると仮定すると、実現手順は次のとおりです.は3つのパラメータの構造関数、Student(String name、String gender、Integer age)を見つけた. 1 1番目のconstructor-arg type=「java.lang.Integer」を読み込み、コンストラクション関数でIntegerタイプのパラメータを見つけ、3番目のパラメータであることを発見するとarg 2=22 を設定するは2番目のconstructor-argを読み出し、構造関数はarg 0であり、arg 1は設定されず、前後順に値を付与し、arg 0=female 3 3番目のconstructor-argを読み込みます.arg 1は設定されていません.arg 1=student 3 です.
私たちはstudent beanが{name=female,gender=student 3,age=33}であることを得て、名前が性別になって、性別が名前になって、私たちが望んだ結果ではありませんて、java反射は失敗しました!
ではspring依存注入はなぜ正常に動作するのでしょうか.なぜならspringはasmフレームワークを使用してjavaクラスのバイトコードを読み取り、コンストラクション関数のパラメータ名を読み取ることができるため、前述のstudent 3構成のようにspringは2番目のconstructor-arg name=「gender」対応コンストラクション関数のarg 1を読み取ることができるため、正常に動作することができる.ASMフレームワークコードのデモ:
AsmDemo.java
ASMフレームワークでは、com.marcus.spring.beans.Studio(name,gender,age)コンストラクション関数パラメータ名を読み取り、student 3 bean注入の実装手順を続行しました.
student 3 xmlファイルには、3つのconstructor-argが配置されています.1番目のパラメータはIntegerタイプと表記され、2番目のパラメータはnameが設定されています.3番目のパラメータには特別な識別はありません.java反射+ASMフレームワークによって、実現手順は次のとおりです.は3つのパラメータの構造関数、Student(String name、String gender、Integer age)を見つけた. 1 1番目のconstructor-arg type=「java.lang.Integer」を読み込み、コンストラクション関数でIntegerタイプのパラメータを見つけ、3番目のパラメータであることを発見するとarg 2=22 を設定する 2 2番目のconstructor-arg name="gender"を読み出し、コンストラクション関数でgenderという名前のパラメータを見つけ、2番目のパラメータであることを発見するとarg 1=female を設定する. 3 3番目のconstructor-argを読み込みます.arg 0は設定されていません.arg 0=student 3 です.
student beanは{name=student 3,gender=female,age=33}で成功した.
小結
SpringフレームワークはASMフレームワークを広く使用しており,springのjarパッケージ構成からspringに対するASMの重要性を見ることができる.3.2.5.RELEASEバージョンを例にとると、ASM部分はspring-core-3.2.5.RELEASE.jarパッケージ、springの最も核心的なjarパッケージの中にあります!AOP,cglibなどはいずれもASMがJavaクラスを読み取り,操作する必要がある.
では、依存注入はどのように実現されますか?最初の反応はjava反射歌です.たとえば、コンストラクション関数注入では、Beanクラスのコンストラクション関数、パラメータ個数、パラメータタイプを反射で読み取ることができます.したがって、xmlプロファイルでパラメータタイプまたはパラメータ順序を指定すれば、反射によってBeanのインスタンスを簡単に作成できます.しかし、実際にはxmlプロファイルでname=パラメータ名を指定しても依存注入を実現できることが分かった.これはjava反射が実現しにくい少なくともjdk 1.8以下では実現できない.jdk 1.8以下では反射によって具体的なパラメータ名が得られないためだ.ケースを見てください.
Student.java
package com.marcus.spring.beans;
public class Student {
private Integer age;
private String name;
private String gender;
public Student() {
}
public Student(String name, String gender, Integer age) {
this.name = name;
this.age = age;
this.gender = gender;
}
public void setAge(Integer age) {
this.age = age;
}
public Integer getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public String getGender() {
return gender;
}
public String toString() {
return String.format("{name: %s, gender: %s, age: %d}", this.name, this.gender, this.age);
}
}
xmlプロファイルioc-di-asm.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="student1" class="com.marcus.spring.beans.Student">
<constructor-arg value="student1" />
<constructor-arg value="male" />
<constructor-arg value="11" />
bean>
<bean id="student2" class="com.marcus.spring.beans.Student">
<constructor-arg type="java.lang.Integer" value="22" />
<constructor-arg value="student2" />
<constructor-arg value="male" />
bean>
<bean id="student3" class="com.marcus.spring.beans.Student">
<constructor-arg type="java.lang.Integer" value="33" />
<constructor-arg name="gender" value="female" />
<constructor-arg value="student3" />
bean>
beans>
テストクラスDIAsmApp.java
public class DIAsmApp {
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("ioc-di-asm.xml");
Student student1 = context.getBean("student1", Student.class);
System.out.println("student1: " + student1.toString());
Student student2 = context.getBean("student2", Student.class);
System.out.println("student2: " + student2.toString());
Student student3 = context.getBean("student3", Student.class);
System.out.println("student3: " + student3.toString());
context.close();
}
}
出力結果
student1: {name: student1, gender: male, age: 11}
student2: {name: student2, gender: male, age: 22}
student3: {name: student3, gender: female, age: 33}
ケース・ノート
1、student 1、反射で実現可能
xmlには3つのconstructor-argが構成されており、type、index、nameなどの他の装飾はありません.この場合、java反射によりインスタンスを正常に作成できます.すなわち、3つのパラメータの構造関数、Student(String name、String gender、Integer age)を探し、constructor-argの出現順に構造関数パラメータに値を割り当て、インスタンスを作成します.
2、student 2、反射で実現可能
xmlは3つのconstructor-argを構成しています.1番目のパラメータはIntegerタイプとしてマークされ、残りの2つはvalue値のみで、他の識別はありません.この場合、java反射によってインスタンスを作成することができます.
3、student 3、java反射は実現できない
xmlには3つのconstructor-argが配置されています.1番目のパラメータはIntegerタイプと表記され、2番目のパラメータはnameが設定されています.3番目のパラメータには特別な識別はありません.java反射で実現できると仮定すると、実現手順は次のとおりです.
私たちはstudent beanが{name=female,gender=student 3,age=33}であることを得て、名前が性別になって、性別が名前になって、私たちが望んだ結果ではありませんて、java反射は失敗しました!
ではspring依存注入はなぜ正常に動作するのでしょうか.なぜならspringはasmフレームワークを使用してjavaクラスのバイトコードを読み取り、コンストラクション関数のパラメータ名を読み取ることができるため、前述のstudent 3構成のようにspringは2番目のconstructor-arg name=「gender」対応コンストラクション関数のarg 1を読み取ることができるため、正常に動作することができる.ASMフレームワークコードのデモ:
AsmDemo.java
package com.marcus.spring.aop;
import java.lang.reflect.Constructor;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import com.marcus.spring.beans.Student;
public class AsmDemo {
public static void main(String[] args) throws ClassNotFoundException {
LocalVariableTableParameterNameDiscoverer localVariableTableParameterNameDiscoverer
= new LocalVariableTableParameterNameDiscoverer();
Class<?> forName = Class.forName(Student.class.getName());
Constructor<?>[] constructors = forName.getConstructors();
for (Constructor<?> constructor : constructors) {
String argNames = "";
String[] parameterNames = localVariableTableParameterNameDiscoverer
.getParameterNames(constructor);
for (String parameterName : parameterNames) {
argNames += argNames.length() < 1 ? parameterName : "," + parameterName;
}
System.out.println(argNames.length()<1 ? constructor.getName() + "()"
: constructor.getName() + "(" + argNames + ")");
}
//output:
//com.marcus.spring.beans.Student()
//com.marcus.spring.beans.Student(name,gender,age)
}
}
ASMフレームワークでは、com.marcus.spring.beans.Studio(name,gender,age)コンストラクション関数パラメータ名を読み取り、student 3 bean注入の実装手順を続行しました.
student 3 xmlファイルには、3つのconstructor-argが配置されています.1番目のパラメータはIntegerタイプと表記され、2番目のパラメータはnameが設定されています.3番目のパラメータには特別な識別はありません.java反射+ASMフレームワークによって、実現手順は次のとおりです.
student beanは{name=student 3,gender=female,age=33}で成功した.
小結
SpringフレームワークはASMフレームワークを広く使用しており,springのjarパッケージ構成からspringに対するASMの重要性を見ることができる.3.2.5.RELEASEバージョンを例にとると、ASM部分はspring-core-3.2.5.RELEASE.jarパッケージ、springの最も核心的なjarパッケージの中にあります!AOP,cglibなどはいずれもASMがJavaクラスを読み取り,操作する必要がある.