学过Java的人对SSH都不会陌生,其中Spring备受青昧除了它的"轻"之外,还因为他的IOC与AOP两大功能的强大。IOC是Spring的核心概念,全称“Inversion Of Control”,翻译成中文是“控制反转”,很多人都把它叫做“依赖注入(Dependency Injection)”。而它的抽象概念是“
依赖关系的转移”。转移是相对于过去不良的应用程序设计来说的,象“
高层模块不应该依赖于低层模块,而模块必须都依赖于抽象”是IOC的一种表现,“
实现必须依赖于抽象,而不是抽象依赖于实现”是IOC的另一种表现。
举一个例子,控制层调用业务逻辑组件,应该只知道业务逻辑组件的接口,而不知道其具体实现类,同样业务逻辑组件调用DAO组件时也应该只知道DAO组件的接口,这称为“依赖于抽象”。把他们原来的高层依赖于低层的关系转移到xml配置文件与一个大的工厂中(Spring本身就是一个工厂),由它们进行实例化与属性的注入,当要修改他们的依赖关系时,无需修改客户端,只需要修改xml配置文件即可。符合OCP原则的“开放-封闭”。
下面来模拟Spring如何把几层模块之间的依赖关系转移到xml文件中去。
首先设计一个VO--Person.java
import java.io.Serializable;
import java.sql.Date;
public class Person implements Serializable {
private String name; //名字
private int age; //年龄
private Date birthday; //出生年月
private double salary; //月薪
//对应的get,set方法
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
DAO组件接口与DAO的实现类,只是简单模拟一下,并没有真的与数据库进行交互
public interface PersonDao {
public void save(Person p);
public void delete(Person p);
}
public class PersonDaoImpl implements PersonDao {
public void delete(Person p) {
System.out.println("现在进行删除的操作...姓名:" + p.getName()
+ ",年龄:" + p.getAge()+",出生年月:"+p.getBirthday()+",月薪:"+p.getSalary());
}
public void save(Person p) {
System.out.println("现在进行保存的操作...姓名:" + p.getName() + ",年龄:"
+ p.getAge()+",出生年月:"+p.getBirthday()+",月薪:"+p.getSalary());
}
}
业务逻辑组件接口与实现类,这里只是简单地调用DAO组件的方法
public interface PersonService {
public void save(Person p);
public void delete(Person p);
}
public class PersonServiceImpl implements PersonService{
private PersonDao personDao; //依赖于抽象
public void delete(Person p) {
personDao.delete(p);
}
public void save(Person p) {
personDao.save(p);
}
public PersonDao getPersonDao() {
return personDao;
}
public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
}
}
简单模拟Spring工厂的代码
import java.io.File;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public class SpringFactory {
//存储Bean的实例
private Map<String, Object> appMap = new HashMap<String, Object>();
//储存xml配置文件中Bean实例的信息
private Map<String, String> beans = new HashMap<String, String>();
//存储xml配置文件中Bean的属性的信息
private Map<String, String> properties = new HashMap<String, String>();
//工厂采用单例模式
private static SpringFactory df;
//私有构造函数
private SpringFactory() throws Exception {
//采用Dom4j对xml文件进行解析
Document doc = new SAXReader().read(new File("beanContext.xml"));
Element root = doc.getRootElement();
List el = root.elements();
for (Iterator it = el.iterator(); it.hasNext();) {
Element em = (Element) it.next();
String id = em.attributeValue("id");
String impl = em.attributeValue("class");
beans.put(id, impl);
// 开始第2次遍历
List e2 = em.elements();
// 储存属性的内容
StringBuilder s = new StringBuilder();
boolean flag = false;
for (Iterator i = e2.iterator(); i.hasNext();) {
Element em2 = (Element) i.next();
String name = em2.attributeValue("name");
String ref = em2.attributeValue("ref");
String value = em2.attributeValue("value");
if (ref != null) {
s.append("ref,").append(name + ",").append(ref + ";");
} else if (value != null) {
s.append("value,").append(name + ",").append(value + ";");
}
flag = true;
}
if (flag == true) {
properties.put(id, s.toString());
}
}
//实例化Bean并注入Bean的属性
initBeans();
}
private final void initBeans() throws Exception {
// 初始化Bean
for (String id : beans.keySet()) {
try {
Object o = Class.forName(beans.get(id)).newInstance();
appMap.put(id, o);
} catch (Exception e) {
e.printStackTrace();
}
}
//这里按照配置文件注入Bean中的属性
for (String id : properties.keySet()) {
String[] property = properties.get(id).split(";");
for (int i = 0; i < property.length; i++) {
String[] part = property[i].split(",");
String type = part[0];
String name = part[1];
String value = part[2];
// 从已经实例化好的appMap里面取出要设置属性的Object
Object bean = appMap.get(id);
// 获取对应的set方法名称
String methodName = "set" + name.substring(0, 1).toUpperCase()
+ name.substring(1, name.length());
Method[] methods = bean.getClass().getMethods();
for (Method m : methods) {
if (m.getName().equals(methodName)) {
Class[] typeParam = m.getParameterTypes();
// 获取非对象类型的属性转换为对应类型后的值
Object param = null;
if (type.equals("ref")) {
param = appMap.get(value);
} else {
param = getParameter(typeParam[0], value);
}
//捕捉一下参数类型不正确的异常
try {
m.invoke(bean, param);
} catch (IllegalArgumentException e) {
System.out.println("参数<"+name+">类型不正确,依赖注入失败!");
}
}
}
}
}
}
// 输入参数的源对象与值(String类型),转换为正确类型的值(只列出常用的几种)
public Object getParameter(Class c, String value) {
String typeName = c.getName();
if (typeName.equals("int") || typeName.equals("java.lang.Integer")) {
return Integer.valueOf(value);
} else if (typeName.equals("java.lang.String")) {
return value;
} else if (typeName.equals("java.lang.Boolean")||typeName.equals("boolean")) {
return Boolean.valueOf(value);
} else if(typeName.equals("java.lang.Long")||typeName.equals("long")){
return Long.valueOf(value);
}
else if(typeName.equals("java.lang.Double")||typeName.equals("double")){
return Double.valueOf(value);
}
else if(typeName.equals("java.lang.Float")||typeName.equals("float")){
return Float.valueOf(value);
}
//捕捉SimpleDateFormat转换日期失败的异常
else if(typeName.equals("java.util.Date")){
try{
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
return formatter.parse(value);
}catch(ParseException e){
System.out.println("日期参数转换类型失败!请输入\"yyyy-MM-dd\"的格式");
return null;
}
}
////捕捉ava.sql.Date转换日期失败的异常
else if(typeName.equals("java.sql.Date")){
try{
return java.sql.Date.valueOf(value);
}
catch(IllegalArgumentException e){
System.out.println("日期参数转换类型失败!请输入\"yyyy-MM-dd\"的格式");
return null;
}
}
else{
return null;
}
}
// 返回SpringFactory的实例
public static synchronized SpringFactory getInstance() throws Exception {
if (df == null) {
df = new SpringFactory();
}
return df;
}
// 获取Map中实例的方法
public Object getBean(String id) {
return appMap.get(id);
}
}
这里有几点要注意:
第一,其实这里主要就用到了
Java的反射+
xml解析的技术,xml解析用到Dom4j,因此项目要加入Dom4j的jar包才能执行。
第二,工厂是先解析完xml文件,然后再进行Bean与组件的实例化和注入属性,并非边解析边实例化,所以代码多了很多:)
第三,获取要注入属性的类型时,并没有依赖于该私有属性的类型去查找,而是按照该属性的set方法中的参数类型,这正是Spring的做法。因此在不按照Java规范书写时,Spring也能进行注入,如
private String name;
public void setYourName(String yourName) {
name = yourName;
}
当然在xml配置文件你要设置为yourName而并非name
第四,有没看到中间一大段很臃肿的代码,这里是进行属性的类型转换时的操作,因为从xml获取属性的值是String类型,要根据各个Bean不同的属性类型而进行正确的转换,这也是难点之一。本来想用策略模式改造,或者加入一个类似类型转换的系统,但又太麻烦,迟下再完善一下。Spring是用BeanUtils进行类型转换,但性能方面BeanUtil并不是最好的选择。对此大家有什么好的建议
第五,Spring有“singleton”与“prototype”两种模式设置(针对Web应用还有request,session等),上面的例子只是仿照“singleton”模式产生单一实例,而“prototype”是每次请求到来的时候都产生单一实例。单例模式能节省更多的内容空间,但如果涉及到
保存数据与
需要维护状态的时候,就要采用prototype的方式。对于上述例子,把生成实例的代码放到getBean()中去就可以了。
<?xml version="1.0" encoding="GBK"?>
<beanContext>
<bean id="person1" class="spring.simulate.Person">
<property name="name" value="Jam"/>
<property name="age" value="18"/>
<property name="birthday" value="1985-8-8"/>
<property name="salary" value="10000"/>
</bean>
<bean id="person2" class="spring.simulate.Person">
<property name="name" value="Wjm"/>
<property name="age" value="20"/>
<property name="birthday" value="1985-9-9"/>
<property name="salary" value="9000"/>
</bean>
<bean id="personDao" class="spring.simulate.PersonDaoImpl">
</bean>
<bean id="personService" class="spring.simulate.PersonServiceImpl">
<property name="personDao" ref="personDao"/>
</bean>
</beanContext>
客户端测试代码:
public class Client {
public static void main(String[] args) throws Exception {
SpringFactory factory = SpringFactory.getInstance();
//实例化Service组件,Dao组件已经注入到Service的组件中
PersonService service = (PersonService) factory.getBean("personService");
//获取一些Person
Person p1 = (Person) factory.getBean("person1");
Person p2 = (Person) factory.getBean("person2");
service.save(p1);
service.delete(p2);
}
}
结果显示:
现在进行保存的操作...姓名:Jam,年龄:18,出生年月:1985-08-08,月薪:10000.0
现在进行删除的操作...姓名:Wjm,年龄:20,出生年月:1985-09-09,月薪:9000.0
分享到:
相关推荐
标题中的“Spring简单模拟Spring容器”意味着我们将探讨Spring框架的核心特性——IoC(Inversion of Control,控制反转)和DI(Dependency Injection,依赖注入),以及如何通过编程方式模拟Spring容器的工作原理。...
模拟Spring的IoC,我们可以创建一个简单的容器类,其中包含一个Map来存储bean。然后使用注解处理器扫描带有特定注解(如`@Component`)的类,并将它们注册到容器中。当需要注入依赖时,容器可以解析注解并自动装配。...
在本文中,我们将探讨如何通过Java来模拟Spring框架的基本功能。Spring是一个广泛应用的开源框架,它主要为Java应用程序提供依赖注入(Dependency Injection,DI)和面向切面编程(Aspect-Oriented Programming,AOP...
1. **创建Bean工厂**:首先,我们需要一个类来模拟Spring的Bean工厂,它负责创建和管理对象。这个工厂可以包含一个Map,用于存储对象及其对应的类。 2. **定义Bean接口**:为每个需要管理的对象定义一个接口,接口...
通过以上步骤,我们可以构建一个简单的IOC容器,模拟Spring的核心功能。这不仅有助于理解Spring的工作原理,也为我们自定义轻量级框架提供了可能。在实际开发中,了解并掌握Spring的IOC机制能够帮助我们更好地设计和...
【标题】:“自己动手模拟spring” 【描述】:在该主题中,我们将深入理解Spring框架的核心概念,并通过编码实践来模拟其工作原理。参考链接提供了一个CSDN博客文章,作者详细介绍了如何从零开始创建一个简易版的...
总的来说,“模拟Spring”不仅是一次学习之旅,也是一次提升开发技能的过程。通过对源码的阅读和实践,我们可以深入理解Spring的内部工作原理,进一步提升我们的编程水平和问题解决能力。无论你是Spring的新手还是...
在这个模拟Spring IoC的项目中,我们可以深入理解以下几个关键知识点: 1. **容器的概念**:Spring IoC容器是管理对象及其依赖关系的核心组件。在这个模拟项目中,会有一个类或接口扮演容器的角色,负责创建对象、...
这个"模拟spring ioc过程"的学习例子是基于Java语言的,旨在帮助理解Spring框架中的这两个核心概念。在Java工程中,我们通常会通过配置文件(如XML或Java配置类)来定义bean的定义和它们之间的依赖关系。在实际运行...
模拟Spring的IOC功能,我们可以创建一个简单的解析器类,该类负责加载XML配置文件,解析Bean定义,实例化和注入依赖。为了实现这个功能,我们需要了解和使用Java的DOM或SAX解析库,以及反射API。这是一个很好的学习...
Spring容器就是一个bean的Map:private Map, Object> beans = new HashMap, Object>(); 2、本工程,模拟实现Spring的IOC,将xml中配置的Bean读入到Spring容器中,并在测试用例中调用Spring容器中的bean。 3、开发...
本资源名为“模拟spring和工具jar包”,其目的是为了帮助我们理解Spring框架的核心概念——依赖注入,并通过一个简化版的实现来学习这一机制。 依赖注入是Spring框架的核心特性之一,它允许我们在不直接创建对象的...
现在,我们来详细探讨如何简单模拟Spring框架中的CGLIB代理。要进行模拟,首先需要了解CGLIB代理的核心实现原理,包括代理类的生成、方法拦截和回调机制等。 1. 代理类的生成 CGLIB使用Enhancer类来生成代理对象。...
模拟Spring的依赖注入,我们可以创建一个简单的容器类,它使用反射来扫描带有特定注解的类,并根据这些注解管理bean。以下步骤概括了这个过程: 1. **定义注解**:创建自定义注解,如`@MyComponent`,用于标记需要...
本文将通过模拟Spring的`BeanFactory`来深入理解其工作原理,帮助开发者更好地掌握Spring的核心概念。 `BeanFactory`是Spring框架中最基础的bean管理容器,它是所有更高级别的容器(如`ApplicationContext`)的基类...
"模拟Spring"可能意味着我们将通过一个简化版或实例化的Spring核心功能来学习其工作原理。这种实践性的方法有助于我们更直观地理解Spring如何管理对象和处理依赖关系。 首先,Spring中的“AbstractOrientedProgram...
在模拟Spring的依赖注入时,我们可以创建一个类似于Spring容器的类,负责创建和管理对象以及它们的依赖关系。这个类可以包含一个注册方法,用于接收需要注入的对象及其依赖,然后在创建对象时进行注入。 **创建模拟...
**模拟Spring AOP技术** Spring AOP(Aspect Oriented Programming,面向切面编程)是Spring框架中的一个重要组件,它提供了一种在不修改源代码的情况下,通过代理模式来实现横切关注点(如日志、事务管理等)的...
总的来说,这个"模拟Spring架构的简易实现"项目是一个很好的学习工具,可以帮助开发者深入理解Spring框架的工作原理,尤其是依赖注入和面向切面编程的概念。通过实际动手操作,可以更好地掌握这些核心概念,并为实际...
模拟Spring并不是重新创建一个完整的Spring框架,而是为了学习和理解Spring的工作原理,通过编写简单的代码来实现IOC(Inversion of Control,控制反转)和AOP(Aspect-Oriented Programming,面向切面编程)的核心...