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

关于spring的IOC(二)

2015-12-24 17:21 549 查看


什么是Ioc/DI

 IoC 容器:最主要是完成了完成对象的创建和依赖的管理注入等等。

先从我们自己设计这样一个视角来考虑:

所谓控制反转,就是把原先我们代码里面需要实现的对象创建、依赖的代码,反转给容器来帮忙实现。那么必然的我们需要创建一个容器,同时需要一种描述来让容器知道需要创建的对象与对象的关系。这个描述最具体表现就是我们可配置的文件。

对象和对象关系怎么表示?

可以用 xml , properties 文件等语义化配置文件表示。

描述对象关系的文件存放在哪里?

可能是 classpath , filesystem ,或者是 URL 网络资源, servletContext 等。

回到正题,有了配置文件,还需要对配置文件解析。

不同的配置文件对对象的描述不一样,如标准的,自定义声明式的,如何统一? 在内部需要有一个统一的关于对象的定义,所有外部的描述都必须转化成统一的描述定义。

如何对不同的配置文件进行解析?需要对不同的配置文件语法,采用不同的解析器


二、 Spring IOC体系结构

(1) BeanFactory

         Spring Bean的创建是典型的工厂模式,这一系列的Bean工厂,也即IOC容器为开发者管理对象间的依赖关系提供了很多便利和基础服务,在Spring中有许多的IOC容器的实现供用户选择和使用,其相互关系如下:



 

其中BeanFactory作为最顶层的一个接口类,它定义了IOC容器的基本功能规范,BeanFactory 有三个子类:ListableBeanFactory、HierarchicalBeanFactory 和AutowireCapableBeanFactory。但是从上图中我们可以发现最终的默认实现类是 DefaultListableBeanFactory,他实现了所有的接口。那为何要定义这么多层次的接口呢?查阅这些接口的源码和说明发现,每个接口都有他使用的场合,它主要是为了区分在 Spring 内部在操作过程中对象的传递和转化过程中,对对象的数据访问所做的限制。例如 ListableBeanFactory 接口表示这些 Bean 是可列表的,而 HierarchicalBeanFactory 表示的是这些 Bean 是有继承关系的,也就是每个Bean 有可能有父 Bean。AutowireCapableBeanFactory 接口定义 Bean 的自动装配规则。这四个接口共同定义了 Bean 的集合、Bean 之间的关系、以及 Bean 行为.

最基本的IOC容器接口BeanFactory

1 public interface BeanFactory {
2
3      //对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象,
4      //如果需要得到工厂本身,需要转义
5      String FACTORY_BEAN_PREFIX = "&";
6
7      //根据bean的名字,获取在IOC容器中得到bean实例
8      Object getBean(String name) throws BeansException;
9
10     //根据bean的名字和Class类型来得到bean实例,增加了类型安全验证机制。
11      Object getBean(String name, Class requiredType) throws BeansException;
12
13     //提供对bean的检索,看看是否在IOC容器有这个名字的bean
14      boolean containsBean(String name);
15
16     //根据bean名字得到bean实例,并同时判断这个bean是不是单例
17     boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
18
19     //得到bean实例的Class类型
20     Class getType(String name) throws NoSuchBeanDefinitionException;
21
22     //得到bean的别名,如果根据别名检索,那么其原名也会被检索出来
23    String[] getAliases(String name);
24
}


在BeanFactory里只对IOC容器的基本行为作了定义,根本不关心你的bean是如何定义怎样加载的。正如我们只关心工厂里得到什么的产品对象,至于工厂是怎么生产这些对象的,这个基本的接口不关心。

            而要知道工厂是如何产生对象的,我们需要看具体的IOC容器实现,spring提供了许多IOC容器的实现。比如XmlBeanFactory,ClasspathXmlApplicationContext等。其中XmlBeanFactory就是针对最基本的ioc容器的实现,这个IOC容器可以读取XML文件定义的BeanDefinition(XML文件中对bean的描述),如果说XmlBeanFactory是容器中的屌丝,ApplicationContext应该算容器中的高帅富.

 

            ApplicationContext是Spring提供的一个高级的IoC容器,它除了能够提供IoC容器的基本功能外,还为用户提供了以下的附加服务。

从ApplicationContext接口的实现,我们看出其特点:

         1.  支持信息源,可以实现国际化。(实现MessageSource接口)

         2.  访问资源。(实现ResourcePatternResolver接口,这个后面要讲)

         3.  支持应用事件。(实现ApplicationEventPublisher接口)

(2) BeanDefinition

 

         SpringIOC容器管理了我们定义的各种Bean对象及其相互的关系,Bean对象在Spring实现中是以BeanDefinition来描述的,其继承体系如下:



 

Bean 的解析过程非常复杂,功能被分的很细,因为这里需要被扩展的地方很多,必须保证有足够的灵活性,以应对可能的变化。Bean 的解析主要就是对 Spring 配置文件的解析。这个解析过程主要通过下图中的类完成:



Spring的运行



Java代码 

public static void main(String[] args) {
  

        ApplicationContext context = new FileSystemXmlApplicationContext(
  

                "applicationContext.xml");
  

        Animal animal = (Animal) context.getBean("animal");
  

        animal.say();   

    }  

这段代码你一定很熟悉吧,不过还是让我们分析一下它吧,首先是applicationContext.xml

Java代码 

<bean id="animal" class="phz.springframework.test.Cat">
  

        <property name="name" value="kitty" />
  

    </bean>  

他有一个类phz.springframework.test.Cat

Java代码 

public class Cat implements Animal {
  

    private String name;
  

    public void say() {
  

        System.out.println("I am " + name + "!");
  

    }   

    public void setName(String name) {
  

        this.name = name;
  

    }   

}  

实现了phz.springframework.test.Animal接口

Java代码 

public interface Animal {
  

    public void say();
  

}  

很明显上面的代码输出I am kitty! 

那么到底Spring是如何做到的呢? 

接下来就让我们自己写个Spring 来看看Spring 到底是怎么运行的吧! 

首先,我们定义一个Bean类,这个类用来存放一个Bean拥有的属性

Java代码 

/* Bean Id */  

    private String id;
  

    /* Bean Class */  

    private String type;
  

    /* Bean Property */  

    private Map<String, Object> properties = new HashMap<String, Object>();
 

一个Bean包括id,type,和Properties。 

接下来Spring 就开始加载我们的配置文件了,将我们配置的信息保存在一个HashMap中,HashMap的key就是Bean 的 Id ,HasMap 的value是这个Bean,只有这样我们才能通过context.getBean("animal")这个方法获得Animal这个类。我们都知道Spirng可以注入基本类型,而且可以注入像List,Map这样的类型,接下来就让我们以Map为例看看Spring是怎么保存的吧 

Map配置可以像下面的

Java代码 

<bean id="test" class="Test">
  

        <property name="testMap">
  

            <map>   

                <entry key="a">
  

                    <value>1</value>
  

                </entry>   

                <entry key="b">
  

                    <value>2</value>
  

                </entry>   

            </map>   

        </property>   

    </bean>  

Spring是怎样保存上面的配置呢?,代码如下:

Java代码 

if (beanProperty.element("map") != null) {
  

                    Map<String, Object> propertiesMap = new HashMap<String, Object>();
  

                    Element propertiesListMap = (Element) beanProperty   

                            .elements().get(0);
  

                    Iterator<?> propertiesIterator = propertiesListMap   

                            .elements().iterator();   

                    while (propertiesIterator.hasNext()) {
  

                        Element vet = (Element) propertiesIterator.next();   

                        if (vet.getName().equals("entry")) {
  

                            String key = vet.attributeValue("key");
  

                            Iterator<?> valuesIterator = vet.elements()   

                                    .iterator();   

                            while (valuesIterator.hasNext()) {
  

                                Element value = (Element) valuesIterator.next();   

                                if (value.getName().equals("value")) {
  

                                    propertiesMap.put(key, value.getText());   

                                }   

                                if (value.getName().equals("ref")) {
  

                                    propertiesMap.put(key, new String[] { value
  

                                            .attributeValue("bean") });
  

                                }   

                            }   

                        }   

                    }   

                    bean.getProperties().put(name, propertiesMap);   

                }  

接下来就进入最核心部分了,让我们看看Spring 到底是怎么依赖注入的吧,其实依赖注入的思想也很简单,它是通过反射机制实现的,在实例化一个类时,它通过反射调用类中set方法将事先保存在HashMap中的类属性注入到类中。让我们看看具体它是怎么做的吧。 

首先实例化一个类,像这样

Java代码 

public static Object newInstance(String className) {
  

        Class<?> cls = null;
  

        Object obj = null;
  

        try {
  

            cls = Class.forName(className);   

            obj = cls.newInstance();   

        } catch (ClassNotFoundException e) {
  

            throw new RuntimeException(e);
  

        } catch (InstantiationException e) {
  

            throw new RuntimeException(e);
  

        } catch (IllegalAccessException e) {
  

            throw new RuntimeException(e);
  

        }   

        return obj;
  

    }  

接着它将这个类的依赖注入进去,像这样

Java代码 

public static void setProperty(Object obj, String name, String value) {
  

        Class<? extends Object> clazz = obj.getClass();
  

        try {
  

            String methodName = returnSetMthodName(name);   

            Method[] ms = clazz.getMethods();   

            for (Method m : ms) {
  

                if (m.getName().equals(methodName)) {
  

                    if (m.getParameterTypes().length == 1) {
  

                        Class<?> clazzParameterType = m.getParameterTypes()[0];
  

                        setFieldValue(clazzParameterType.getName(), value, m,   

                                obj);   

                        break;
  

                    }   

                }   

            }   

        } catch (SecurityException e) {
  

            throw new RuntimeException(e);
  

        } catch (IllegalArgumentException e) {
  

            throw new RuntimeException(e);
  

        } catch (IllegalAccessException e) {
  

            throw new RuntimeException(e);
  

        } catch (InvocationTargetException e) {
  

            throw new RuntimeException(e);
  

        }   

}  

最后它将这个类的实例返回给我们,我们就可以用了。我们还是以Map为例看看它是怎么做的,我写的代码里面是创建一个HashMap并把该HashMap注入到需要注入的类中,像这样,

Java代码 

if (value instanceof Map) {
  

                Iterator<?> entryIterator = ((Map<?, ?>) value).entrySet()   

                        .iterator();   

                Map<String, Object> map = new HashMap<String, Object>();
  

                while (entryIterator.hasNext()) {
  

                    Entry<?, ?> entryMap = (Entry<?, ?>) entryIterator.next();   

                    if (entryMap.getValue() instanceof String[]) {
  

                        map.put((String) entryMap.getKey(),   

                                getBean(((String[]) entryMap.getValue())[0]));
  

                    }   

                }   

                BeanProcesser.setProperty(obj, property, map);   

            }  

好了,这样我们就可以用Spring 给我们创建的类了,当然Spring能做到的远不止这些,这个示例程序仅仅提供了Spring最核心的依赖注入功能中的一部分。 

转载:http://blog.csdn.net/it_man/article/details/4402245


http://www.cnblogs.com/ITtangtang/p/3978349.html#a2


http://jiwenke.iteye.com/blog/493965
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: