Spring框架之SpringIoc容器(一)
2017-10-14 20:24
477 查看
SpringIoC,被称之为控制反转,是一个比较抽象的概念,对于初学者不太好理解,如下面的例子来说,通常我们创建对象时,会通过主动需求的方式来主动的创建一个实例对象,然而,控制反转则是通过将主动权转交给其它,这也是就是控制反转的概念;比如,我们做果汁的时候需要购买果汁机,橙子,准备白开水等,其实这些都是自己主动准备的过程,也就是说这杯果汁需要你主动的去创造,然而,现在你进需要通过微信等下单就可以的倒果汁,你并没有主动的去创造果汁,但是这样也达到了你的要求。
SpringIoC容器的设计主要是基于BeanFactory和ApplicaitonContext两个接口,其中ApplicationContext也是BeanFactory接口的一个子接口,也就是说,Spring最底层的接口为BeanFactory,其它的高级的接口则实现了对BeanFactory接口的功能的扩展,所以在大多数的情况下都会使用ApplicationContext作为Spring IoC容器,同时其扩展了很多的接口,例如WebApplicationContext,而具体的ApplicationContext则会在某个利于创造实现类在某一个领域使用,例如Spring
MVC中的GenericWebApplicationContext就广泛的应用于java web工程之中。
为此我们可以看一下Spring中BeanFactory的源码:
isSingleton是判断此实例是不是单例,是真,则这个容器中只有一个实例,而如果是prototype,则在每次调用时都会生成一个实例,一般的默认情况下是singleton模式。
我们通过一个实例来进行说明SpringIoc的过程:
首先添加必要的Spring框架的jar包,同时为了方便测试,我们是有JUnit测试类进行测试,所以也需要JUnit相关的Jar包。
我们首先模拟一下SpringIOC容器控制反转的概念,从容器中获取实例,而不是主动的去生成实例。
首先我们先设计一个UnitTestBase类实现读取spring的XML配置文件等,也同时设计了getBean方法,模拟最底层的BeanFactory接口的功能实现;before方法获取整个项目的配置,ClassPathXmlApplicationContext context的实例则在after方法中释放。
1.模拟控制反转的过程
首先设计一个接口OneInterface和对应的实现类OneInterfaceImpl类,设计如下:
Spring-ioc.xml的配置如下:
红色部分则定义类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> 标签完成。
对应的测试类设计如下:
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; } @Before public void before() { if (StringUtils.isEmpty(springXmlpath)) { springXmlpath = "classpath*:spring-*.xml"; } try { context = new ClassPathXmlApplicationContext(springXmlpath.split("[,\\s]+")); context.start(); } catch (BeansException e) { e.printStackTrace(); } } @After public 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"); } @Test public 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"); } @Test public void testSetter() { InjectionService service = super.getBean("injectionService"); service.save("这是要保存的数据"); } @Test public void testCons() { InjectionService service = super.getBean("injectionService"); service.save("这是要保存的数据"); } }
相关文章推荐
- 【Spring学习笔记】Spring框架的IoC容器学习笔记
- 【Spring学习笔记】Spring框架的IoC容器学习笔记
- Spring动态获取IoC容器中管理的Bean
- spring源码初步学习-自己实现的ioc容器结构
- Spring实现一个简单的SpringIOC容器
- Spring(一)Spring IOC容器配置详解——基于xml文件形式
- Spring源码解读5——IoC容器的高级特性
- 【Spring源码--IOC容器的实现】-- 综述
- Spring IOC容器启动流程源码解析(一)——容器概念详解及源码初探
- 【Spring.Framework】【IoC】Spring容器,Bean及Bean的实例化
- Spring ioc容器启动流程—obtainFreshBeanFactory
- Spring IoC/DI容器 的helloworld工程
- [置顶] Spring框架介绍和IoC容器中Bean配置(Spring框架)
- Spring容器实例Bean的三种方法(IOC三种方法)
- Spring源码阅读(三)—IOC容器依赖注入
- Spring-IOC容器之Bean的生命周期
- Spring框架IOC容器和AOP解析
- springioc容器学习第一天第二篇
- spring源码学习之路---IOC容器初始化要义之bean定义载入(五)
- (一)Spring核心-IoC容器的实现