本文源码可至码云查阅(https://gitee.com/wondersWX/myspring),我也还在一步步构建中,欢迎fork,欢迎star!
自打开始JavaWeb编程以来,从最初的jsp+servelt,到SSH框架,更行技术框架SSM框架,实现分布式架构,进行前后分离,接触到的框架技术可以说数不胜数,但从没能离开的就是spring,最开始的时候只是将spring用作对象容器,做框架整合,事务管理,然后慢慢从struts过渡到springmvc,使用spring进行view层的控制,再后来,使用spring-boot,有直接打包好的视图层、和jpa、mybatise实体层,到现在使用spring-clouder实现微服务,通过路由加nigix实现前后分离架构。最近在一个微信群中,看到群友分享的一个面试题,如果不能使用spring,你会怎么编程?发现自己看到这个问题着实愣了一下,的确使用spring已成了习惯,没想过缺少了这个框架该怎么办。其实使用了spring这么久,spring两大基础特性ioc(控制反转),aop(面向切面)两大特性可以说是十分熟悉了,自己对该如何实现这两大特性也有一定的思路,那还等什么,自己来尝试实现一下吧!
那么就从大家最熟悉的开始,对于applicationContext.xml文件中bean的配置可以说用过spring的人没有不熟悉的,那么其本质是什么呢?简单说,就是从xml文件中读取到bean的定义,spring的bean工厂基于此定义进行bean的创建和装配,然后你就能轻松通过getBean()方法获取到实例化的对象,再进一步抽象,就是将一段字符串转化为一个对象实例,熟悉反射的人可能就能想到了,这不挺像类的反射嘛,给出类路径获取Class,再使用newInstance获取对象。没错spring的对象创建就是大量使用了反射的方式。好了说了这么多我们就来尝试自己实现一个最简单的IOC吧!
spring的BeanFactory在创建对象时并不是直接读取xml文件中的配置,而是对bean的定义进行了封装也就是BeanDefinition
package com.fxx.bean;
public class BeanDefiniton {
private String beanClassName;
private Class beanClass;
//bean的创建与装载应由工厂完成,beanDefinition只维护此属性,不提供创建bean的方法
private Object bean;
private PropertyValues pvs;
public String getBeanClassName() {
return beanClassName;
}
public void setBeanClassName(String beanClassName) {
this.beanClassName = beanClassName;
//一般通过class反射创建实例,但ioc目的是通过修改字符串达到调整实例的目标故在设定classname的同时,修改beanClass属性
try {
this.beanClass = Class.forName(beanClassName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public Class getBeanClass() {
return beanClass;
}
public void setBeanClass(Class beanClass) {
this.beanClass = beanClass;
}
public Object getBean() {
return bean;
}
public void setBean(Object bean) {
this.bean = bean;
}
public PropertyValues getPvs() {
return pvs;
}
public void setPvs(PropertyValues pvs) {
this.pvs = pvs;
}
}
只是通过反射创建对象还不够,我们当然想要给对象进行属性注入,spring对属性配置也进行了封装package com.fxx.bean;
public class PropertyValue {
private final String name;
private final Object value;
//对象属性属于不可改变的时候,可将其设置为final,在构造器中赋值,并不提供set方法(提供也没用)
public PropertyValue(String name,Object value){
this.name=name;
this.value=value;
}
public String getName() {
return name;
}
public Object getValue() {
return value;
}
}存在多个属性注入,首相想到的是应该是使用list将propertyvalue管理起来,事实上spring也是这么做的,但是为了更灵活的属性注入,提供属性注入前后的操作,那么我们最熟悉的代理设计模式就可以用上了package com.fxx.bean;
import java.util.ArrayList;
import java.util.List;
/**
* 用于载入属性前判断
*/
public class PropertyValues {
private final List<PropertyValue> propertyValueList = new ArrayList<PropertyValue>();
public void addValue(PropertyValue pv){
//此处进行注入前操作
propertyValueList.add(pv);
}
public List<PropertyValue> getPropertyValueList() {
return propertyValueList;
}
}
好了有了beanDfiniton,现在只要将其注册到工厂中,就可以获取到对象了,我们来创建一个最简单的对象工厂,使用map来管理beanDfiniton,通过对象name获取对象,代码如下
package com.fxx.bean.factory;
import com.fxx.bean.BeanDefiniton;
public interface BeanFactory {
Object getBean(String name) throws Exception;
void registBeanDefinition(String name, BeanDefiniton beanDefiniton);
}
package com.fxx.bean.factory;
import com.fxx.bean.BeanDefiniton;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public abstract class AbstractBeanFactory implements BeanFactory{
private final Map<String,BeanDefiniton> beanDefinitonMap = new ConcurrentHashMap<String, BeanDefiniton>();
public Object getBean(String name) throws Exception {
if(!beanDefinitonMap.containsKey(name)||beanDefinitonMap.get(name)==null){
throw new Exception("对象定义不存在!");
}
return beanDefinitonMap.get(name).getBean();
}
/**
* 注册同时创建bean并装载,将bean的创建与装载相分离,创建的方式由子类实现(bean的创建有多种类型的需求)
* @param name
* @param beanDefiniton
*/
public void registBeanDefinition(String name, BeanDefiniton beanDefiniton){
if(beanDefiniton==null){
return;
}
Object bean = null;
try {
bean = creatBean(beanDefiniton);
} catch (Exception e) {
e.printStackTrace();
}
beanDefiniton.setBean(bean);
beanDefinitonMap.put(name,beanDefiniton);
}
protected abstract Object creatBean(BeanDefiniton beanDefiniton) throws Exception;
}
package com.fxx.bean.factory;
import com.fxx.bean.BeanDefiniton;
import com.fxx.bean.PropertyValue;
import com.fxx.bean.PropertyValues;
import java.lang.reflect.Field;
public class AutoWiredBeanFactory extends AbstractBeanFactory{
/**
* 实现实例创建以及属性装载
* @param beanDefiniton
* @return
*/
@Override
protected Object creatBean(BeanDefiniton beanDefiniton) throws Exception{
return doCreatBean(beanDefiniton);
}
private Object doCreatBean(BeanDefiniton beanDefiniton) throws Exception{
Object bean = beanDefiniton.getBeanClass().newInstance();
setPropertyValues(bean,beanDefiniton.getPvs());
return bean;
}
private void setPropertyValues(Object bean,PropertyValues pvs) throws Exception {
if(pvs.getPropertyValueList().size()==0){
return;
}
for (PropertyValue pv : pvs.getPropertyValueList()){
Field declaredField = bean.getClass().getDeclaredField(pv.getName());
declaredField.setAccessible(true);
declaredField.set(bean,pv.getValue());
}
}
}
本文介绍了如何手动实现Spring框架中的IOC容器核心功能,包括通过反射创建对象实例及属性注入过程。作者逐步解析了BeanDefinition、PropertyValue和PropertyValues类的设计原理,并提供了一个简单的Bean工厂实现。
最简单的IOC&spm=1001.2101.3001.5002&articleId=79598468&d=1&t=3&u=096a92bec66c4e999eddc0ff1d559f74)
9883

被折叠的 条评论
为什么被折叠?



