IOC的介绍与使用
1. IOC的介绍
IOC是控制反转,是spring中的一个非常重要一个特性,IOC也称为DI即依赖注入。简而言之就是把spring变成一个容器,由spring来控制对象的创建和他们之间的依赖关系。下面通过一个例子来熟悉spring的IOC的使用与意义。
例:有一个战士(Knight)类,战士有不同的武器,用java实现如下:
- 创建战士类Knight.java。
这个类里有两个属性,用户名(username)和武器(weapon)。武器属性的类型是一个接口weapon,这个接口里只包括一个空方法attack()。在knight.java里面为相应的属性添加getter和setter方法以及构造方法,再编写一个fight()方法,执行weapon的attack方法。
public class Knight {
private String username;
private Weapon weapon;
public Knight() {
}
public Knight(String username, Weapon weapon) {
this.username = username;
this.weapon = weapon;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Weapon getWeapon() {
return weapon;
}
public void setWeapon(Weapon weapon) {
this.weapon = weapon;
}
public void fight(){
System.out.println(username+"开始攻击了");
weapon.attack();
}
}
public interface Weapon {
void attack();
}
- 创建武器的一些类,比如刀Knife,斧子Axe,枪Gun。它们都实现weapon接口。
public class Knife implements Weapon {
public void attack() {
System.out.println("拿起了刀");
}
}
....
public class Axe implements Weapon {
public void attack() {
System.out.println("拿起了斧子");
}
}
....
public class Gun implements Weapon {
public void attack() {
System.out.println("拿起了枪");
}
}
那么knight中如何创建Weapon呢?开始大家都会直接使用new来创建具体的weapon实例,但这种方法过于依赖一个具体的实现类,如果要修改武器的种类,那么所有的都要修改,没有灵活性。还有一种基于工厂的模式来创建,这里给出使用简单的工厂来演示。
public class SimpleFactory{
public static Weapon getWeapon(){
return new Knife();
}
....
public class Test{
public static void main(String[] args){
Weapon w= SimpleFactory.getWeapon();
Knight k=new Knight("老王",w);
k.fight();
}
}
这种基于工厂的模式创建实例解决了灵活性的问题,但调整的时候要修改原代码SimpleFactory,因此也不是很理想。最佳的方式是将具体的类写到配置文件中,通过读取配置文件来创建具体的对象。下面给出这种方式的方法。
2.创建配置文件存储具体的对象
- 创建beans.properties文件,加上下面这个代码
weapon=com.lu.spring.base.Gun
- 为方便确定哪些对象需要创建,可以自己定义一个Annotation来指定要创建的对象
@Retention(RetentionPolicy.RUNTIME)
public @interface Inject {
public String value()default "";
}
然后在需要创建的对象的setter方法上添加该Annotation
@Inject
public void setWeapon(Weapon weapon) {
this.weapon = weapon;
}
- 创建一个基类,在基类中创建所有的对象,让所有需要添加这个对象的类继承这个基类。
public class Base {
public Base(){
Method[] ms=this.getClass().getMethods();
Properties pro=new Properties();
try {
pro.load(Base.class.getClassLoader().getResourceAsStream("beans.properties"));
} catch (IOException e) {
e.printStackTrace();
}
for(Method m:ms){
if(m.isAnnotationPresent(Inject.class)){
String mname=m.getName();
mname=mname.substring(3);
mname=mname.substring(0,1).toLowerCase()+mname.substring(1);//weapon
System.out.println(mname);
String cname= (String) pro.get(mname);
Object o= null;
try {
o = Class.forName(cname).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
m.invoke(this,o);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
}
如此以来,只要创建Knight,就会自动调用父类不带参数的构造方法来完成对象的注入,这就是依赖注入。只要继承Base的所有类都支持这种依赖注入的方式,这就是spring的DI所做的事情。
以上内容只是spring的简单学习,如有不足,望请指正。