Spring框架之SpringIoc容器(一)

来源:互联网 发布:5到8岁儿童服装店淘宝 编辑:程序博客网 时间:2024/05/16 05:20

   SpringIoC,被称之为控制反转,是一个比较抽象的概念,对于初学者不太好理解,如下面的例子来说,通常我们创建对象时,会通过主动需求的方式来主动的创建一个实例对象,然而,控制反转则是通过将主动权转交给其它,这也是就是控制反转的概念;比如,我们做果汁的时候需要购买果汁机,橙子,准备白开水等,其实这些都是自己主动准备的过程,也就是说这杯果汁需要你主动的去创造,然而,现在你进需要通过微信等下单就可以的倒果汁,你并没有主动的去创造果汁,但是这样也达到了你的要求。

     SpringIoC容器的设计主要是基于BeanFactory和ApplicaitonContext两个接口,其中ApplicationContext也是BeanFactory接口的一个子接口,也就是说,Spring最底层的接口为BeanFactory,其它的高级的接口则实现了对BeanFactory接口的功能的扩展,所以在大多数的情况下都会使用ApplicationContext作为Spring IoC容器,同时其扩展了很多的接口,例如WebApplicationContext,而具体的ApplicationContext则会在某个利于创造实现类在某一个领域使用,例如Spring MVC中的GenericWebApplicationContext就广泛的应用于java web工程之中。

为此我们可以看一下Spring中BeanFactory的源码:

public interface BeanFactory{Stirng FACTORY_BEAN_PREFIX = "&";Object getBean(String name) throws BeanException;<T> T getBean(Class<T> requiredType) throws BeanException;Object getBean(String name,Object...args)throws BeanException;<T> T getBean(Class<T> requiredType,Object...args) throws BeanException;boolean containsBean(String name);boolean isSingleton(String name) throws NoSuchBeanDefinitionException;boolean isPrototype(String name) throws NoSuchBeanDefinitionException;boolean isTypeMatch(Stirng name,ResolveableType typeToMatch) throws NoSuchBeanDefinitionException;boolean isTypeMatch(String name,Class<?> typeToMatch) throws NoSuchBeanDifinitionException;Class<?> getType(String name) throws NoSuchBeanDifinitonException;String [] getAliases(String name);}
对于源码中的个体Bean()方法,从接口中的参数的类型来看,可以字符串也可以是Class类型,由于Class类型可以扩展接口也可以继承父类,所以在一定程度上会存在使用父类类型无法准确货的实例的异常,比如,有一个饮料类,有多个实现类,但是这个时候容器就无法判断获取哪个实现类的实例。

isSingleton是判断此实例是不是单例,是真,则这个容器中只有一个实例,而如果是prototype,则在每次调用时都会生成一个实例,一般的默认情况下是singleton模式。

   我们通过一个实例来进行说明SpringIoc的过程:

首先添加必要的Spring框架的jar包,同时为了方便测试,我们是有JUnit测试类进行测试,所以也需要JUnit相关的Jar包。

我们首先模拟一下SpringIOC容器控制反转的概念,从容器中获取实例,而不是主动的去生成实例。

首先我们先设计一个UnitTestBase类实现读取spring的XML配置文件等,也同时设计了getBean方法,模拟最底层的BeanFactory接口的功能实现;before方法获取整个项目的配置,ClassPathXmlApplicationContext context的实例则在after方法中释放。

public class UnitTestBase {private ClassPathXmlApplicationContext context;private String springXmlpath;public UnitTestBase() {}public UnitTestBase(String springXmlpath) {this.springXmlpath = springXmlpath;}@Beforepublic void before() {if (StringUtils.isEmpty(springXmlpath)) {springXmlpath = "classpath*:spring-*.xml";}try {context = new ClassPathXmlApplicationContext(springXmlpath.split("[,\\s]+"));context.start();} catch (BeansException e) {e.printStackTrace();}}@Afterpublic void after() {context.destroy();}@SuppressWarnings("unchecked")protected <T extends Object> T getBean(String beanId) {try {return (T)context.getBean(beanId);} catch (BeansException e) {e.printStackTrace();return null;}}protected <T extends Object> T getBean(Class<T> clazz) {try {return context.getBean(clazz);} catch (BeansException e) {e.printStackTrace();return null;}}}

