Spring入门(接口、IOC、注入)

来源:互联网 发布:知乎网友 蒙歌 编辑:程序博客网 时间:2024/06/11 10:35

接口
用于沟通的中介物的抽象化
实体把自己提供给外界的一种抽象化说明,用以由内部操作分离出外部沟通方法,使其能被修改内部而不影响外界其他实体与其交互的方式(比如实现注册功能,只要提供相应信息即可,至于注册这个功能如何实现,逻辑是什么样,数据存储在哪是不对外公开的)
对应Java接口即声明,声明了哪些方法是对外公开提供的
在Java8中,接口可以拥有方法体

面向接口编程
结构设计中,分清层次及调用关系,每层只向外(上层)提供一组功能接口,各层次仅依赖接口而非实现类
接口实现的变动不影响各层间的调用,这一点在公共服务中尤为重要
“面向接口编程”中的“接口”是用于隐藏具体实现和实现多态性的组件

举例

package com.imooc.ioc.interfaces;public interface OneInterface {    public void say(String arg);}

这里声明一个接口,里边有一个方法,下面的是实现。

package com.imooc.ioc.interfaces;public class OneInterfaceImpl implements OneInterface {     public void say(String arg) {        System.out.println("ServiceImpl say: " + arg);    }}

对外提供的是接口,里边不包括任何实现,具体实现根据业务变化进行调整,下边是使用。

public class Main{    public static void main(String[] args){        OneInterface oif=new OneInterfaceImpl();        System.out.println(oif.hello("word."));    }}

用接口来进行声明,然后将接口的实现类赋值给对象的声明,然后进行调用。

什么是IOC
IOC:控制反转,控制权的转移,应用程序本身不负责依赖对象的创建和维护,而是由外部容器负责创建和维护
DI(依赖注入)是其一种实现方式
目的:创建对象并且组装对象之间的关系

如何理解?
IOC容器在初始化的时候会创建一系列对象,同时可以把对象之间的依赖关系通过注入的方式组织起来。也就是说当一个类A里边有另一个类B,在实例化的时候,要先实例化一个A的对象,再实例化一个B的对象,然后把B的对象赋值给A。也就是说IOC负责一个对象组装的功能。
我们在使用对象的时候直接去The Spring Container中拿就可以了,它就是前边说到的外部容器,应用程序更多的关心对象的使用,而不是创建。
IOC容器说明

IOC是控制反转,是哪些方面的控制被反转了?获得依赖对象的过程由自身管理变为由IOC容器主动注入,所以控制反转也被叫依赖注入。这实际上给出了实现IOC的方法:注入。所谓依赖注入,就是由IOC容器在运行期间,动态地将某种依赖关系注入到对象之中。

将IOC和房屋中介对比
对于房屋中介,我们是先找中介,然后由中介介绍房子,之后我们租房、入住。
对于IOC,我们先找IOC容器,然后容器返回对象,然后我们使用对象。

在Spring容器中,对象或者说是Bean是如何配置的(IOC容器中把所有对象都叫Bean)?
刚才已经定义了一个接口以及实现了那个接口,如果由Spring的Bean来管理要如何配置?Spring对于Bean或者整个Spring的使用有两种方法,一种是基于xml的配置,还有一种是注解。
以下是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="com.imooc.ioc.interfaces.OneInterfaceImpl"></bean> </beans>

id是唯一标识,class指定了属于哪个类。
使用的例子如下

package com.imooc.test.ioc.interfaces;import org.junit.Test;import org.junit.runner.RunWith;import org.junit.runners.BlockJUnit4ClassRunner;//import org.springframework.test.context.ContextConfiguration;//import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import com.imooc.ioc.interfaces.OneInterface;import com.imooc.test.base.UnitTestBase;@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.");    }}

这里用到了junit的单元测试。
单元测试
下载junit-*.jar并引入工程
创建UnitTestBase类,完成对Spring配置文件的加载、销毁
所有的单元测试类都继承自UnitTestBase,通过它的getBean方法获取想要得到的对象
子类(具体执行单元测试的类)加注解:@RunWith(BlockJUnit4ClassRunner.class)
单元测试方法加注解:@Test
右键选择要执行的单元测试方法执行或者执行一个类的全部单元测试方法

Bean容器初始化
基础:两个包
-org.springframework.beans
-BeanFactory提供配置结构和基本功能,加载并初始化Bean
-org.springframework.context
-ApplicationContext保存了Bean对象并在Spring中被广泛使用
初始化ApplicationContext的方式
-加载本地文件,即指定到具体磁盘目录上的文件
-Classpath,相对路径,将对于工程
-Web应用中依赖servlet或Listener
举例:
文件FileSystemXmlApplicationContext context=new FileSystemXmlApplicationContext ("F:/workspace/appcontext.xml");
ClasspathClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("classpath:spring-context.xml");
Web应用

<listener>    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener>    <servlet>        <servlet-name>context</servlet-name>        <servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>        <load-on-startup>1</load-on-startup>    </servlet>

