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

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的源码:

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("这是要保存的数据");
}

}





                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息