Spring Ioc实现机制——简析

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Anger_Coder/article/details/12706277
        需要明确一点,任何项目没有了Spring,也依旧能做,那么为什么Spring还会这么火?答案就是Spring的两个特性IoC与AOP,这里需要指出的是,并不是Spring提出的AOP的概念,只能说是Spring很好的实现了AOP的特性。那么,这次就先讨论下Spring IoC的实现机制。
 IoC是什么东东?
 IoC实现的机制是什么样子的?
 模拟Spring IoC的实现
 Spring源码中的IoC
 参考资料
一、IoC是什么东东?
        IoC的e文叫做Inversion of Control,翻译过来就是控制反转,那么IoC究竟翻转了什么呢?思考下在面向对象的世界中,如果我们想在对象A中,操作对象B,那么A一定会持有B的引用(对象关系),而后才能进行操作。这样的带来的问题是代码不够整洁、代码维护成本高、耦合度大。
        那么,Spring IoC带来了这个问题的解决办法,Spring将对象之间的依赖关系转而用配置文件来管理,也就是Spring的DI——Dependency Injection(依赖注入),同时,任何一个对象都应该有一个保存他的地方,也就是IoC容器,IoC容器保存了所有的Bean对象,这个Bean对象就是真实的Object。Spring通过IoC容器,进而操作这些Bean,从而达到对这些对象管理以及一些列额外操作的目的。

        那么接下来回答前文提出的问题:
        Q:IoC是什么?
        A:IoC是控制反转器。

        Q:IoC反转了什么?
        A:IoC反转了对象的创建及依赖关系,Spring将对象的创建以及对象之间的依赖关系交给了IoC容器来管理,管理的标准,则是配置文件。
二、IoC的实现机制是什么样的?
        思考下,Spring既然是通过配置文件来管理对象的依赖关系,而IoC则是将这种关系进行了实现。那么,是不是说我们要做如下两件事情:
        1.解析配置文件,获得对象信息
        2.合理的创建它们
        那么,现在根据这个思路来进行尝试

三、模拟Spring IoC的实现
        第一步,解析配置文件,获得对象信息;因为Spring的配置文件是*.xml文件,也就是对XML文件的解析。
        
<?xml version="1.0" encoding="UTF-8"?>
 
<beans>
    <bean id="u" class="com.hzy.dao.impl.UserDAOImpl"/>
    
    <bean id="userService" class="com.hzy.service.UserService">
        <property name="userDAO" bean="u"/>
    </bean>
</beans>
        对XML解析使用了JDOM,jdom的下载地址:http://www.jdom.org/downloads/index.html

        第二步,根据解析出来的关系将实例化他们,这里用到的技术为:反射机制
 public class ClassPathXmlApplicationContext implements BeanFactory
{
    private Map<String, Object> beans = new HashMap<String, Object>();    //IoC容器
    
    public ClassPathXmlApplicationContext() throws Exception
    {
        SAXBuilder builder = new SAXBuilder();
        Document document = builder.build( this.getClass().getClassLoader().getResource( "resource/beans.xml" ) );
        
        Element root = document.getRootElement();
        
        List<Element> list = root.getChildren( "bean" );                // 获得所有的bean的Element
        
        for( int i = 0; i < list.size(); i++ )
        {
            Element element = (Element)list.get( i );
            
            String  id    = element.getAttributeValue( "id" );            
            String  clazz = element.getAttributeValue( "class" );
            
            System.out.println( id + " : " + clazz );
            Object obj = Class.forName( clazz ).newInstance();            // 1th.实例化Bean对象
            beans.put( id, obj );
            
            /**
             *     <bean id="u" class="com.hzy.dao.impl.UserDAOImpl"/>
    
                <bean id="userService" class="com.hzy.service.UserService">
                    <property name="userDAO" bean="u"/>
                </bean>
             */
            // 2th.注入依赖
            // 获得所有property属性
            for( Element propertyElement : (List<Element>)element.getChildren( "property" ) )
            {
                String name       = propertyElement.getAttributeValue( "name" );    // userDAO
                String injectBean = propertyElement.getAttributeValue( "bean" );    // u;
                Object propertyObj = beans.get( injectBean );
                
                // 3th.拼接userService中 userDAO属性 的 setter方法
                // name.substring( 0, 1 ).toUpperCase() 将 u 变成大写
                String methodName = "set" + name.substring( 0, 1).toUpperCase() + name.substring( 1 );
                
                System.out.println( "method name = " + methodName );
                
                /**
                 * getMethod 会返回对象的方法..这个方法来自对象的公开方法或接口        反射机制
                 * Returns a Method object that reflects the specified 
                 * public member method of the class or interface represented by this Class object. 
                 */
                Method m = obj.getClass().getMethod( methodName, propertyObj.getClass().getInterfaces() );
                // 4th.注入
                m.invoke( obj, propertyObj );
            }
        }
    }
    
    @Override
    public Object getBean( String name ) 
    {
        return beans.get( name );
    }
}

        完整工程的示例代码在:Spring Ioc模拟源码,运行com.hzy.test中的UserServiceTest.java即可。

四、Spring中IoC的实现(源码)
        
        首先,如上图所示,Spring的核心组件有Core、Context、Bean这三个;这三个造就了Spring的根基,决定了上层诸如,IoC、AOP、Transaction....这些特性功能。

4.1 三大核心组件的协同工作
        那么看看这三个组件都负责些什么,把Spring想象成一个大型的舞台剧,那么:
        Context:这台舞台剧的场景、硬件设施
        Core    :这台舞台剧的工作人员,负责协调、调动资源
        Bean   :这台舞台唔剧的演员
        
        那么各个组件的实际的工作就是,Bean包装了Object,Object中含有数据;Context为Bean提供生存环境,同时维护Bean之间的关系,而这个Context对应的Bean的集合,这个关系集合就称为IoC容器;而Core则是为发现、建立、维护每个Bean之间的关系提供相应的工具类。
        下面就以ClassPathXmlApplicationContext来解释下这些概念。
        查看Api文档,发现ClassPathXmlApplicationContext继承了BeanFactory,BeanFactory是Bean组件的顶级接口,BeanFactory提供了对Bean的定义、创建、解析。Bean组件在org.springframework.beans包下。同时Bean Factory的最直接实现类是DefaultListableBeanFactory,在这个类中定义了一个集合,用来保存类对象

        Context组件,为了实现资源的调度,实现了ResourceLoader接口,并且Context的ApplicationContext接口继承了BeanFactory,这样Context通过ApplicationContext可以保证能访问到任何外部资源。
        那么我们实现Spring IoC的思路就很简单了:
        1th.解析XML,获得相应的Bean定义
        2th.实例化Bean
        3th.根据注入方式进行注入 (示例中如property)
        4th.利用反射进行注入

五、小结
         Spring是很优秀的开源框架,很多内容值得借鉴
         下篇会讨论AOP的实现,AOP是对传统OOP的一种补充,AOP与OOP的关注点分别为:
OOP:
        将需求功能划分为不同的并且相对独立,封装良好的类,并让他们有着属于自己的行为,依靠集成和多态来定义彼此的关系
AOP:
       将通用需求功能从不相关的类中分离出来,能够使得很多类共享一个行为

六、参考资料
       马士兵 《Spring视频》
       许令波《深入分析 Java Web 技术内幕》
        

————————————————
版权声明:本文为CSDN博主「anger_coder」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Anger_Coder/article/details/12706277

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值