Bean工厂接口类:
public interface BeanFactory {
Object getBean(String name) throws Exception;
}
Bean包装类:
/**
* Bean的内容及元数据,保存在BeanFactory中,包装Bean的实体
*/
public class BeanDefinition {
private Object bean;
private Class<?> beanClass;
private String beanClassName;
public BeanDefinition() {
}
public BeanDefinition(Object object) {
this.bean=object;
}
public void setBeanClassName(String beanClassName) {
this.beanClassName = beanClassName;
try {
this.beanClass = Class.forName(beanClassName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//省略部分get/set方法
}
Bean工厂实现类:
public class AbstractBeanFactory implements BeanFactory {
// 存放Factory里的所有Bean的详细信息
private Map<String, BeanDefinition> beanDefinitionMap =
new ConcurrentHashMap<String, BeanDefinition>();
// 存放Factory里的所有Bean的Name
private final List<String> beanDefinitionNames = new ArrayList<String>();
@Override
public Object getBean(String name) throws Exception {
BeanDefinition beanDefinition = beanDefinitionMap.get(name);
if (beanDefinition == null) {
throw new IllegalArgumentException("No bean named " + name + " is defined");
}
Object bean = beanDefinition.getBean();
return bean;
}
/**
* 将新加入的BeanDefinition注册到BeanDefinitionMap中
*/
public void registerBeanDefinition(String name, BeanDefinition beanDefinition)
throws Exception {
beanDefinitionMap.put(name, beanDefinition);
beanDefinitionNames.add(name);
}
}
至此,一个简单的IOC容器搭建完成。
测试一下:
public class HelloWorldServiceImpl {
public void helloWorld2() {
System.out.println("hello");
}
}
第一步:
BeanDefinition直接根据Bean对象实例化。
public void Step1() throws Exception {
BeanFactory beanFactory = new AbstractBeanFactory();
BeanDefinition beanDefinition = new BeanDefinition(new HelloWorldServiceImpl());
// 注册
((AbstractBeanFactory)beanFactory).registerBeanDefinition("helloworld",beanDefinition);
HelloWorldServiceImpl h = (HelloWorldServiceImpl) beanFactory.getBean("helloworld");
h.helloWorld2();
}
打印结果:helloworld
第二步:
BeanDefinition根据className实例化。
public void Step2() throws Exception {
BeanFactory beanFactory = new AbstractBeanFactory();
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setBeanClassName("com.myspring.HelloWorldServiceImpl");
// 注册
((AbstractBeanFactory)beanFactory).registerBeanDefinition("helloworld",beanDefinition);
HelloWorldServiceImpl h = (HelloWorldServiceImpl) beanFactory.getBean("helloworld");
h.helloWorld2();
}
然后再在AbstractBeanFactory.getBean()方法返还bean之前加上如下代码:
if (bean == null) {
bean = beanDefinition.getBeanClass().newInstance();
}
第三步:
如果我们在HelloWorldServiceImpl里面有简单的参数怎么办?如:
private String text;
private int a;
public void helloWorld() {
System.out.println(text + a + " ss");
}
既然有参数,那我们就设计一个PropertyValue:
/**
* 用于Bean的属性注入
*/
public class PropertyValue {
private final String name;
private final Object value;
// 省略get,set方法
}
然后在BeanDefinition里面增加一个List<PropertyValue> pvs = new ArrayList<PropertyValue>,毕竟不能限制一个类只有一个属性。如果一个类中,有重复的属性,如在spring的配置文件中这样配置:
<bean id="userService" class="com.bjsxt.services.UserService" >
<property name="userDao" bean="u" />
<property name="userDao" bean="u" />
</bean>
因此我们需要再加入一个类PropertyValues
/**
* 包装一个对象所有的PropertyValue。<br/>
*/
public class PropertyValues {
private final List<PropertyValue> propertyValueList = new ArrayList<PropertyValue>();
public PropertyValues() {
}
public void addPropertyValue(PropertyValue pv) {
// TODO 这里可以对重复propertyName进行判断
this.propertyValueList.add(pv);
}
public List<PropertyValue> getPropertyValues() {
return this.propertyValueList;
}
}
因而在BeanDefinition里加入private PropertyValues propertyValues;即可。相应的getBean方法也要变。
@Override
public Object getBean(String name) throws Exception {
BeanDefinition beanDefinition = beanDefinitionMap.get(name);
if (beanDefinition == null) {
throw new IllegalArgumentException("No bean named " + name + " is defined");
}
Object bean = beanDefinition.getBean();
if (bean == null) {
bean = beanDefinition.getBeanClass().newInstance();
}
creatBean(bean, beanDefinition);
return bean;
}
public void creatBean(Object bean, BeanDefinition beanDefinition) throws Exception {
if (beanDefinition.getPropertyValues() != null)
creatBeanWithProperty(bean, beanDefinition);
}
}
public void creatBeanWithProperty(Object bean, BeanDefinition beanDefinition) throws Exception{
int size = beanDefinition.getPropertyValues().getPropertyValues().size();
List<PropertyValue> list = beanDefinition.getPropertyValues().getPropertyValues();
for (int i = 0; i <size ; i++) {
if(list.get(i).getValue() instanceof BeanReference){
String beanName=((BeanReference)list.get(i).getValue()).getName();
Object referenceBean = getBean(beanName);
String ms="set" + Character.toUpperCase(list.get(i).getName().charAt(0)) + list.get(i).getName().substring(1);
Method m = bean.getClass().getDeclaredMethod(ms, referenceBean.getClass());
m.invoke(bean, referenceBean);
} else {
String fieldName = list.get(i).getName();
Object value = list.get(i).getValue();
// getDeclaredField是获得所有的字段(不仅仅是public)
Field field = bean.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(bean, value);
field.setAccessible(false);
}
}
}
测试一下:
public void Step3() throws Exception {
BeanFactory beanFactory = new AbstractBeanFactory();
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setBeanClassName("com.myspring.HelloWorldServiceImpl");
PropertyValues propertyValues = new PropertyValues();
propertyValues.addPropertyValue(new PropertyValue("text","Hello World!"));
propertyValues.addPropertyValue(new PropertyValue("a",new Integer(15)));
beanDefinition.setPropertyValues(propertyValues);
((AbstractBeanFactory)beanFactory).registerBeanDefinition("helloworld", beanDefinition);
HelloWorldServiceImpl h = (HelloWorldServiceImpl) beanFactory.getBean("helloworld");
h.helloWorld();
}
测试结果:Hello World!15 ss
第四步:
上面的类里面的成员变量依然是int,double等的基本变量(String 在这里也算基本变量),如果我在类里面加一个引用变量呢?
private OutputService out;
public void helloWorld3(){
out.output(text);
}
OutputService的output方法很简单就是输出text的内容。
那么下来,理所应当的我们会设计出一个参考类:
public class BeanReference {
private String name;
private Object bean;
}
对于BeanReference,我们可以按下面的方式使用
public void Step4() throws Exception {
BeanFactory beanFactory = new AbstractBeanFactory();
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setBeanClassName("com.myspring.HelloWorldServiceImpl");
BeanDefinition beanDefinition2 = new BeanDefinition();
beanDefinition2.setBeanClassName("com.myspring.OutputService");
BeanReference beanReference = new BeanReference("outPutService");
beanReference.setBean(beanDefinition2);
PropertyValues propertyValues = new PropertyValues();
propertyValues.addPropertyValue(new PropertyValue("text","Hello World! with referencebean"));
propertyValues.addPropertyValue(new PropertyValue("a",new Integer(15)));
propertyValues.addPropertyValue(new PropertyValue("out",beanReference));
beanDefinition.setPropertyValues(propertyValues);
((AbstractBeanFactory)beanFactory).registerBeanDefinition("helloworld", beanDefinition);
((AbstractBeanFactory)beanFactory).registerBeanDefinition("out", beanDefinition2);
HelloWorldServiceImpl h = (HelloWorldServiceImpl) beanFactory.getBean("helloworld");
h.helloWorld3();
}
下面的是creatBean部分
int size = beanDefinition.getPropertyValues().getPropertyValues().size();
for (int i = 0; i <size ; i++) {
List<PropertyValue> list = beanDefinition.getPropertyValues().getPropertyValues();
if (list.get(i).getValue() instanceof BeanReference) {
String beanName = list.get(i).getName();
// 循环调用getBean
Object referenceBean = getBean(beanName);
String ms = "set" + Character.toUpperCase(beanName.charAt(0)) + beanName.substring(1);
Method m = bean.getClass().getDeclaredMethod(ms, referenceBean.getClass());
m.invoke(bean, referenceBean);
} else {
String fieldName = list.get(i).getName();
Object value = list.get(i).getValue();
// getDeclaredField是获得所有的字段(不仅仅是public)
Field field = bean.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(bean, value);
field.setAccessible(false);
}
}
测试结果:Hello World! with referencebean
第五步:
public void Step5() throws Exception {
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader();
xmlBeanDefinitionReader.loadBeanDefinitions("bin/resources/tinyioc.xml");
BeanFactory beanFactory = new AbstractBeanFactory();
for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : xmlBeanDefinitionReader.getBeanDefinitionMap().entrySet()) {
((AbstractBeanFactory)beanFactory).registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());
}
HelloWorldServiceImpl helloWorldService = (HelloWorldServiceImpl) beanFactory.getBean("helloWorldService");
helloWorldService.helloWorld3();
}
在java中,获取文件有两种方式:Class类下的getResource(String path)方法与ClassLoader类下的getResource(String path)方法。
ClassLoader.getResource()参数中不带"/"。默认就是根路径(在Eclipse中,根路径就是工程下的bin文件夹,在默认情况下,Eclipse会把项目中的src下的内容拷贝到bin下,因此也可以理解为根目录就是src目录)。
Class.getResource()可以带"/"也可以不带。一旦带了‘/’就默认从根路径(就是bin 就是src)下查找了;如果没有‘/’就从这个类本身的那个路径下查找。
XmlBeanDefinitionReader的主要作用就是读取xml,然后转换成一个个BeanDefinition,再存储进BeanDefinitionMap,再创建一个BeanFactory,将BeanDefinitionMap中的记录一个一个再注册一遍。
public class XmlBeanDefinitionReader {
private Map<String, BeanDefinition> beanDefinitionMap;
public XmlBeanDefinitionReader(){
beanDefinitionMap = new HashMap<String, BeanDefinition>();
}
public void loadBeanDefinitions(String local) throws IOException, ParserConfigurationException, SAXException {
InputStream is = new FileInputStream(local);
parseNode(is);
}
}
/**
* 通过InputStream 获得每一个bean
* @param is
* @throws ParserConfigurationException
* @throws SAXException
* @throws IOException
*/
public void parseNode(InputStream is) throws ParserConfigurationException, SAXException, IOException {
DocumentBuilderFactory domfac = DocumentBuilderFactory.newInstance();
DocumentBuilder domBuilder = domfac.newDocumentBuilder();
// 默认是工程目录
Document doc = domBuilder.parse(is);
Element root = doc.getDocumentElement();
NodeList beans = root.getChildNodes();
for (int i = 0; i < beans.getLength(); i++)
if (beans.item(i) instanceof Element) {
Element el=(Element)beans.item(i);
parseElement(el);
}
is.close();
}
/**
* 分析每一个bean的id class
* @param el
*/
public void parseElement(Element el){
String id = el.getAttribute("id");
String classPath=el.getAttribute("class");
BeanDefinition bd=new BeanDefinition();
bd.setBeanClassName(classPath);
parseProperties(el,bd);
beanDefinitionMap.put(id, bd);
}
/**
* 分析每一个bean的参数 并加入到beandefinition的property里面
* @param el
* @param bd
*/
public void parseProperties(Element el,BeanDefinition bd){
NodeList bl=el.getElementsByTagName("property");
for (int i = 0; i < bl.getLength(); i++)
if (bl.item(i) instanceof Element) {
Element property=(Element)bl.item(i);
String name=property.getAttribute("name");
if (property.getAttribute("ref")!="") {
BeanReference br=new BeanReference(property.getAttribute("ref"));
PropertyValue pV=new PropertyValue(name,br);
bd.getPropertyValues().addPropertyValue(pV);
}
if (property.getAttribute("value")!="") {
String value=property.getAttribute("value");
PropertyValue pV=new PropertyValue(name, value);
bd.getPropertyValues().addPropertyValue(pV);
}
}
}
public Map<String, BeanDefinition> getBeanDefinitionMap() {
return beanDefinitionMap;
}
第六步:
对比XmlBeanDefinitionReader与AbstractBeanFactory,就能发现两个类里面都有beanDefinitionMap。
另外,在第五步中
BeanFactory beanFactory = new AbstractBeanFactory();
for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : xmlBeanDefinitionReader.getBeanDefinitionMap().entrySet()) {
((AbstractBeanFactory)beanFactory).registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());
}
按照使用者与创建者分离的原则,初始化注册的代码出现在客户端不合适。
public void Step7() throws Exception {
ApplicationContext ac = new ApplicationContext("bin/resources/tinyioc.xml");
HelloWorldServiceImpl helloWorldService = (HelloWorldServiceImpl) ac.getBean("helloWorldService");
helloWorldService.helloWorld3();
}
把XmlBeanDefinitionReader与AbstractBeanFactory合起来,也就是说要把getBean与loadBeanDefinitions装到一个类里面去。
public class ApplicationContext implements BeanFactory {
private AbstractBeanFactory abf = new AbstractBeanFactory();
public ApplicationContext(String local) throws Exception {
loadBeanDefinitions(abf,local);
}
protected void loadBeanDefinitions(AbstractBeanFactory beanFactory,String configLocation) throws Exception {
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader();
xmlBeanDefinitionReader.loadBeanDefinitions(configLocation);
for (Map.Entry<String, BeanDefinition> beanDefinitionEntry :
xmlBeanDefinitionReader.getBeanDefinitionMap().entrySet()) {
beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());
}
}
@Override
public Object getBean(String id) {
Object obj=null;
try {
obj = abf.getBean(id);
} catch (Exception e) {
e.printStackTrace();
}
return obj;
}
}
AbstractBeanFactory与ApplicationContext都继承了BeanFactory,然后我们不直接用BeanFactory,而是让ApplicationContext中装一个AbstractBeanFactory,这不就是最简单的代理模式么?
这里还有一些部分与TinySpring不同:
1 Resources部分
在我完成的代码里,读取xml的时候直接就是一个InputStream,TinySpring的方式是有一个Resource类,同时还有一个LoadResource类用来加载资源,当然实现的内部机理都是inputstream;
2 接口问题
我一直认为,良好的代码是一次一次重构出来的,依我现在的水平,确实不能够很清晰地说出,分了那么多层接口,抽象类的实际作用,因此在我的代码里各个部分都很"薄弱"(只有一层)
3 类的加载
有两种方式一种直接加载,一种延迟加载,TinySpring最开始的那几个step还是在getBean的时候才newInstance的,但是到后面所以的类都直接加载了。
protected void onRefresh() throws Exception{
beanFactory.preInstantiateSingletons();
}
public void preInstantiateSingletons() throws Exception {
for (Iterator<String> it = this.beanDefinitionNames.iterator(); it.hasNext();) {
String beanName = (String) it.next();
getBean(beanName);
}
}
4 单例模式
TinySpring中一个bean默认只会加载一次,第二次getBean()的时候会取出之前已经creat的那个;
public Object getBean(String name) throws Exception {
BeanDefinition beanDefinition = beanDefinitionMap.get(name);
if (beanDefinition == null) {
throw new IllegalArgumentException("No bean named " + name + " is defined");
}
Object bean = beanDefinition.getBean();
// 查找beanDefinition
if (bean == null) {
bean = doCreateBean(beanDefinition);
bean = initializeBean(bean, name);
beanDefinition.setBean(bean);
}
return bean;
}
protected Object doCreateBean(BeanDefinition beanDefinition) throws Exception {
Object bean = createBeanInstance(beanDefinition);
// 写入beanDefinition
beanDefinition.setBean(bean);
applyPropertyValues(bean, beanDefinition);
return bean;
}
我写的代码中,没有上面的步骤,因此即使第二次get一个已经get过得bean,仍然会产生一个新的bena!
转:http://blog.csdn.net/dlf123321/article/details/39994071,http://blog.csdn.net/dlf123321/article/details/40017593
分享到:
相关推荐
我尝试从使用功能的角度出发,参考Spring的实现,一步一步构建,最终完成一个精简版的Spring,tiny-spring是为了学习Spring的而开发的,可以认为是一个Spring的精简版。不需要反编译,直接下载后,用myeclipse打开。...
在分析和实现TinyShell的过程中,学生可以深入理解操作系统的工作原理,如进程创建、文件系统交互、I/O操作以及命令行接口的设计思想。这不仅是对C语言编程技能的锻炼,也是对操作系统概念的实践应用。通过完成这个...
tiny-spring是为了学习Spring的而开发的,可以认为是一个Spring的精简版。Spring的代码很多,层次复杂,阅读起来费劲。我尝试从使用功能的角度出发,参考Spring的实现,一步一步构建,最终完成一个精简版的Spring。...
在"tiny-spring-master"这个项目中,可能是对Spring框架的一个简化版实现,它可以帮助初学者更直观地理解Spring的基本工作原理。通过阅读这个小型版本的源码,你可以逐步了解Spring的核心特性,为后续深入研究完整版...
在源代码分析过程中,理解Spring的模块化设计和组件间的交互至关重要。例如,`BeanPostProcessor`接口允许自定义bean初始化和销毁的逻辑,`ApplicationListener`接口则可以监听Spring事件。深入源码还可以发现Spring...
文档中提到的“1000行代码读懂Spring核心”,指的是通过一个名为tiny-spring的开源项目,来逐步讲解Spring框架的实现原理。这个项目是对Spring框架核心功能的一个简化版本,通过逐行代码的分析,来帮助开发者理解...
源码分析可以帮助我们了解tiny-beans如何实现依赖查找、初始化Bean以及管理它们的生命周期等核心功能。 总的来说,tiny-beans是一个针对小型项目或对框架性能和体积有特定要求的Java开发者的理想选择。它以简洁、...
SSM集成,即Spring、SpringMVC和Mybatis的整合,是Java开发中常见的Web应用程序框架。这个示例项目展示了如何将这三个强大的...开发者可以通过分析和运行这个项目,深入理解SSM集成的工作原理,为自己的项目提供参考。
三、mall-tiny-01项目结构分析 1. `pom.xml`:项目的主配置文件,定义了项目依赖和构建规则。 2. `src/main/java`:包含了主要的业务逻辑代码,按照模块进行了组织,如`com.macro.mall.tiny.modules.*`。 3. `src/...
Order-System-Backend 后台部署文档Order system backend; Nginx + python3 flask + mysql db一、部署架构图二、部署流程1. 服务器后台环境配置1.1 服务器系统环境腾讯云 Ubuntu 16.04 LTS Server1.2 Docker 安装若...
家居网关的硬件载体为基于ARM Cortex-A9的Tiny4412开发板,其软件部分则采用Qt开发,Qt是一个高效的跨平台C++图形用户界面应用程序开发框架。 文章中还提到了智能家居系统中采用的Wi-Fi、ZigBee、蓝牙等通信协议,...
6. **项目实现过程**:开发过程中,需要进行需求分析、系统设计、编码实现、单元测试和集成测试等步骤。同时,代码版本控制工具如Git的使用,保证了团队协作的效率和代码的一致性。在部署阶段,可能采用Tomcat服务器...
同时此项目配备了完善的开发文档( 60+ 页 ),涵盖了整个系统的需求分析、功能分析、系统设计、数据库设计、系统模块设计和系统实现等内容,可以为项目的学习者或使用者提供很好的辅助作用。 技术栈: Spring + ...
基于SSM框架搭建的java web商家进销...spring+spring mvc+mybatis+bootstrap+jquery+highcharts+Ajax 数据库文件 链接: https://pan.baidu.com/s/19x_5WF3SGm_PfnjynBYTCA 密码: a38p jar包文件 maven搭建
这样的项目通常旨在让学生全面了解并实践Web开发过程,包括需求分析、系统设计、编码实现、测试和文档编写等环节。 综上所述,"基于SSH的lmzManagement系统示例源码"是一个完整的Java Web项目,它利用SSH框架实现了...
6. **毕业论文与毕业设计**:这个项目可能是一个学生毕业设计或论文的一部分,因此包含了完整的开发过程,从需求分析、系统设计到编码实现,再到测试和文档编写。这部分内容对学习者来说具有很高的参考价值,可以...
- **图片处理**: 可能会用到图片懒加载技术,如Intersection Observer,以及图片压缩库,如TinyPNG,以优化用户体验和加载速度。 - **AJAX**: 用于实现无刷新的页面更新,提高用户体验,可能使用jQuery或其他库...
7. 数据分析模块:统计销售数据,分析用户行为。这可能需要使用数据挖掘技术,如Apache Hadoop或Spark进行大数据处理。 在开发过程中,项目可能采用了Maven或Gradle作为构建工具,进行依赖管理。同时,为了保证代码...
5. **Spring框架**:依赖注入、AOP、事务管理、Spring Boot、Spring Cloud。 6. **数据库**:SQL优化、索引原理、事务隔离级别、主从复制、分库分表。 7. **网络协议**:TCP/IP、HTTP、HTTPS等,以及网络编程。 *...