手写简单的beanFactory主要分两步:
1、定义bean对象,对应Spring中的< bean >标签;
2、创建BeanFactory,根据 BeanFactory 来获取实例对象;
bean定义对象:
package com.lks.util;
/**
* Created by likaisong on 2019/3/3.
*/
public class BeanDefined {
private String beanId;
private String classPath;
public void setClassPath(String classPath) {
this.classPath = classPath;
}
public String getBeanId() {
return beanId;
}
public String getClassPath() {
return classPath;
}
}
创建beanFactory
package com.lks.util;
import java.util.List;
/**
* Created by likaisong on 2019/3/3.
*/
public class BeanFactory {
private List<BeanDefined> beanDefinedList;
public List<BeanDefined> getBeanDefinedList() {
return beanDefinedList;
}
public void setBeanDefinedList(List<BeanDefined> beanDefinedList) {
this.beanDefinedList = beanDefinedList;
}
/**
* 通过反射实例化对象
* @param beanId
* @return
* @throws Exception
*/
public Object getBean(String beanId) throws Exception {
Object instance = null;
for (BeanDefined bean : beanDefinedList){
if (beanId.equals(bean.getBeanId())){
String classPath = bean.getClassPath();
instance = Class.forName(classPath).newInstance();
return instance;
}
}
return instance;
}
}
其中最主要的是getBean() 方法,利用反射机制,获取到对象,然后调用 newInstance() 默认的构造方法进行实例化,最后返回一个实例化好的对象,Spring 就是利用类似这样反射工厂的方式进行对象的实例化的。
测试类TestMain.java:
package com.lks.util;
import com.lks.bean.User;
import org.testng.annotations.Test;
import java.util.ArrayList;
import java.util.List;
/**
* Created by likaisong on 2019/3/3.
*/
public class TestMain {
@Test
public void testBeanFactory() throws Exception {
//注册bean
BeanDefined beanDefined = new BeanDefined();
beanDefined.setBeanId("user");
beanDefined.setClassPath("com.lks.bean.User");
List<BeanDefined> beanDefineds = new ArrayList<BeanDefined>(16);
beanDefineds.add(beanDefined);
//声明BeanFactory,类似于Spring中的ApplicationContext
BeanFactory factory = new BeanFactory();
factory.setBeanDefinedList(beanDefineds);
//实际调用
User user = (User) factory.getBean("user");
System.out.println(user);
}
}
这里主要分三步:
1、注册bean,相当于在 Spring 配置文件中添加 < bean > 标签;
2、将注册好的 bean 添加到 BeanFactory 中,使 bean 能够被 BeanFactory 管理,就如 Spring 中 bean 添加到 Spring 容器中一样;
3、通过 BeanFactory 来进行对象的实例化
通过简单的三步,一个类的实例化就完成了,这只是一个最简单的BeanFactory。
为了加深对BeanFactory以及< bean > 标签中的 scope 属性的理解,我们下面在前面一个beanFactory的基础上,实现自己的 scope 属性的功能。
scope 属性有两个值,分别是 prototype(原型)和 singleton(单例)
singleton: 在 Spring 容器启动时,被标记的类创建并保存在 Spring 框架 SingletonList 中,每次都只会返回同一个实例对象。
prototype: Spring 容器在启动时,被标记的类不会被创建,每次都会返回一个全新的实例对象。
在bean定义对象中新增bean scope属性:
package com.lks.util;
/**
* Created by likaisong on 2019/3/3.
*/
public class BeanDefined {
private String beanId;
private String classPath;
//和Spring一样,默认是单例
private String beanScope = "singleton";
public void setBeanScope(String beanScope) {
this.beanScope = beanScope;
}
public String getBeanScope() {
return beanScope;
}
public void setClassPath(String classPath) {
this.classPath = classPath;
}
public String getBeanId() {
return beanId;
}
public String getClassPath() {
return classPath;
}
public void setBeanId(String beanId) {
this.beanId = beanId;
}
}
BeanFactory中处理scope属性,根据scope属性的值返回实例化对象:
package com.lks.util;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Created by likaisong on 2019/3/3.
*/
public class BeanFactory {
//存放bean集合
private List<BeanDefined> beanDefinedList;
private Map<String, Object> springIoc;
public BeanFactory(){
}
public BeanFactory(List<BeanDefined> beanDefinedList) throws Exception {
this.beanDefinedList = beanDefinedList;
springIoc = new HashMap<String, Object>(16);
for (BeanDefined bean: beanDefinedList){
if ("singleton".equals(bean.getBeanScope())){
String classPath = bean.getClassPath();
Object instance = Class.forName(classPath).newInstance();
springIoc.put(bean.getBeanId(), instance);
}
}
}
public List<BeanDefined> getBeanDefinedList() {
return beanDefinedList;
}
public void setBeanDefinedList(List<BeanDefined> beanDefinedList) {
this.beanDefinedList = beanDefinedList;
}
/**
* 通过反射实例化对象
* @param beanId
* @return
* @throws Exception
*/
public Object getBean(String beanId) throws Exception {
Object instance = null;
for (BeanDefined bean : beanDefinedList){
if (beanId.equals(bean.getBeanId())){
String classPath = bean.getClassPath();
instance = Class.forName(classPath).newInstance();
return instance;
}
}
return instance;
}
/**
* 根据scope属性获取实例化对象
* @param beanId
* @return
* @throws Exception
*/
public Object getScopeBean(String beanId) throws Exception {
Object instance = null;
for (BeanDefined bean: beanDefinedList){
if (beanId.equals(bean.getBeanId())){
String classPath = bean.getClassPath();
if ("singleton".equals(bean.getBeanScope())){
instance = springIoc.get(beanId);
} else {
instance = Class.forName(classPath).newInstance();
}
}
}
return instance;
}
}
这里定义一个Map根据beanId存放需要实例化的对象,如果scope的属性值是singleton的话,就把实例化对象存放在map中,在getScopeBean方法中根据scope的值返回已经实例化的对象或者是新实例化的对象。
测试类中的写法基本和上面的testBeanFactory方法差不多,只不过是新增了scope的赋值方法
如果scope的属性值是 prototype的话:
打印出来的是两个完全不同的实例对象。
如果scope的属性值是 singleton的话:
打印出来的是同一个实例对象。