您的位置:首页 > 编程语言 > Java开发

Spring Framework源代码解析之IOC容器(一)

2012-05-21 11:56 435 查看


    最近开始写博客,觉得这样对自己很有好处,可以从头到尾把散乱的知识梳理一遍,通过自己的理解把它写下了,这个过程受益匪浅。今天写Spring的随笔,使用Spring大概有3年时间,可大多时候只是使用它的特性,并没有深入学习它。Spring的源码据网友说写的很漂亮,我也来学习一下。

IOC之HelloWorld

    假设我们有这样一个业务,根据产品的ID,从产品库中取得该产品的详细信息。用户接口可能是Web浏览器、桌面软件或者超市的条形码扫描器,总之会用一个类来接受用户请求,我们暂且定名为ProductAction.java.

而具体处理逻辑则是放在产品服务接口中,ProductService.java。该接口有一个实现类ProductServiceImpl.java,具体实现写在ProductServiceImpl.java中。代码如下:

ProductService.java

public interface ProductService {
/**
* @Title: getProduct
* @Description: 根据ID获取产品信息
* @param id
* @return Product
*
* @throws
*/
Product getProduct(String id);
}


ProductServiceImpl.java

@Service("productService")
public class ProductServiceImpl implements ProductService {

/* (non-Javadoc)
* @see com.cnblogs.leefreeman.domain.service.ProductService#getProduct(java.lang.String)
*/
@Override
public Product getProduct(String id) {
// TODO 此处编写取得产品详细信息的逻辑
return null;
}

}


Product.java

public class Product {
/**
* id
*/
private String id;
/**
* 名称
*/
private String name;
/**
* 生产日期
*/
private Date productionDate;
/**
* 保质期
*/
private Date shelfLife;

/**
* @return the id
*/
public String getId() {
return id;
}

/**
* @param id
*            the id to set
*/
public void setId(String id) {
this.id = id;
}

/**
* @return the name
*/
public String getName() {
return name;
}

/**
* @param name
*            the name to set
*/
public void setName(String name) {
this.name = name;
}

/**
* @return the productionDate
*/
public Date getProductionDate() {
return productionDate;
}

/**
* @param productionDate
*            the productionDate to set
*/
public void setProductionDate(Date productionDate) {
this.productionDate = productionDate;
}

/**
* @return the shelfLife
*/
public Date getShelfLife() {
return shelfLife;
}

/**
* @param shelfLife
*            the shelfLife to set
*/
public void setShelfLife(Date shelfLife) {
this.shelfLife = shelfLife;
}
}


ProductAction. java

public class ProductAction {
/**
* 注入ProductServiceImpl.java
*/
@Resource(name = "productService")
private ProductService productService;

public Product getProductById(String id) {
Product product = productService.getProduct(id);
return product;
}
}


Spring配置文件

<?xml version="1.0" encoding="UTF-8"?>
<?XML:NAMESPACE PREFIX = [default] http://www.springframework.org/schema/beans NS = "http://www.springframework.org/schema/beans" /><?XML:NAMESPACE PREFIX = [default] http://www.springframework.org/schema/beans NS = "http://www.springframework.org/schema/beans" />
<?xml:namespace prefix = context />


这样就可以实现往ProductAction类中注入指定的ProductService,而具体业务的交给了ProductServiceImpl处理。

何为IOC?

    从上例可以看出,通过Spring的IOC特性,将ProductService具体的实现类注入到ProductAction中,从而ProductAction可以调用ProductService的方法进行逻辑处理。在没有使用Spring的情况下,要完成以上功能,也可以通过new关键字,将ProductSerivce接口的实现类实例化出来。但他们的区别在哪里呢?当使用new关键字实例化对象时,ProductAction类对ProductService实现类的实例化具有控制权;而使用Spring IOC时,ProductAction和ProductService之间的关系则通过Spring来配置(通过注解或者XML配置文件),而对ProductService的控制权由ProductAction转移到了Spring IOC容器上,这就是所谓的控制反转。IOC特性的直接用处就是解耦,在ProductAction中,我们并没有看到对ProductService实现类的依赖,而它们之间的依赖关系则是通过第三方(Spring IOC)来维护。

IOC工作流程

Step1:系统运行时,Spring开始启动,指定将加载的配置文件。

应用程序:

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application-context.xml");


Web应用:

web.xml

contextConfigLocation
classpath:spring-hibernate-mysql.xml

org.springframework.web.context.ContextLoaderListener


Step2:接着AbstractApplicationContext类开始调用prepareRefresh方法,对ApplicationContext进行刷新。

Step3:XmlBeanDefinitionReader类调用loadBeanDefinitions方法进行配置文件加载,配置文件中定义的Java Bean会被加载在IOC容器的一个HashMap当中。HashMap的key就是Bean的id,HasMap的value就是这个Java Bean。(当中详细过程分为定位、载入、注册,我们后面再详细说明)

Step4:依赖注入,当用户向IOC容器索要Bean时,将触发BeanFactory中的getBean方法,当然不同类型的配置会调用不同的BeanFactory,如XmlBeanFactory。从而得到相应的JavaBean。

小结

    上面简要介绍了Spring IOC的特性,对IOC的理解,IOC容器的大致工作流程,下文将依据上述流程详细解析IOC容器的实现。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: