Spring的IOC

来源:互联网 发布:我的淘宝店铺找不到了 编辑:程序博客网 时间:2024/06/13 08:52

Spring框架可以对Java Bean的处理进行有效的规划,比如创建、销毁,还可以动态的对一个属性进行注入,通过使用Spring的IOC容器,使软件项目对Java Bean的管理更加统一和方便。

IOC的介绍

全称:Inversion of Control中文解释:依赖注入。暂时可以理解为:IOC容器就是为了管理bean,创建bean的一个内存区,在这个内存区可以将操作bean的代码以面向接口的方式进行开发,这样基于接口的多态性程序结构的分层就更加灵活化,维护和扩展更加方便。在Spring中IOC占据了很核心的功能,通过IOC容器就可以完全管理java bean,包括创建、销毁,还可以对数据库的java bean 进行事务处理,并且还支持一些企业级的应用(JDNI,java mail).


传统的方法保存数据是这样的:

public class Runit{SaveService service = new SaveService();public void setService(SaveService service) {this.service = service;}public static void main(String[] args) {Runit runit= new Runit();runit.service.save();}}/*** 存储服务类**/public class SaveService{public void save(){System.out.println("数据被保存到数据库了");}}
上面的设计实际上并不合理,比如:
1.在这里是将数据保存到数据库,如果将数据保存到xml文件中,那么就需要修改SaveService的代码,这样就造成了程序的更改,不利于项目的安全与维护。
2.SaveService无法在单实例的情况下进行重用。因为它的声明是在Runit类中。
3.如果SaveService.java需要引用其他资源,例如数据库的连接,数据库的JNDI、邮件JavaMail的服务、RMI远程方法调用等,那么Runit.java就不得不维护这些资源的开启和关闭。
Spring是怎样解决上面的问题呢?

上面的实例中,Runit.java完全负责创建和使用SaveService.java。这样这俩个模块之间就产生了非常紧的耦合性。即使是接口也依然会出现创建一个实现类的实例赋值给接口的情况。在IOC容器的帮助下,就可以实现松耦合,并且模块之间是分离的。IOC容器也是基于接口和实现分离的。IOC容器。创建对象的操作是有IOC容器来控制的,并且也完全基于接口与实现的分离来开发,接口的实现类是依赖IOC容器进行赋值的,所以控制发转也称依赖注入。


设计使用Spring来实现上面的数据存储过程:

/** * 创建数据保存的接口 **/package dataoperate;public interface IDataOperate {public void save(String text);}package dataoperate;public class DBOperate implements IDataOperate {//这里以输出文本的方法来测试数据保存@Overridepublic void save(){System.out.println("将数据"+text+"保存到数据库了");}}

创建一个运行类:
package run.testimport dataoperate.IDataOperate;public class Run{private IDataOperate dataOperate;public IDataOperate getDataOperate(){return dataOperate;}public void setDataOperate(IDataOperate dataOperate) {this.dataOperate = dataOperate;}public static void main(String[] args) {}}

现在程序中还没有创建一个实现类,只要有接口的实现类实例,那么就可以进行数据的保存了。IOC的使用方法是将类交给IOC容器进行管理,所以这个实现类的创建也要由IOC容器完成。项目中有一个applicationContext.xml配置文件,在这个文件中进行接口实现类的配置。配置的目的就是由接口来创建这个实现类。
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xmlns:p="http://www.springframework.org/schema/p"   xsi:schemaLocation="http://www.springframework.org/schema/beans    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">   <bean id="dboperate" class="dataoperate.DBOperate"></bean>   <bean id="run" class="run.test.Run">   <property name="dataOperate" ref="dboperate"></property>   </bean></beans>

在配置文件中配置了俩个bean,bean标签的功能就是声明一个类,然后通过IOC容器创建出来。id就是对象的变量名称,class代表创建那个类,路径要写全。

在配置Run的bean中又配置了子标签property,它的作用就是对bean中全局变量名为dataOperate进行注入。注入谁呢?由ref属性来配置。这样的设计就是典型的IOC,对象的控制权在IOC容器中。

package run.testimport dataoperate.IDataOperate;public class Run{private IDataOperate dataOperate;public IDataOperate getDataOperate(){return dataoperate;}public void setDataOperate(IDataOperate dataOperate) {this.dataOperate = dataOperate;}public static void main(String[] args) {               ApplicationContext con = new ClassPathXmlApplicationContext("applicationContext.xml");Run run = apc.getBean("run");run.getDataOperate.save();}}
这里它的main方法就是这样的。首先通过配置文件的到上下文。也就是通过这个配置文件的到IOC容器。由于IOC容器里有很多由ioc容器自动创建的bean,所以通过getBean来获得bean实例。

具体IOC容器如何通过配置文件就进行了bean的创建,以及如何注入到另一个bean中,下面来简单的看一下源代码以及它的实现原理:

其实Spring的IOC容器也是一个类,不过该类实现了最基本的BeanFactory接口,通过工厂模式来取得相对应的bean对象的引用。BeanFactory接口提供了那些功能呢?

package org.springframework.beans.factory;import org.springframework.beans.BeansException;public interface BeanFactory {//这里是对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象,如果需要得到工厂本身,需要转义String FACTORY_BEAN_PREFIX = "&";//根据bean的名字,在IOC容器中得到bean实例,这个IOC容器就是一个大的抽象工厂。Object getBean(String name) throws BeansException;/** * 这里是根据bean的名字和Class类型来得到bean的实例,如果获得的bean与类型不匹配,那么将会抛出异常。 */<T> T getBean(String name, Class<T> requiredType) throws BeansException;//根据需要的类型获取bean<T> T getBean(Class<T> requiredType) throws BeansException;//根据名称和可变参数来获取Object getBean(String name, Object... args) throws BeansException;//根据需要的类型以及可变参数获取<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;//是否包含该名称的beanboolean containsBean(String name);//该名称的bean是否是单例boolean isSingleton(String name) throws NoSuchBeanDefinitionException;//该名称的bean是否是原型boolean isPrototype(String name) throws NoSuchBeanDefinitionException;//类型是否匹配boolean isTypeMatch(String name, Class<?> targetType) throws NoSuchBeanDefinitionException;//获取改名称的bean的类型Class<?> getType(String name) throws NoSuchBeanDefinitionException;//获取别名String[] getAliases(String name);}

在BeanFactory中只对IOC容器的基本行为做了定义,不关心bean是怎样加载定义的。如果要知道IOC是怎样加载bean的,需要通过具体的IOC容器,spring已经准备好了一系列工厂来让我们使用,比如XmlBeanFactory就是针对最基础的BeanFactory的IOC容器实现。

Spring提供了一个BeanFactory的基本实现,XmlBeanFactory同样的通过使用模板模式来得到对IOC容器的抽象—AbstractBeanFactory,DefaultListableBeanFactory这些抽象类为其提供模板服务。其中通过Resource接口来抽象bean定义数据,对xml定义文件的解析通过委托给XmlBeanDefinitionReader来完成。下面的代码展现了IOC容器创建的基本过程。

//创建IOC配置文件的抽象资源ClassPathResource res = new ClassPathResource("beans.xml");//创建一个beanFactoryDefaultListableBeanFactory factory = new DefaultListableBeanFactory(res);//把读取配置信息的BeanDefinitionReader,这里是XmlBeanDefinitionReader配置给BeanFactoryXmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);//从定义好的资源位置读入配置信息,具体的解析过程由XmlBeanDefinitionReader来完成,这样完成整个载入bean定义的过程。reader.loadBeanDefinitions(res);

基本的IOC容器源码:

@Deprecated@SuppressWarnings({"serial", "all"})public class XmlBeanFactory extends DefaultListableBeanFactory {//为容器定义一个默认使用的bean定义读取器private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);public XmlBeanFactory(Resource resource) throws BeansException {this(resource, null);}public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {super(parentBeanFactory);this.reader.loadBeanDefinitions(resource);}}


ApplicationContext是BeanFactory的子接口,BeanFactory接口提供了最基本的对象管理功能,而子接口ApplicationContext提供了更多的附加功能。ApplicationContext接口常用的实现类有三个:FileSystemXmlApplicationContext,ClassPathXmlApplicationContext,XmlWebApplicationContext.



0 0
原创粉丝点击