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


        最近开始写博客,觉得这样对自己很有好处,可以从头到尾把散乱的知识梳理一遍,通过自己的理解把它写下了,这个过程受益匪浅。今天写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容器的实现。

  • 相关阅读:
    [LeetCode] 1131. Maximum of Absolute Value Expression 绝对值表达式的最大值
    [LeetCode] 1130. Minimum Cost Tree From Leaf Values 叶值的最小代价生成树
    [LeetCode] 1129. Shortest Path with Alternating Colors 颜色交替的最短路径
    [LeetCode] 1128. Number of Equivalent Domino Pairs 等价多米诺骨牌对的数量
    [LeetCode] 1125. Smallest Sufficient Team 最小的必要团队
    [LeetCode] 1124. Longest Well-Performing Interval 表现良好的最长时间段
    [LeetCode] 1122. Relative Sort Array 数组的相对排序
    Gitalk 自动初始化评论
    [LeetCode] 1111. Maximum Nesting Depth of Two Valid Parentheses Strings 有效括号的嵌套深度
    [LeetCode] 1110. Delete Nodes And Return Forest 删点成林
  • 原文地址:https://www.cnblogs.com/leefreeman/p/2511432.html
Copyright © 2020-2023  润新知