Spring注入
Spring注入是指在启动Spring容器加载bean配置的时候,完成对变量的赋值行为
常用的两种注入方式。
如何理解?
在前边介绍IOC容器加载过程的时候,IOC容器在加载的时候,会扫描xml文件的bean的相关配置,然后为这些bean进行实例化。注入就是在创建的过程中完成对成员变量的赋值。比如在A类引用了一个B类,然后声明了一个B类的变量b,注入就是指在IOC容器初始化A的时候,就把A的成员变量b进行赋值。
1.设值注入
2.构造注入

设值注入:

<bean id="injectionService" class="com.imooc.ioc.injection.service.InjectionServiceImpl">     <property name="injectionDAO" ref="injectionDAO"/></bean>    <bean id="injectionDAO" 其实就是class="com.imooc.ioc.injection.dao.InjectionDAOImpl"></bean>

设值注入其实就是set通过一个属性或者一个成员变量的set方法来进行注入。上边代码中的两个bean id class,就是声明两个bean,在IOC容器初始化加载当前xml文件的时候去创建两个对象,并且id为injectionService和injectionDAO。
在service里边有个property(属性),也就是说在InjectionServiceImpl这个类里边会有一个InjectionDAO的成员变量,它是InjectionDAOImpl类型的,它有一个引用ref,应用到的就是下边的bean的那个id的injectionDAO,这个injectionDAO代表了InjectionDAOImpl的一个实例。然后将这个实例赋值给上边的id为injectionService的bean中的那个name为injectionDAO的那个属性。这种方式就是设值注入,也就是我们通过set方式去注入。
为了方便理解,可以这样想。在Java的面向对象的封装里面,通常会将成员变量声明为private类型,然后会定义这个成员变量的set和get方法,通过get方法取值,通过set方法赋值。设值注入就是自动调用类的set方法。也就是说在InjectionServiceImpl这个类里必须有setinjectionDAO这样一个方法。然后Spring的IOC容器会自动调用这个方法为这个属性进行赋值。

构造注入

<bean id="injectionService" class="com.imooc.ioc.injection.service.InjectionServiceImpl">     <constructor name="injectionDAO" ref="injectionDAO"/></bean>    <bean id="injectionDAO" class="com.imooc.ioc.injection.dao.InjectionDAOImpl"></bean>

构造注入和设值注入写法很像,只是内部有点区别,property变为了constructor-arg,即构造器的参数。那么我们必须在InjectionServiceImpl里有一个构造器,这个构造器的参数必须叫injectionDAO。
它代表的意思就是IOC容器在调用InjectionServiceImpl的构造方法去创建这个类的实例的时候,就会根据reference,把InjectionDAOImpl的实例赋值给InjectionServiceImpl的构造器中声明的injectionDAO这个属性,从而完成在创建InjectionServiceImpl的时候对injectionDAO,也就是InjectionServiceImpl的一个成员变量的赋值。

例子的代码实现如下:
先定义了InjectionService和InjectionDAO的接口,然后是它们的实现类。

public interface InjectionService {     public void save(String arg);   }
public interface InjectionDAO {     public void save(String arg);   }

正常Service用于处理业务逻辑,DAO负责数据库的访问。
这里的DAO不访问数据库,Service也不做业务操作,只是模拟

public class InjectionDAOImpl implements InjectionDAO {     public void save(String arg) {        //模拟数据库保存操作        System.out.println("保存数据:" + 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);    }}

设值注入就是通过set方法,这里给injectionDAO这个属性生成set方法,然后在Service的save方法里调用InjectionDAO的save方法,传入经过业务处理后的数据,即injectionDAO.save(arg);
配置的代码如下

<bean id="injectionService" class="com.imooc.ioc.injection.service.InjectionServiceImpl">    <property name="injectionDAO" ref="injectionDAO"></property></bean><bean id="injectionDAO" class="com.imooc.ioc.injection.dao.InjectionDAOImpl"></bean>

这个代码和之前出现的几乎一样,这里可以更好的理解,在InjectionServiceImpl这个类里边会有一个InjectionDAO的成员变量injectionDAO,name也就是它。

然后就是测试了

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

如何在单元测试中测试这个类前边已经说过了。
输出结果为:
Service接收参数这是要保存的数据
保存数据:这是要保存的数据:542156630
(第一行是Service的save方法,里边又调用了DAO的save方法,为第二行的输出)

这里要注意,虽然InjectionServiceImpl里有set方法,但是我们并没有手动调用这个方法。我们是通过xml文件的配置,即set文件注入方式完成的。

构造器注入只要做部分改变就好。
前边的InjectionServiceImpl中已经有这部分代码

//构造器注入    public InjectionServiceImpl(InjectionDAO injectionDAO1) {        this.injectionDAO = injectionDAO1;    }   

显示地去写一个构造器。并且注意要修改xml文件的内容

<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>

然后在测试类里边写一个测试方法

@Testpublic void testCons() {    InjectionService service = super.getBean("injectionService");    service.save("这是要保存的数据");}

输出的内容和之前一样。

以上是看慕课网视频之后自己将内容理出来便于今后学习。

阅读全文
0 0
原创粉丝点击