1:从最简单的工厂模式开始
BeanDefinition : 一个用来描述bean的类
BeanFactory : 一个用来存储 BeanDefinition 集合的类,提供了get和set方法。
BeanDefinition:
public class BeanDefinition {
private Object bean;
public BeanDefinition(Object bean) {
this.bean = bean;
}
public Object getBean() {
return bean;
}
}
BeanFactory:
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);
}
}
测试类
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();
}
}
public class HelloWorldService {
public void helloWorld(){
System.out.println("Hello World!");
}
}
使用工厂模式来存储BeanDefinition ,这个 BeanDefinition 是spring 在生成Bean之前, 要先对类进行封装,记下类的属性, 单例 , 类路径 等等一些 属性来描述这个以后要生成bean的这个类。
2:抽象工厂模式 创建bean
把 BeanFactory 变成接口,转换成抽象工厂模式,然后定义方法,具体的实现交给子类,子类新增创建bean的方法。
BeanFactory 接口
public interface BeanFactory {
Object getBean(String name);
void registerBeanDefinition(String name, BeanDefinition beanDefinition);
}
抽象工厂
AbstractBeanFactory
public abstract class AbstractBeanFactory implements BeanFactory {
private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();
@Override
public Object getBean(String name) {
return beanDefinitionMap.get(name).getBean();
}
@Override
public void registerBeanDefinition(String name, BeanDefinition beanDefinition) {
Object bean = doCreateBean(beanDefinition);
beanDefinition.setBean(bean);
beanDefinitionMap.put(name, beanDefinition);
}
/**
* 初始化bean
* @param beanDefinition
* @return
*/
protected abstract Object doCreateBean(BeanDefinition beanDefinition);
}
抽象工厂实现类
public class AutowireCapableBeanFactory extends AbstractBeanFactory {
@Override
protected Object doCreateBean(BeanDefinition beanDefinition) {
try {
Object bean = beanDefinition.getBeanClass().newInstance();
return bean;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
}
BeanDefinition 除了会有生成的bean属性外,新增class classname属性
public class BeanDefinition {
private Object bean;
private Class beanClass;
private String beanClassName;
public BeanDefinition() {
}
public void setBean(Object bean) {
this.bean = bean;
}
public Class getBeanClass() {
return beanClass;
}
public void setBeanClass(Class beanClass) {
this.beanClass = beanClass;
}
public String getBeanClassName() {
return beanClassName;
}
public void setBeanClassName(String beanClassName) {
this.beanClassName = beanClassName;
try {
this.beanClass = Class.forName(beanClassName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public Object getBean() {
return bean;
}
}
3:创建bean 再设置bean的属性
BeanFactory , AbstractBeanFactory 代码不变
新增类 PropertyValue 用来描述bean对象的属性
public class PropertyValue {
private final String name;
private final Object value;
public PropertyValue(String name, Object value) {
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
public Object getValue() {
return value;
}
}
新增属性集合类,而并不是直接使用一个集合,这样做的好处就是,通过类封装集合,可以在设置集合的时候,再设置其他的一下属性。
PropertyValues
public class PropertyValues {
private final List<PropertyValue> propertyValueList = new ArrayList<PropertyValue>();
public PropertyValues() {
}
public void addPropertyValue(PropertyValue pv) {
//TODO:这里可以对于重复propertyName进行判断,直接用list没法做到
this.propertyValueList.add(pv);
}
public List<PropertyValue> getPropertyValues() {
return this.propertyValueList;
}
}
在BeanDefinition中新增PropertyValues 集合类
public class BeanDefinition {
private Object bean;
private Class beanClass;
private String beanClassName;
private PropertyValues propertyValues;
......
}
在实现类去实现创建类的时候,要把对象属性设置上去
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());
}
}
}
4:怎么获取BeanDefinition(xml)
资源接口以及实现类
//定义抽象类 来获取资源的流
public interface Resource {
InputStream getInputStream() throws IOException;
}
//通过url可以获取资源 提供获取资源的方式
public class UrlResource implements Resource {
private final URL url;
public UrlResource(URL url) {
this.url = url;
}
@Override
public InputStream getInputStream() throws IOException{
URLConnection urlConnection = url.openConnection();
urlConnection.connect();
return urlConnection.getInputStream();
}
}
//资源加载器
public class ResourceLoader {
public Resource getResource(String location){
URL resource = this.getClass().getClassLoader().getResource(location);
return new UrlResource(resource);
}
}
定义 BeanDefinitionReader 来得到 BeanDefinition ,然后在抽象类定义获取的BeanDefinition 集合和获取BeanDefinition 的来源的ResourceLoader
spring中存在大量的抽象类来实现接口的方式(类似装饰器模式),通过包装抽象类,把所有实现类的功能再抽象到一个类中。
public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader {
private Map<String,BeanDefinition> registry;
private ResourceLoader resourceLoader;
protected AbstractBeanDefinitionReader(ResourceLoader resourceLoader) {
this.registry = new HashMap<String, BeanDefinition>();
this.resourceLoader = resourceLoader;
}
public Map<String, BeanDefinition> getRegistry() {
return registry;
}
public ResourceLoader getResourceLoader() {
return resourceLoader;
}
}
具体的XmlBeanDefinitionReader 类继承 BeanDefinitionReader,通过解析xml -> resource 来获取bean
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
public XmlBeanDefinitionReader(ResourceLoader resourceLoader) {
super(resourceLoader);
}
@Override
public void loadBeanDefinitions(String location) throws Exception {
InputStream inputStream = getResourceLoader().getResource(location).getInputStream();
doLoadBeanDefinitions(inputStream);
}
protected void doLoadBeanDefinitions(InputStream inputStream) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = factory.newDocumentBuilder();
Document doc = docBuilder.parse(inputStream);
// 解析bean
registerBeanDefinitions(doc);
inputStream.close();
}
public void registerBeanDefinitions(Document doc) {
Element root = doc.getDocumentElement();
parseBeanDefinitions(root);
}
protected void parseBeanDefinitions(Element root) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
processBeanDefinition(ele);
}
}
}
protected void processBeanDefinition(Element ele) {
String name = ele.getAttribute("name");
String className = ele.getAttribute("class");
BeanDefinition beanDefinition = new BeanDefinition();
processProperty(ele,beanDefinition);
beanDefinition.setBeanClassName(className);
getRegistry().put(name, beanDefinition);
}
private void processProperty(Element ele,BeanDefinition beanDefinition) {
NodeList propertyNode = ele.getElementsByTagName("property");
for (int i = 0; i < propertyNode.getLength(); i++) {
Node node = propertyNode.item(i);
if (node instanceof Element) {
Element propertyEle = (Element) node;
String name = propertyEle.getAttribute("name");
String value = propertyEle.getAttribute("value");
beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name,value));
}
}
}
}
5:解决循环依赖问题
解决循环依赖问题核心思想:
创建一个bean属性的时候判断这个bean是否存在。
详细就是:用一个对象来描述一个类引用其他类的情况,之前初始化beanDefintion的时候就调用createbean方法,现在统一再getbean的时候判断为空就创建bean,然后如果想就把所有的bean初始化,循环beanname 然后创建bean。
核心代码:
1:填充属性的时候发现是对象,就再调用getbean方法,如果容器有这个bean就能直接获取到这个bean,如果容器没有这个bean就再去创建bean直到它返回。
private void applyPropertyValues(Object bean, BeanDefinition beanDefinition) {
try {
//获取所有的属性的集合
PropertyValues propertyValues = beanDefinition.getPropertyValues();
for(PropertyValue propertyValue : propertyValues.getPropertyValues()){
Field field = bean.getClass().getDeclaredField(propertyValue.getName());
field.setAccessible(true);
Object value = propertyValue.getValue();
//在加载属性的时候发现这个属性是一个bean,去把这个bean获取到然后设置到属性上
if (value instanceof BeanReference) {
BeanReference beanReference = (BeanReference) value;
//就是说这个类的bean属性设置的时候 又会去调用父方法的getBean方法获取bean,
// 这个就是我们在调试spring源码的时候 老是转回来的原因 也就是我们放弃的原因
value = getBean(beanReference.getName());
}
field.set(bean, value);
}
}catch (Exception e){
e.printStackTrace();
}
}
@Override
public Object getBean(String name) {
BeanDefinition beanDefinition = beanDefinitionMap.get(name);
if(null == beanDefinition){
throw new IllegalArgumentException("No bean named " + name + " is defined");
}
Object bean = beanDefinition.getBean();
if(null == bean){
bean = doCreateBean(beanDefinition);
}
return bean;
}
2:在读取xml配置的时候,要提前识别这个属性 是一个bean ,然后初始化这个bean的时候才能知晓
private void processProperty(Element ele, BeanDefinition beanDefinition) {
NodeList propertyNode = ele.getElementsByTagName("property");
for (int i = 0; i < propertyNode.getLength(); i++) {
Node node = propertyNode.item(i);
if (node instanceof Element) {
Element propertyEle = (Element) node;
String name = propertyEle.getAttribute("name");
String value = propertyEle.getAttribute("value");
//是普通的含有值的属性 直接把属性值添加进来
if (value != null && value.length() > 0) {
beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, value));
}else{
//没有值的 那没有值的一种是ref 就是属性是其他bean情况
String ref = propertyEle.getAttribute("ref");
//如果配置和ref 没有配置ref内容 抛出异常
if (ref == null || ref.length() == 0) {
throw new IllegalArgumentException("Configuration problem: <property> element for property '"
+ name + "' must specify a ref or value");
}
//如果ref配置了一个其他bean的名称, 之前定义的描述属性 对象类 也可以存储这个 bean属性,因为 PropertyValue 的属性值是一个Object
BeanReference beanReference = new BeanReference(ref);
beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, beanReference));
}
}
}
}
6:AppliactionContext 加入
新增applicationContext接口,老三样,接口,抽象类,具体实现类
public interface ApplicationContext extends BeanFactory {
}
public abstract class AbstractApplicationContext implements ApplicationContext{
protected AbstractBeanFactory beanFactory;
public AbstractApplicationContext(AbstractBeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
public void refresh() throws Exception{
}
@Override
public Object getBean(String name) {
return beanFactory.getBean(name);
}
}
public class ClassPathXmlApplicationContext extends AbstractApplicationContext{
private String configLocation;//加载xml的地址
public ClassPathXmlApplicationContext(String configLocation) throws Exception {
this(configLocation, new AutowireCapableBeanFactory());
}
public ClassPathXmlApplicationContext(String configLocation, AbstractBeanFactory beanFactory) throws Exception{
super(beanFactory);
this.configLocation = configLocation;
refresh();
}
/**
* 相当于把之前的加载的这一段代码 都放在了ApplicationContext 中
* @throws Exception
*/
@Override
public void refresh() throws Exception {
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader());
xmlBeanDefinitionReader.loadBeanDefinitions(configLocation);
for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : xmlBeanDefinitionReader.getRegistry().entrySet()) {
beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());
}
}
}
核心就是 applicationContext 继承了BeanFactory类,然后把上一张我们初始化 beanDefintion map等动作的功能干了.
调用方式如下 ,只能说很像, 有点相似了。
public void test() throws Exception {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("tinyiocl6.xml");
OrderService orderService = (OrderService) classPathXmlApplicationContext.getBean("orderService");
System.out.println(orderService.getStockService());
}