天天看点

通俗的介绍Spring的IOC特性和原理

前言:

我才做项目没多久,几个项目都是用的spring框架,先开始其实并不清楚spring有什么好的特性,只知道别人那样写的,我也就依葫芦画瓢的写,后来也是想搞清楚为什么spring框架这么流行,才来大致的看了一些博文和例子,才理解一些东西;在一开始的时候在我脑子里spring的特性就是aop和ioc,别人一问spring就说这两个东西,到底干嘛的怎么实现的,不知道,那么用就行了,现在看起来感觉好无知,哈哈哈;所以说本人还是只菜鸟,有什么地方说的不对的海清大神们能够纠正和指导;

正文:

行了,废话不多说,直接入主题,本篇就先讲讲ioc这个特性;按照正常的介绍都会列出缩写的英文过来解释下,我就不解释了,ioc就叫控制反转;其实我知道,大部分人一开始接触都会产生疑问,不知道什么意思,那么我那个东西来对比一下,就会简单明了了: 我先类比下,就拿我这个人来说,在没有ioc的情况下时:当我饿了的时候,我肯定要吃饭,我自家去买东西吃,当我渴了的时候我要自己倒水喝;而有了ioc之后的情况:我差不多就和几个月大的小孩一样,当我饿的时候就会有人主动喂我吃,我渴了的时候有人主动给我水喝; 从上面这个例子的对比,我们是不是能很清晰的看到,ioc的控制翻转是什么意思了吧,就是原本应该是我自己去做的东西,而ioc会主动地给我做,控制权完全到了spring的手上,而且当我自己吃东西的时候我知道要去吃什么,但是用了ioc后,我并不知道我将要吃什么,spring拿什么给你吃,你就吃什么,但是这是能满足你的需求的,这样的话就实现了解耦,的一项之间的依赖性不强了,我不需要关心调用的那个类里面有其他什么东西,反正spring会在我要的时候拿给我; 再来看下下面的代码就会更加清新的看到这个控制反转的好处: A类

<pre name="code" class="java">public class A {
	
	public void getMethod(){
		B b = new B();
        b.eat();
    }
	
	public void getMethod1(){
		B b = new B();
        b.eat();
    }
	
	public void getMethod2(){
		B b = new B();
        b.eat();
    }
	public void getMethod3(){
		B b = new B();
        b.eat();
    }

}
           

B类

public class B {
    public String eat(){
        return "aaaa";
    };
}
           

从上面的代码片我们不难看的出,上面是在不使用ioc的情况下,A类中的方法调用B类中的eat()方法,需要new一个B对象出来调用;这是一次调用,我们来联想一个场景,如果B中的这个方法在很多类中都被调用了,那是不是每次都要A主动地new一次B对象才能进行调用,这样的话得new多少次;而通过ioc就方便多了,无论你A类中需要调用多少次的不需要你主动地去new多少个B类,只需要把这个B类加入到bean容器中管理,spring会在A需要的时候主动给你new一个B然后调用方法,这样是不是省去了很多new,也方便了;实现ioc的方式有两种,一种是在xml文件中配置bean,那些类是要加入bean中管理的就手动加进去;另外一种就是注解,只要在你申明的那个类上加制定注解就可以了;

看下代码:

A类:

import org.springframework.beans.factory.annotation.Autowired;

public class A {
	
	@Autowired
	private B b;
	
	public void getMethod(){
        b.eat();
    }
	
	public void getMethod1(){
        b.eat();
    }
	
	public void getMethod2(){
        b.eat();
    }
	public void getMethod3(){
        b.eat();
    }

}
           

B类:

public class B {
	public String eat(){
        return "aaaa";
    };

}
           

好了,现在我们知道了控制反转是什么意思了,那在来看看控制反转是怎么实现的呢;我们有就得认识一个新词,DI:依赖注入;就比如说我上面代码片中的那个在声明B上面的@Autowired注解;要知道注解的的实现过程就得知道java中的一个功能,反射;

反射在我们通常的编码情况下不是经常用到;什么是反射呢,简单来讲,就是有一个类,你只知道类名,里面到底有什么你不知道,然后可以通过一些方法你可以动态获取

这个类中的所有方法和属性,就结束了;是怎么实现的呢,现在我们有个类C,先是根据forName("C的路径")或者是C.getClass()来取到C的实例,假如得到的实例叫c1,然后通过c1.getDeclaredMethods();来获取到所有的方法,返回的是个数组;通过c1.getDeclaredFields();获取到所有属性;

下面来看下这段代码:

首先有个未知的类C:

public class C {
	
	private int age;
	
	private String name;

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "C [age=" + age + ", name=" + name + ", getAge()=" + getAge()
				+ ", getName()=" + getName() + ", getClass()=" + getClass()
				+ ", hashCode()=" + hashCode() + ", toString()="
				+ super.toString() + "]";
	}

}
           

然后在写个TestC类来取出C类中的属性和方法:

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class TestC {
	public static void main(String[] args) {
		C c = new C();
		Class<? extends Object> c1 = c.getClass();//取得class对象
		
		Method[] method=c1.getDeclaredMethods();//获取对象中的方法
		for(Method m : method){
			System.out.println("C中的方法有:"+m.toString());
		}
		
		Field[] field=c1.getDeclaredFields();
		for(Field f : field){
			System.out.println("C中的属性有:"+f.toString());
		}
	}

}
           

下面是打印出的结果:

C中的方法有:public java.lang.String com.yoho.controller.C.toString()
C中的方法有:public java.lang.String com.yoho.controller.C.getName()
C中的方法有:public void com.yoho.controller.C.setName(java.lang.String)
C中的方法有:public int com.yoho.controller.C.getAge()
C中的方法有:public void com.yoho.controller.C.setAge(int)
C中的属性有:private int com.yoho.controller.C.age
C中的属性有:private java.lang.String com.yoho.controller.C.name
           

这样是不是就能直观的看出来了,C中的两个属性和set,get,tostring方法都被打出来了;

行了,反射讲清楚后,那注解就很容易理解了,上面那个@Autowried注解就是类似这样实现的,通过取到注解可以取到类名,或者是类对象类型,这边插个题外话,一般实现装箱的注解@Autowried和@Resource两个都可以,前者是按类型,后者是按名称;好了回归正题,通过取到类名后,就通过反射把这个类中的所有方法都取出来,当然肯定不是像我上面打印出来,而是通过加入到spring的bean容器中管理,然后在有需要用的时候spring就会自动给你提供;