• spring的IOC,DI及案例详解


    spring的IOC,DI及案例详解

    一:spring的基本特征

     

    Spring是一个非常活跃的开源框架;它是一个基于Core来架构多层JavaEE系统的框架,它的主要目的是简化企业开发。Spring以一种非侵入式的方式来管理你的代码,Spring提倡“最少侵入,这也意味着你可以适当的时候安装或卸载Spring。


     二:开发Spring所需要的工具

      1.Spring的jar包

    到http://www.springsource.org/download下载spring,然后进行解压缩,在解压目录中找到下面jar文件,拷贝到类路径下 

    --spring的核心类库 在spring文档的dist下: distspring.jar
    --引入的第三方类库 都spring文档的lib下:libjakarta-commonscommons-logging.jar
    以上两个jar包,是开发spring最基本的jar包。


    如果使用了切面编程(AOP),还需要下列jar文件 lib/aspectj/aspectjweaver.jar和aspectjrt.jar lib/cglib/cglib-nodep-2.1_3.jar

    如果使用了JSR-250中的注解,如@Resource/@PostConstruct/@PreDestroy,还需要下列jar文件 libj2eecommon-annotations.jar 注:JSR(Java 规范请求)是指向JCP(Java Community Process)提出新增一个标准化技术规范的正式请求。任何人都可以提交JSR(Java 规范请求),以向Java平台增添新的API和服务。JSR已成为Java界的一个重要标准。

    2.Spring的配置文件

     默认情况下是applicationContext.xml文件。可以建很多XML文件,工程中一般都是这样配置的。


     三:Spring基本功能及案例详解

    1.Spring的IOC

    Spring内IOC的最直接体现就是@Autowired注解

    而IOC的精髓就是解耦类中没有显式的对属性的赋值代码,同时属性的实际类型和值在运行时有系统动态的赋值,Spring对IOC做了很大的扩展,使用者可以很灵活的控制注入的对象类型及值

    SpringIOC(控制反转):把对象的创建,初始化,销毁等工作交给Spring容器来做。由Spring容器控制对象的生命周期。 

    步骤:A:启动Spring容器;B:从Spring容器中把对象取出来;C:最后,对象调用实际的业务方法。 

    A:启动Spring容器:

    在类路径下寻找配置文件来实例化容器:ApplicationContext context = new ClassPathXmlApplicationContext("配置文件类路径");

    通过这种方式加载。需要将spring配置文件放到当前项目的classpath路径下。classpath路径指的是当前项目的src目录,该目录是java源文件的存放位置。

    在文件系统路径下寻找配置文件来实例化容器:ApplicationContext context = new FileSystemXmlApplicationContext("配置文件系统路径"); 

    注:经常采用第一种方式启动Spring容器。

    B:从Spring容器中把对象取出来:

    context.getBean("配置文件中bean的id"); 如:HelloWorld helloWorld = (HelloWorld)context.getBean("helloWorld");

    C:对象调用实际的业务方法:

    helloWorld.hello(); 


    1.1.Spring容器创建对象的方式 

    A:默认的情况下是调用该类默认的无参构造函数来创建类的对象。

    案例:

    Spring的主配置文件:applicationContext.xml(因为我这里将会讲到很多模块,所以我用一个主配置文件去加载各个模块的配置文件):

     

      具体业务模块配置文件applicationContext-creatobject.xml

    业务类HelloWorld.java

     

    客户端代码:

     

      由此看出:如果业务类HElloWorld.java又写了该类的有参构造函数,此时就覆盖了默认的无参构造函数。这样就导致Spring容器在创建该类的对象时失败。因为默认的是调用该类的默认无参构造函数,而此时又找不到无参构造函数了,所以就创建对象失败。

    B:Spring容器利用静态工厂方法创建类对象。 

      案例:

    Spring的主配置文件:applicationContext.xml(因为我这里将会讲到很多模块,所以我用一个主配置文件去加载各个模块的配置文件):

    具体业务模块配置文件applicationContext-creatobject-method.xml

     

    业务类HelloWorld.java

     

    静态工厂类方法:

     

    客户端代码:

     

    C:Spring容器利用实例工厂方法创建对象

    再次不做案例分析,记住即可。 

    最后说明一下:spring配置文件中,只要是一个bean就会为该bean创建对象(默认是调用该类的默认构造函数创建对象)


    1.2.Spring配置文件中别名的用

    案例:

    Spring的主配置文件:applicationContext.xml(因为我这里将会讲到很多模块,所以我用一个主配置文件去加载各个模块的配置文件):

     

    具体业务模块配置文件applicationContext-alias.xml

     

    业务类HelloWorld.java

     

    客户端代码:

     

    由此看出:通过配置文件中的配置,可以达到在一个地方命名,在多个地方使用不同的名字的效果。


    1.3.Spring容器创建对象的时机

    案例:

    Spring的主配置文件:applicationContext.xml(因为我这里将会讲到很多模块,所以我用一个主配置文件去加载各个模块的配置文件):

     

    具体业务模块配置文件applicationContext-creatobject-when.xml

    业务类HelloWorld.java

     

    客户端代码:

    执行结果:

    由执行结果可看出:在单例情况下(默认就是单例,关于单例,下面会讲到):

    A:在默认情况下,启动spring容器的时候(ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml)),就调用该类的无参构造函数创建对象。所以spring容器创建对象的时机是:启动spring容器时创建。 

    B:在spring的配置文件bean中有一个属性lazy-init="default/false/true":

    a:如果lazy-init="default/false",在启动spring容器的时候创建对象。

    b:如果lazy-init="true",在获取对象的时候创建对象,即context.getBean()时,创建对象。

    a与b的意义:

    在第一种情况下可以在启动spring容器的时候,检查spring配置文件的正确性。如果再结合tomcat,如果spring容器不能正常启动整个tomcat就不能正常启动。但是这样的缺点是把一些bean过早的放在了内存中,如果有数据,则对内存来说是一个消耗。在第二种情况下,可以减少内存的消耗,但是不容易检查出配置文件中的错误,排错比较困难。 


    1.4.Spring容器中bean的单例与多例

    案例:

    Spring的主配置文件:applicationContext.xml(因为我这里将会讲到很多模块,所以我用一个主配置文件去加载各个模块的配置文件):

     

    具体业务模块配置文件applicationContext-creatobject-scope.xml

     

    业务类HelloWorld.java

     

    客户端代码:

    执行结果:

    在配置文件的bean中的scope="singleton"的情况下(即默认情况下):

    在配置文件的bean中的scope="prototype"的情况下:

    从执行的结果,我们来总结归纳一下:

    从第一个执行结果看出,由spring容器产生的bean默认是单例的。打印结果看出,两次分别获取的bean结果是一样的。并且单例模式下,spring容器在启动的时候创建对象。

    从第二个执行结果看出,若果将配置文件中的bean的scope值修改为“prototype”,那么由spring容器产生的bean就是多例的。打印结果看出,两次分别获取的bean结果是不一样的。并且在多例模式下,spring容器在context.getBean(),即获取对象的时候创建对象。这里有两次获取bean,所以打印出两个:new instance-----scope

    综上:可以在spring的配置文件 ,scope的值进行修改="singleton/prototype/request/session/global session/global" ,如果spring的配置文件的scope为“prototype”,则在得到或者说从spring容器获取该bean的时候才创建对象。 


    1.5.Spring容器中对象的生命周期

    案例

    Spring的主配置文件:applicationContext.xml(因为我这里将会讲到很多模块,所以我用一个主配置文件去加载各个模块的配置文件):

     

    具体业务模块配置文件applicationContext-initdestory.xml

    业务类HelloWorld.java

    客户端代码:

    执行结果:

    由执行结果的顺序可以看出:在单例情况下,即默认scope="singleton"的时候

    a:spring容器在启动的时候创建对象;

    b:spring容器执行init方法;

    c:程序员调用自己的业务方法;

    d:当spring容器关闭的时候执行destory方法。

    spring容器:ApplicationContext applicationContext = new ClassPathXmlApplicationContext("");

    它的关闭:需要将applicationContext转化一下:

    ClassPathXmlApplication cpxa = (ClassPathXmlApplicationContext) applicationContext; 

    cpxa.close(); 这样才能关闭spring容器,执行destory方法。

    注意:当scope=“prototype”的时候(即多例的情况下),spring容器不会执行destory()方法。 




    2.Spring的DI(依赖注入)

    springDI:理解为依赖注入,俗称给属性赋值。

    平常中,我们给类的属性赋值,无非两种方式:1.调用类的set,get方法;2.调用类的构造方法。比如下面一个类中的属性类型,几乎代表了所有类型:

    public class Person{  

    private Long pid;

    private String pname;

    private Student student;

    private List lists;

    private Set sets;

    private Map map;

    private Properties properties;

    //set,get方法 

    }

    说明:一个类中的所有属性都可以采用SpringDI的方式赋值,但并不是所有的属性都适合赋值。

    2.1.调用类的set,get方法

    案例:

    Spring的主配置文件:applicationContext.xml(因为我这里将会讲到很多模块,所以我用一个主配置文件去加载各个模块的配置文件):

    具体业务模块配置文件applicationContext-di-set.xml

    业务类Person.java

    业务类Student.java

    客户端代码:

    执行结果:

    总结:从业务中的标注看,

    1.我这里使用了自己编写的工具类SpringInit.java,是为了方便2的使用;

    工具类的代码如下:

    public class SpringInit{

    public static ApplicationContext context;//spring容器 

    //静态代码块,在类加载的之后执行,只执行一次

    static{

    context = new ClassPathXmlApplicationContext("applicationContext.xml");//启动spring容器

     }

    然后我的客户端类继承了这个工具类。

    结合配置文件和执行结果,看出是通过set方法赋值的。首先创建对象解析所有的property,把name解析出来,拼接成set方法,把value和ref解析出来并赋值。 


    2.2.调用类的构造方法

    案例:

    Spring的主配置文件:applicationContext.xml(因为我这里将会讲到很多模块,所以我用一个主配置文件去加载各个模块的配置文件):

     

    具体业务模块配置文件applicationContext-di-constructor.xml

    业务类同1.1中的业务类相同,只是Person类中添加一个构造方法:

    public Person(String pname,Student){

    this.pname = pname;

    this.student = student;

    }

    客户端代码:

    执行结果:

    总结:构造函数的方式赋值:

    1.如果spring的配置文件中的bean中没有<constructor-arg>元素,则spring容器调用默认的构造函数创建对象。
    2.如果spring的配置文件中的bean中有<constructor-arg>元素,则该元素确定唯一的构造函数创建对象并赋值。
    <constructor-arg>中的元素:index:代表参数的位置 从0开始计算。
    type:值的是参数的类型。
    value:给基本类型赋值。
    ref:给引用类型赋值。

    2.3.spring的IOC与DI的意义

    案例:

    Spring的主配置文件:applicationContext.xml(因为我这里将会讲到很多模块,所以我用一个主配置文件去加载各个模块的配置文件):

    具体业务模块配置文件applicationContext-document.xml

    业务类:

    ducument接口:

    三个实现接口的类:

    ------------------------------------------------------------------------------------------------------------------------------

    ---------------------------------------------------------------------------------------------------------------------------------

    文档管理类DocumentManager.java

    客户端代码:

     

    执行结果:

    从例子可以看出,Spring的IOC与DI的完美结合,是其做到了真正的面向接口编程。如果我们想读写Excel或者Word,只需要修改配置文件中的传入参数即可。而传统的方式是不完全面向接口的编程,把实现类暴露给客户端了。


    2.3.spring的IOC与DI实现mvc的模拟例子

    案例:  

    Spring的主配置文件:applicationContext.xml(因为我这里将会讲到很多模块,所以我用一个主配置文件去加载各个模块的配置文件):

     

    具体业务模块配置文件applicationContext-mvc.xml

    业务类:

    服务层接口与实现:

    -----------------------------------------------------------------------------------------------

    dao层接口与实现:

    ------------------------------------------------------------------------------------------

    控制层action

    客户端代码:

    执行结果:

    从例子可以看出,Spring的IOC与DI的完美结合,是其做到了真正的面向接口编程。这里的依赖注入都采用了set的方式注入的。

    参考http://www.cnblogs.com/vanl/p/5607534.html

  • 相关阅读:
    Android学习笔记----天地图API开发之UnsatisfiedLinkError
    Android学习笔记----ArcGIS在线地图服务(Android API)坐标纠偏
    Android学习笔记----Java字符串MD5加密
    Android学习笔记----Java中的字符串比较
    MySQL数据库导入错误:ERROR 1064 (42000) 和 ERROR at line xx: Unknown command ''.
    新浪微博POI点签到数据及可视化的初步成果
    Chrome调试本地文件无法使用window.opener对象进行窗口间值传递
    132、Android安全机制(2) Android Permission权限控制机制(转载)
    用addOnGlobalLayoutListener获取View的宽高
    Android Studio解决unspecified on project app resolves to an APK archive which is not supported
  • 原文地址:https://www.cnblogs.com/leeego-123/p/10824033.html
Copyright © 2020-2023  润新知