1.模拟控制反转的过程

首先设计一个接口OneInterface和对应的实现类OneInterfaceImpl类,设计如下:

public interface OneInterface {public void say(String arg);}
对应的实现类:

public class OneInterfaceImpl implements OneInterface {public void say(String arg) {System.out.println("ServiceImpl say: " + arg);}}
设计的对应的测试类为:
@RunWith(BlockJUnit4ClassRunner.class)public class TestOneInterface extends UnitTestBase {public TestOneInterface() {super("classpath*:spring-ioc.xml");}@Testpublic void testSay() {OneInterface oneInterface = super.getBean("oneInterface");oneInterface.say("This is a test.");}}
    通过调用父类UnitTestBase类的构造方法完成了TestOneInterface类的建立,借用OneInterface接口以及父类的getBean方法完成了SpringBean的获取,在测试方法testSay中实现了控制反转的理念,仅使用getBean()方法就可以获取相应类型的实例,在这里我们仅需要使用传递getBean方法的参数即可,不再需要使用new的主动创建对象的方法,在这里仅需说明使用哪个类型的对象或者是Bean的名字即可,就可以得到相应的对象。

Spring-ioc.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"    xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans.xsd" >        <bean id="oneInterface" class="....OneInterfaceImpl"></bean> </beans>

红色部分则定义类bean的名字为oneInterface,以及bean对应的实现类.


2.SpringBean的注入方式:

定义了一个模拟与数据库操作的流程,利用DAO的设计思想设计了DAO接口,实现类以及service接口及其实现类:

首先定义接口InjectionDAO,用于定义数据库底层操作的方法:

public interface InjectionDAO {public void save(String arg);}
其实现类为InjectionDAOImpl:

public class InjectionDAOImpl implements InjectionDAO {public void save(String arg) {//模拟数据库保存操作System.out.println("保存数据:" + arg);}}
定义InjectionService接口,用于声明业务逻辑所需的方法,可以在这个接口的实现类中完成复杂的业务逻辑:

public interface InjectionService {public void save(String arg);}
其对应的实现类为:

public class InjectionServiceImpl implements InjectionService {private InjectionDAO injectionDAO;//构造器注入public InjectionServiceImpl(InjectionDAO injectionDAO1) {this.injectionDAO = injectionDAO1;}//设值注入public void setInjectionDAO(InjectionDAO injectionDAO) {this.injectionDAO = injectionDAO;}public void save(String arg) {//模拟业务操作System.out.println("Service接收参数:" + arg);arg = arg + ":" + this.hashCode();injectionDAO.save(arg);}}
其中设置类两种bean的注入方式,由构造器或者setter方法设置;同时实现了所继承的save方法。
然而,体现不同的则是再配置文件spring-injection.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"    xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans.xsd" >        <!--         <bean id="injectionService" class="com.imooc.ioc.injection.service.InjectionServiceImpl"> --><!--         <property name="injectionDAO" ref="injectionDAO"></property> --><!--         </bean> --><bean id="injectionService" class="com.imooc.ioc.injection.service.InjectionServiceImpl">        <constructor-arg name="injectionDAO" ref="injectionDAO"></constructor-arg>        </bean>                <bean id="injectionDAO" class="com.imooc.ioc.injection.dao.InjectionDAOImpl"></bean> </beans>
绿色所示的内容为,setter方式的注入,再InjectionServiceImpl类中需要一个injectionDAO类型的类的实例来完成InjectionServiceImpl这个类的实例化,所以再id为injectionService的类的injectionDAO参数则需要引用id为injectionDAO的bean来完成初始化。
红色部分为同构构造器的方式完成springbean的注入,通过使用标签<constructor-arg> 标签完成。
对应的测试类设计如下:
@RunWith(BlockJUnit4ClassRunner.class)public class TestInjection extends UnitTestBase {public TestInjection() {super("classpath:spring-injection.xml");}@Testpublic void testSetter() {InjectionService service = super.getBean("injectionService");service.save("这是要保存的数据");}@Testpublic void testCons() {InjectionService service = super.getBean("injectionService");service.save("这是要保存的数据");}}