IOCの紹介
IOCは、実際には、これら二つの概念が同じで、制御の反転は学術用語でも依存性注入として知られている、制御の反転(制御の反転)を表し、不明瞭、理解を容易にするために、その後依存性注入の導入は、理解容易にします。
なぜ使用IOC
大規模なプロジェクトを結合するときに使用していないのIOCで、プログラムを更新する際に、多くの場合、直接、元の部品を保つために、本来の機能を削除していない、昔のクラスを置き換えるために新しいクラスを使用することが必要であるが、この方法すべての関連するクラスは、これは非常に面倒であり、変更を忘れて、それはエラーになり、修正する必要があり、プログラムを実行することはできませんIOCクラスとクラスはデカップリングしながら、デカップリング層を達成することができ、一つだけを変更する必要が到達し、それは簡単に拡張を維持するために、プロジェクト全体を更新することができます。
IOCを達成する方法
デカップリングの目的、及び対象反射体を注入するためにインタフェースを使用する必要性を達成するために
二つのクラスとテストクラスを作成します。1.
//User类
public class User {
private UserDAO userDAO;
public UserDAO getUserDAO() {
return userDAO;
}
}
//UserDAO类
public class UserDAO {
}
//测试类
public class Demo {
public static void main(String[] args) {
User user = new User();
user.getUserDAO();
}
}
今、私は最初に注入するためにリフレクションを使用しており、この2つのクラスのような他のニーズがある場合、それはより多くの変更、その後、前のユーザーやデモ、関係に応じて修正されなければならない、新しいUserDAO1代わりUserDAOを作成したいですUserDAOとUserDAO1はIUserDAOを実装してみましょう、とUserクラスのプロパティはIUserDAOになりましょう
public class User {
private IUserDAO userDAO;
public IUserDAO getUserDAO() {
return userDAO;
}
反射デモ注入を持つクラスでuserDAO1
public static void main(String[] args) throws Exception {
User user = new User();
//如果要更换UserDAO类,只需要添加一个新的类让他实现IuserDAO,这里修改一下就可以了
IUserDAO userDAO = new UserDAO1();
//通过反射取得UserDAO的属性并把要更改的类的实例注入
Class<? extends User> aClass = user.getClass();
Field field = aClass.getDeclaredField("userDAO");
field.setAccessible(false);
field.set(user,userDAO);
}
この目的のために、そして確かに私は1つ1、取得するコード行で新しいオブジェクトに移動するにはあまりにも面倒好きではないが、それがたくさんのような大きなプロジェクトは、一つ一つは、それを見つけることがあれば、疑問に思うだろうか?ケースのリークを見つけるには、そのバグ。そして、これだけの書き込みは一度、より多くのクラスの後、より多くのプロジェクトは、その上に、このいずれかを使用することができます。
2.さえ属性にそれを注入する多くの方法がありますか?
そして、最初の二つの性質に、コメントのMyFieldをカスタマイズし、アノテーションを使用し、デフォルト値を与えました
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface MyField {
Class name() default Class.class;
String value() default "";
}
その後、注入される特性に注釈を追加し、必要な注射を加算した値
public class User {
@MyField(name = UserDAO1.class)
public IUserDAO userDAO;
@MyField(value = "张三")
public String name;
public IUserDAO getUserDAO() {
return userDAO;
}
}
デモでは、ユーザーの要素を注入します
public static void main(String[] args) throws Exception {
User user = new User();
//遍历获取user中的所有元素
Field[] declaredFields = user.getClass().getDeclaredFields();
for (Field field:declaredFields){
MyField annotation = field.getAnnotation(MyField.class);
//判断元素上面是否有MyFiled注解
if (annotation != null){
//如果有就获取name和value的值
Class userDAO1 = annotation.name();
String name = annotation.value();
//如果name的值不为空,且不等于默认值,就说明需要注入,直接注入
if (userDAO1!=null && !userDAO1.equals(Class.class)){
field.set(user,userDAO1.newInstance());
}
//如果value值不为空且不等于默认值,就说明需要注入,直接注入
if(name!=null && !name.equals("")){
field.set(user,name);
}
}
}
System.out.println(user);
}
出力はUser{userDAO=com.qf.demo.UserDAO1@511d50c0、名前です=「ジョー・スミス」}
命令注入が成功し、そして今、我々はUserDAOを変更したいあなたはノートの値のみを変更する場合ことがわかったが、厳密に言えば、ノートをJavaのコードは、それは意味していたではないデカップリングの目的を達成するためのJavaコードを変更する必要はありません。
3.だけでなく、Userクラスを注入するためには、多くの種類があるのですか?
実際、原理は同じですが、私は、すべてのクラスを注入して、フォルダ全体を横断する必要性にすべてのJavaファイルへのアクセスをカスタム注釈SpringComponentを追加して、クラスが注入上に書いたSpringComponentに直接注釈を付けます方法
public static void main(String[] args) throws Exception {
Injection injection = new Injection();
injection.init("com.qf.demo");
}
public void init(String packageName) throws Exception {
String basePath="D:\\program\\idea\\day52_demo\\src\\main\\java\\";
//将传入的"com.qf.demo"转换成"com\qf\demo"
String replace = packageName.replace(".", "/");
File file = new File(basePath + "\\"+replace);
//遍历该文件夹下所有文件
File[] files = file.listFiles();
for (File f:files){
String name = f.getName();
if(f.isFile()){
//只有java文件才是哦们需要的,如果是文件就判断是不是以".java"结尾的
if (name.endsWith(".java")){
//如果是就以“.”将文件名分割成"demo"和"java"两部分
String[] split = name.split("\\.");
String className = split[0];
Class<?> aClass = Class.forName(packageName +"." +className);
//判断类上是否有SpringComponent注解,如果有就调用inject方法,将类对象传入
SpringComponent annotation = aClass.getAnnotation(SpringComponent.class);
if (annotation != null){
inject(aClass);
}
}
}else{
//如果不是文件就是文件夹,就使用递归循环该方法
String childPath=packageName+"."+name;
init(childPath);
}
}
}
public <T>void inject(Class<T> clazz) throws Exception {
//创建传入类对象的实例对象
T t = clazz.newInstance();
Field[] declaredFields = clazz.getClass().getDeclaredFields();
for (Field field:declaredFields){
MyField annotation = field.getAnnotation(MyField.class);
//判断元素上面是否有MyFiled注解
if (annotation != null){
//如果有就获取name和value的值
Class aClass = annotation.name();
String name = annotation.value();
//如果name的值不为空,且不等于默认值,就说明需要注入,直接注入
if (aClass!=null && !aClass.equals(Class.class)){
field.set(t,aClass.newInstance());
}
//如果value值不为空且不等于默认值,就说明需要注入,直接注入
if(name!=null && !name.equals("")){
field.set(t,name);
}
}
}
}
エンディング
今、IOCは、最も基本的な機能を実現していますが、次のような多くの欠点があるものの:
1.あなたはアドレスbasePathを変更する必要がある新しいプロジェクトを作成するたび
2.私は、オブジェクト内の要素を取るか、新しい目標を取りたい言葉は、と前者は区別欠く
Bの元素であり、Bと最初の実装は、その後のBが空である場合3.
...