学习项目 Github 地址:code4craft/tiny-spring
1、step-1-container-register-and-get
使用map当做bean的容器
1.1 HelloWorldService.java
public class HelloWorldService {
public void helloWorld(){
System.out.println("Hello World!");
}
}
1.2 BeanDefinition.java
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
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容器,两个函数分别实现对bean的插入和读取
1.4 BeanFactoryTest.java
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和一个BeanDefinition,在初始化BeanDefinition的时候new 了一个HelloWorldService
3、将BeanDefinition插入到BeanFactory的map属性
4、需要时,直接从BeanFactory中get到这个BeanDefinition,并获取其中的HelloWorldService,然后执行helloWorld方法。
step-2-abstract-beanfactory-and-do-bean-initilizing-in-it
step1中的bean是初始化好之后再set进去的,实际使用中,我们希望容器来管理bean的创建。于是我们将bean的初始化放入BeanFactory中。相比step1,
- BeanDefinition 类增加了
Class beanClass
和String beanClassName
属性,对应增加了 setter 和 getter 方法,重点关注 setBeanClassName 方法,这个方法加载名为“beanClassName”的类并执行其静态代码块,同时为属性 beanClass 赋值。public void setBeanClassName(String beanClassName) { this.beanClassName = beanClassName; try { this.beanClass = Class.forName(beanClassName); } catch (ClassNotFoundException e) { e.printStackTrace(); } }
- BeanFactoryTest.java
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 方法
step-3-inject-bean-with-property
与step2相比,这里主要为bean注入属性。我们选择将属性注入信息保存成PropertyValue
对象,并且保存到BeanDefinition
中。这样在初始化bean的时候,我们就可以根据PropertyValue来进行bean属性的注入。
-
1、改变 HelloWorldService.java,增加属性
String text
及 setText()方法。 -
2、BeanFactoryTest.java中添加了一段设置属性
public class BeanFactoryTest { @Test public void test() throws Exception { // 1.初始化beanfactory BeanFactory beanFactory = new AutowireCapableBeanFactory(); // 2.bean定义 BeanDefinition beanDefinition = new BeanDefinition(); beanDefinition.setBeanClassName("us.codecraft.tinyioc.HelloWorldService"); // 3.设置属性 PropertyValues propertyValues = new PropertyValues(); propertyValues.addPropertyValue(new PropertyValue("text", "Hello World!")); beanDefinition.setPropertyValues(propertyValues); // 4.生成bean beanFactory.registerBeanDefinition("helloWorldService", beanDefinition); // 5.获取bean HelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService"); helloWorldService.helloWorld(); } }
3、AutowireCapableBeanFactory.java 中增加了一个applyPropertyValues方法,来进行属性赋值。
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); //设置true,使得反射能访问私有变量 declaredField.set(bean, propertyValue.getValue()); } } }
整体流程:
- 目标依旧:执行 HelloWorldService 的 helloWorld 方法,但是不直接 new HelloWorldService()。再加上一个小目标:为 HelloWorldService 的 text 属性赋值。
- 先 new 一个 BeanFactory,再 new 一个 BeanDefinition。
- 通过 Class.forName 得到 HelloWorldService 的 object(同时 将 bean 的
beanClass
和beanClassName
设置好了)。 - 将 PropertyValues 放入 BeanDefinition 的实例中。
- 得到 HelloWorldService 的 instance,将 PropertyValues 的属性值放入 instance 中,(将 bean 的
propertyValues
设置好了),在设置属性bean
,完整的 bean 就此产生,通过 getBean()方法就能够拿到 HelloWorldService 的 instance 了,就可以调用参数/执行方法了。