Fork me on GitHub

tiny-spring分析笔记(1)

tinySpring 分析笔记——IOC(1)

学习项目 Github 地址:code4craft/tiny-spring

step-1-container-register-and-get

使用 map 当作 bean 的容器,避免间接 new ,代替直接 new。

1.1 HelloWorldService.java

1
2
3
4
5
6
public class HelloWorldService {

public void helloWorld(){
System.out.println("Hello World!");
}
}

简单不解释。

1.2 BeanDefinition.java

1
2
3
4
5
6
7
8
9
10
11
12
public class BeanDefinition {

private Object bean;

public BeanDefinition(Object bean) {
this.bean = bean;
}

public Object getBean() {
return bean;
}
}

最简单的 bean 文件,初始化时为 bean 赋值,getBean() 方法。

1.3 BeanFactory.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class BeanFactory {

private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();

public Object getBean(String name) {
return beanDefinitionMap.get(name).getBean();
}

public void registerBeanDefinition(String name, BeanDefinition beanDefinition) {
beanDefinitionMap.put(name, beanDefinition);
}

}

最简单的容器——Map,具有插入和取值功能。

1.4 BeanFactoryTest.java【important】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class BeanFactoryTest {

@Test
public void test() {
// 1.初始化beanfactory
BeanFactory beanFactory = new BeanFactory();

// 2.注入bean
BeanDefinition beanDefinition = new BeanDefinition(new HelloWorldService());
beanFactory.registerBeanDefinition("helloWorldService", beanDefinition);

// 3.获取bean
HelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService");
helloWorldService.helloWorld();
}
}

整体流程:

  1. 目标:执行 HelloWorldService 的 helloWorld 方法,但是不直接 new HelloWorldService()
  2. 所以先 new 一个 BeanFactory,然后 new 一个 BeanDefinition,在 BeanDefinition 中 new 一个 HelloWorldService(权宜之计)
  3. 将 BeanDefinition 插入 BeanFactory 的属性 Map 中
  4. 有需要时,从 BeanFactory 的 Map 中 get 到这个 BeanDefinition,然后执行 helloWorld 方法
  5. 结束

评价:曲线救国,意识有了,但操作垃圾

step-2-abstract-beanfactory-and-do-bean-initilizing-in-it

相比上一步,step 2 :

  1. BeanDefinition 类增加了 Class beanClassString beanClassName属性,对应增加了 setter 和 getter 方法,重点关注 setBeanClassName 方法,这个方法加载名为“beanClassName”的类并执行其静态代码块,同时为属性 beanClass 赋值。
1
2
3
4
5
6
7
8
9
public void setBeanClassName(String beanClassName) {
this.beanClassName = beanClassName;
try {
this.beanClass = Class.forName(beanClassName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}

2.1 BeanFactoryTest.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class BeanFactoryTest {

@Test
public void test() {
// 1.初始化beanfactory
BeanFactory beanFactory = new AutowireCapableBeanFactory();

// 2.注入bean
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setBeanClassName("us.codecraft.tinyioc.HelloWorldService");
beanFactory.registerBeanDefinition("helloWorldService", beanDefinition);

// 3.获取bean
HelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService");
helloWorldService.helloWorld();

}
}

整体流程:

  1. 目标依旧:执行 HelloWorldService 的 helloWorld 方法,但是不直接 new HelloWorldService()
  2. 先 new 一个 BeanFactory,再 new 一个 BeanDefinition
  3. 但是,没有选择继续 new HelloWorldService,而是将 HelloWorldService 的全路径传入 setBeanClassName 方法中,由此得到这个类的 object(不是 instance)
  4. 在 beanFactory.registerBeanDefinition 的方法中,执行 beanDefinition.getBeanClass().newInstance() 方法,得到这个类的 instance。
  5. 然后从 BeanFactory 的 Map 中 get 到这个 BeanDefinition,然后执行 helloWorld 方法
  6. 结束

评价:将 bean 的创建放入工厂中,不错

step-3-inject-bean-with-property

相对上一步,step 3 为 bean 注入属性:

  1. 改变 HelloWorldService.java,增加属性String text及 setText()方法。

  2. 在 BeanFactoryTest.java 中增加了一段设置 Property(即 text) 的代码,如下:

1
2
3
4
5
6
7
8
// 2.定义 bean
...(拿到 HelloWorldService 的 object
// 3.设置属性
PropertyValues propertyValues = new PropertyValues();
propertyValues.addPropertyValue(new PropertyValue("text", "Hello World!"));
beanDefinition.setPropertyValues(propertyValues);
// 4.生成 bean
...
  1. 在生成 newInstance()的方法之后,增加一个 applyPropertyValues()的方法。在这个方法中,将 HelloWorldService 中 name 为“text”的属性与 PropertyValues 中的同名属性“text”相匹配。然后将属性值赋进去。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class AutowireCapableBeanFactory extends AbstractBeanFactory {

@Override
protected Object doCreateBean(BeanDefinition beanDefinition) throws Exception {
Object bean = createBeanInstance(beanDefinition);
applyPropertyValues(bean, beanDefinition);
return bean;
}

protected Object createBeanInstance(BeanDefinition beanDefinition) throws Exception {
return beanDefinition.getBeanClass().newInstance();
}

protected void applyPropertyValues(Object bean, BeanDefinition mbd) throws Exception {
for (PropertyValue propertyValue : mbd.getPropertyValues().getPropertyValues()) {
Field declaredField = bean.getClass().getDeclaredField(propertyValue.getName());
declaredField.setAccessible(true);
declaredField.set(bean, propertyValue.getValue());
}
}
}

整体流程:

  1. 目标依旧:执行 HelloWorldService 的 helloWorld 方法,但是不直接 new HelloWorldService()。再加上一个小目标:为 HelloWorldService 的 text 属性赋值。
  2. 先 new 一个 BeanFactory,再 new 一个 BeanDefinition。
  3. 通过 Class.forName 得到 HelloWorldService 的 object(同时 将 bean 的 beanClassbeanClassName设置好了)。
  4. 将 PropertyValues 放入 BeanDefinition 的实例中。
  5. 得到 HelloWorldService 的 instance,将 PropertyValues 的属性值放入 instance 中,(将 bean 的propertyValues设置好了),在设置属性bean,完整的 bean 就此产生,通过 getBean()方法就能够拿到 HelloWorldService 的 instance 了,就可以调用参数/执行方法了。
  6. 完毕。
-------------The End-------------