编写一个IOC
结合上期--《1.1 SpringIoC探究--初识IOC》
将代码重新梳理:
代码结构图:
代码如下:AudiCar
package com.imooc.spring.ioc.class03.car;
public class AudiCar implements Car{
public void start() {
System.out.println(this.getClass().getSimpleName() + ": 出发 !!!");
}
public void stop() {
System.out.println(this.getClass().getSimpleName() + ": 到达 !!!");
}
public void turnLeft() {
System.out.println(this.getClass().getSimpleName() + ": 左转 !!!");
}
public void turnRight() {
System.out.println(this.getClass().getSimpleName() + ": 右转 !!!");
}
}
BuickCar
package com.imooc.spring.ioc.class03.car;
public class BuickCar implements Car{
public void start() {
System.out.println(this.getClass().getSimpleName() + ": 出发 !!!");
}
public void stop() {
System.out.println(this.getClass().getSimpleName() + ": 到达 !!!");
}
public void turnLeft() {
System.out.println(this.getClass().getSimpleName() + ": 左转 !!!");
}
public void turnRight() {
System.out.println(this.getClass().getSimpleName() + ": 右转 !!!");
}
}
car
package com.imooc.spring.ioc.class03.car;
public interface Car {
void start();
void stop();
void turnLeft();
void turnRight();
}
Human
package com.imooc.spring.ioc.class03.humen;
public interface Human {
public void goHome();
}
HumenWithCar
package com.imooc.spring.ioc.class03.humen;
import com.imooc.spring.ioc.class03.car.Car;
public abstract class HumenWithCar implements Human{
protected final Car car;
public HumenWithCar(Car car) {
this.car = car;
}
public abstract void goHome();
}
Li4Human
package com.imooc.spring.ioc.class03.humen;
import com.imooc.spring.ioc.class03.car.Car;
public class Li4Human extends HumenWithCar{
public Li4Human(Car car) {
super(car);
}
public void goHome() {
car.start();
car.turnRight();
car.stop();
}
}
Zhang3Human
package com.imooc.spring.ioc.class03.humen;
import com.imooc.spring.ioc.class03.car.Car;
public class Zhang3Human extends HumenWithCar{
public Zhang3Human(Car car) {
super(car);
}
public void goHome() {
car.start();
car.turnLeft();
car.stop();
}
}
为了编写简易版的IoC容器,做以下约定:
1、所有Bean的生命周期交由IoC容器管理;
2、所有被依赖的Bean通过构造方法执行注入;
3、被依赖的Bean要优先创建
POM
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.imooc.spring.ioc</groupId>
<artifactId>SpringIoc-Preparing-Class03</artifactId>
<version>1.0.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
IoC容器功能:
1、实例化Bean;
2、保存Bean;
3、提供Bean;
4、每一个Bean都产生一个唯一的ID与之对应。
IocContrainner.java
package com.imooc.spring.ioc.class03;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
public class IocContrainner {
/**
* 用来存储beans,String为bean的id,Object为bean本身
*/
private final Map<String, Object> beans = new HashMap<String, Object>();
/**
* 根据beanId获取一个bean
* @param beanId beanId
* @return 返回bean
*/
public Object getBean(String beanId) {
return beans.get(beanId);
}
/**
* 委托IoC容器创建一个bean
* @param clazz 要创建的bean的class
* @param beanId beanId
* @param paramBeanIds 要创建的bean的class的构造方法所依赖的bean[需要的参数BeanId们]
*/
public void registerBean(Class<?> clazz, String beanId, String... paramBeanIds) { //paramBeanIds被依赖的BeanId
//组装构造方法所需要的参数值
Object[] paramValues = new Object[paramBeanIds.length];
for (int i = 0; i < paramBeanIds.length; i++) {
Object paramValue = getBean(paramBeanIds[i]);
if (paramValue == null) {
throw new RuntimeException("Can't find bean of id: " + paramBeanIds[i]);
}
paramValues[i] = paramValue;
}
Object bean = null;
// 获取并循环所有的构造方法,调用构造方法实例化Bean
Constructor<?>[] constructors = clazz.getConstructors();
for (Constructor<?> constructor : constructors) {
try {
bean = constructor.newInstance(paramValues);
} catch (InstantiationException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
}
if (bean == null) {
throw new RuntimeException("找不到合适的构造方法:" + paramBeanIds);
}
//将实例化的Bean放入Beans
beans.put(beanId, bean);
}
}
测试用例:Class03Test.java
package com.imooc.spring.ioc.class03;
import com.imooc.spring.ioc.class03.car.AudiCar;
import com.imooc.spring.ioc.class03.car.BuickCar;
import com.imooc.spring.ioc.class03.humen.Human;
import com.imooc.spring.ioc.class03.humen.Li4Human;
import com.imooc.spring.ioc.class03.humen.Zhang3Human;
import org.junit.Before;
import org.junit.Test;
public class Class03Test {
private final IocContrainner iocContrainner = new IocContrainner();
//使用Before:创建Bean和使用bean是两个不同的业务逻辑
@Before
public void before() {
iocContrainner.registerBean(AudiCar.class, "audi");
iocContrainner.registerBean(BuickCar.class, "buick");
iocContrainner.registerBean(Zhang3Human.class, "zhang3", "audi");
iocContrainner.registerBean(Li4Human.class, "li4", "buick");
}
@Test
public void test() {
Human zhang3 = (Human) iocContrainner.getBean("zhang3");
System.out.println("张三要回家啦");
zhang3.goHome();
Human li4 = (Human) iocContrainner.getBean("li4");
System.out.println("李四要回家啦");
li4.goHome();
}
}
输出:
使用IoC容器好处:
1、所有的依赖关系被集中的管理起来,清晰明了:用before方法--zhang3依赖于audi,li4依赖于buick;
2、每个类只需关心自己的业务逻辑:zhang3和li4i的方法中,只关注gohome,创建车甚至车是什么都不关心,只关心具体的gohome业务;
3、很容易更改依赖关系--zhang3依赖于audi,li4依赖于buick,可更换依赖关系。
————————————————————————————————————————————
内容来源---《Spring框架小白的蜕变》---源码