zoukankan      html  css  js  c++  java
  • 14 Spring的核心机制及容器

    1 .依籁注入

    art59C2工厂模式

    创建一个Java Project,命名为FactoryExample。在src文件夹下建立包“face”,在该包下建立接口

    “Human.java”,代码如下:

    package face;

    public interface Human {

    void eat();

    void walk();

    Chinese.java代码如下:

    package iface;

    import face.Human;

    public class Chinese implements Human{

    public void eat() {

    System.out.println("中国人很会吃!");

    }

    public void walk() {

    System.out.println("中国人健步如飞!");

    }

    }

    American.java代码如下:

    package iface;

    import face.Human;

    public class American implements Human{

    public void eat() {

    System.out.println("美国人吃西餐!");

    }

    public void walk() {

    System.out.println("美国人经常坐车!");

    }

    }

    在src下建包“factory”,在该包内建立工厂类Factory.java,代码如下:

    package factory;

    import iface.American;

    import iface.Chinese;

    import face.Human;

    public class Factory {

    public Human getHuman(String name){

    if(name.equals("Chinese")){

    return new Chinese();

    }else if(name.equals("American")){

    return new American();

    }else{

    throw new IllegalArgumentException("参数不正确");

    }

    }

    }

    在src下建包test,在该包内建立Test测试类,代码如下:

    package test;

    import face.Human;

    import factory.Factory;

    public class Test {

    public static void main(String[] args) {

    Human human=null;

    human=new Factory().getHuman("Chinese");

    human.eat();

    human.walk();

    human=new Factory().getHuman("American");

    human.eat();

    human.walk();

    }

    }

    程序为Java应用程序,直接运行可看出结果,如图7.2所示

    image

          2. 依赖注入的应用

    1. 为项目添加Spring开发能力

    右击项目名,依次选择【MyEclipse】→【Add Spring Capabilities…】,将出现如图7.3所示的对话框,选中要应用的Spring版本及所需的类库文件。注意,本书用的Spring版本为Spring 3.0。

    image

    选择结束后,单击【Next】按钮,出现如图7.4所示的界面,用于创建Spring的配置文件

    image

    2. 修改配置文件applicationContext.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"

    xmlns:p="http://www.springframework.org/schema/p"

    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <bean id="chinese" class="iface.Chinese"></bean>

    <bean id="american" class="iface.American"></bean>

    </beans>

    3. 修改测试类

    配置完成后,就可以修改Test类的代码如下(注意重新导入一下spring.jar)

    package test;

    import org.springframework.context.ApplicationContext;

    import org.springframework.context.support.FileSystemXmlApplicationContext;

    import face.Human;

    public class Test {

    public static void main(String[] args) {

    ApplicationContext ctx=

    new FileSystemXmlApplicationContext("src/applicationContext.xml");

    Human human = null;

    human = (Human) ctx.getBean("chinese");

    human.eat();

    human.walk();

    human = (Human) ctx.getBean("american");

    human.eat();

    human.walk();

    }

    }

    image

    注入的两种方式

    1.设置注入(factoryExample1)

    人类的接口Human.java,代码如下:

    public interface Human {

    void speak();

    }

    语言接口Language.java,代码如下:

    public interface Language {

    public String kind();

    }

    下面是Human实现类Chinese.java代码:

    public class Chinese implements Human{

    private Language lan;

    public void speak() {

    System.out.println(lan.kind());

    }

    public void setLan(Language lan) {

    this.lan = lan;

    }

    }

    下面是Language实现类English.java代码:

    public class English implements Language{

    public String kind() {

    return "中国人也会说英语!";

    }

    }

    下面通过Spring的配置文件来完成其对象的注入。看其代码:

    <?xml version="1.0" encoding="UTF-8"?>

    <beans

    xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:p="http://www.springframework.org/schema/p"

    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <!-- 定义第一个Bean,注入Chinese类对象 -->

    <bean id="chinese" class="Chinese">

    <!-- property元素用来注定需要容器注入的属性,lan属性需要容器注入

    ref就指向lan注入的id -->

    <property name="lan" ref="english"></property>

    </bean>

    <!-- 注入english -->

    <bean id="english" class="English"></bean>

    </beans>

    每个Bean的id属性是该Bean的唯一标识,程序通过id属性访问Bean。而且Bean与Bean的依赖关系也通过id属性关联。

    测试代码如下:

    import org.springframework.context.ApplicationContext;

    import org.springframework.context.support.FileSystemXmlApplicationContext;

    public class Test {

    public static void main(String[] args) {

    ApplicationContext ctx = new FileSystemXmlApplicationContext("src/applicationContext.xml");

    Human human = null;

    human = (Human) ctx.getBean("chinese");

    human.speak();

    }

    }

    image

    2. 构造注入

    例如,只要对前面的代码Chinese类进行简单的修改:

    public class Chinese implements Human{

    private Language lan;

    public Chinese(){};

    // 构造注入所需要的带参数的构造函数

    public Chinese(Language lan){

    this.lan=lan;

    }

    public void speak() {

    System.out.println(lan.kind());

    }

    }

    配置文件也需要作简单的修改:

    <?xml version="1.0" encoding="UTF-8"?>

    <beans

    ……

    <!-- 定义第一个Bean,注入Chinese类对象 -->

    <bean id="chinese" class="Chinese">

    <!-- 使用构造注入,为Chinese实例注入Language实例 -->

    <constructor-arg ref="english"></constructor-arg>

    </bean>

    <!-- 注入english -->

    <bean id="english" class="English"></bean>

    </beans>

    其中,“constructor-arg”用来表示通过构造方式来进行依赖注入,“index="0"”表示构造方法中的第一个参数,如果只有一个参数,可以省略不写,如果有多个参数,就直接重复配置“constructor-arg”即可,不过要改变“index”的值,例如,如果在“HelloWorld”类中还有一个参数“mess”,并且通过构造方法为其注入值:

    public HelloWorld(String message,String mess){

    this.message=message;

    this.mess=mess;

    }

    那么,只需在配置文件config.xml中加上一个“constructor-arg”:

    <constructor-arg index="1">

    <value>HelloYabber</value>

    </constructor-

    在开发过程中,set注入和构造注入都是会经常用到的,这两种依赖注入的方式并没有绝对的好坏,只是使用的场合有所不同而已。使用构造注入可以在构建对象的同时一并完成依赖关系的建立,所以,如果要建立的对象的关系很多,使用构造注入就会在构造方法上留下很多的参数,是非常不易阅读的,这时建议使用set注入。然而,用set注入由于提供了setXx()方法,所以不能保证相关的数据在执行时不被更改设定,因此,如果想要让一些数据变为只读或私有,使用构造注入会是个很好的选择。

    2. spring 容器

            Spring 是作为一容器存在的,应用中的所有组件都处于spirng的管理之下,都被spring 以bean方式管理.spring 负债创建bean的实例,并管理其生命周期.spring有两个核心接口:

            BeanFactory和ApplicationContext,其中applicationContext是beanFactory的子接口.它们都可代表Spring容器.spring容器是生成Bean的工厂,所有的组件都被当前bean处理,如数据

           源、hibernate的sessionfactory、事务管理器等。bean是spring容器的基本单位,所以先讲基本知识及相关应用。

    14.2.1 Bean的定义

    Bean是描述Java的软件组件模型,其定义在Spring配置文件的根元素<beans>下,<bean>元素是<beans>元素的子元素,在根元素<beans>下可以包含多个<bean>子元素。每个<bean>可以完成一个简单的功能,也可以完成一个复杂的功能,<bean>之间可以互相协同工作,完成复杂的关系。

    在HelloWorld实例中,config.xml中的Bean的配置如下:

    <bean id="HelloWorld" class="org.model.HelloWorld">

    <property name="message" >

    <value>Hello Yabber!</value>

    </property>

    </bean>

    在Bean中有一个id属性及class属性,这个id唯一标识了该Bean。在配置文件中,不能有重复的Bean的id,因为在代码中通过BeanFactory或ApplicationContext来获取Bean的实例时,都要用它来作为唯一索引:

    HelloWorld helloWorld=(HelloWorld) ac.getBean("HelloWorld");

    14.2.2Bean的基本属性

    1.Bean的id属性

    为Bean指定别名可以用name属性来完成,如果需要为Bean指定多个别名,可以在name属性中使用逗号(,)、分号(;)或空格来分隔多个别名,在程序中可以通过任意一个别名访问该Bean实例。例如,id为“HelloWorld”的Bean,其别名为:

    <bean id="HelloWorld" name="a;b;c" class="org.model.HelloWorld">

    <property name="message" >

    <value>Hello Yabber!</value>

    </property>

    </bean>

    则在程序中可以利用“a”、“b”、“c”任意一个来获取Bean的实例:

    HelloWorld helloWorld=(HelloWorld) ac.getBean("a");或

    HelloWorld helloWorld=(HelloWorld) ac.getBean("b");或

    HelloWorld helloWorld=(HelloWorld) ac.getBean("c");

    以上三种方法均可完成Bean实例的获取

    2.Bean的class属性

    可以看出,每个Bean都会指定class属性,class属性指明了Bean的来源,即Bean的实际路径,注意,这里要写出完整的包名+类名。例如:

    <bean id="HelloWorld" name="a;b;c" class="org.model.HelloWorld">

    class属性非常简单,这里就不过多介绍了。

    3.Bean的scope属性

    scope属性用于指定Bean的作用域,Spring支持5种作用域,这5种作用域如下:

    singleton:单例模式,当定义该模式时,在容器分配Bean的时候,它总是返回同一个实例。该模式是默认的,即不定义scope时的模式。

    prototype:原型模式,即每次通过容器的getBean方法获取Bean的实例时,都将产生信息的Bean实例

    request:对于每次HTTP请求中,使用request定义的Bean都将产生一个新实例,即每次HTTP请求将会产生不同的Bean实例。只有在Web应用中使用Spring时,该作用域有效。

    session:对于每次HTTP Session请求中,使用session定义的Bean都将产生一个新实例,即每次HTTP Session请求将会产生不同的Bean实例。只有在Web应用中使用Spring时,该作用域有效。

    global session:每个全局的Http Session对应一个Bean实例。典型情况下,仅在使用portlet context的时候有效。只有在Web应用中使用Spring时,该作用域才有效。

    比较常用的是前两种作用域,即singleton及prototype。下面举例说明这两种作用域的差别。

    仍然是对HelloWorld程序进行修改,在配置文件config.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-2.5.xsd">

    <bean id="HelloWorld1" class="org.model.HelloWorld"></bean>

    <bean id="HelloWorld2" class="org.model.HelloWorld" scope="prototype"></bean>

    </beans>

    在“HelloWorld1”Bean中没有定义“scope”属性,即默认的“singleton”单例模式。“HelloWorld2”Bean中指定作用域为“prototype”,即原型模式。

    HelloWorld.java类不变,编写测试类代码

    <?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-2.5.xsd">
        <bean id="HelloWorld1" class="org.model.HelloWorld"></bean>
        <bean id="HelloWorld2" class="org.model.HelloWorld" scope="prototype"></bean>
    </beans>

    编写测试类代码:

    package org.test;
    import org.model.HelloWorld;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.FileSystemXmlApplicationContext;
    public class BeanTest {
        public static void main(String[] args) {
            ApplicationContext ac=new FileSystemXmlApplicationContext("/WebRoot/WEB-INF/classes/config.xml");
            HelloWorld helloWorld1=(HelloWorld) ac.getBean("HelloWorld1");
            HelloWorld helloWorld2=(HelloWorld) ac.getBean("HelloWorld1");
            HelloWorld helloWorld3=(HelloWorld) ac.getBean("HelloWorld2");
            HelloWorld helloWorld4=(HelloWorld) ac.getBean("HelloWorld2");
            System.out.println(helloWorld1==helloWorld2);
            System.out.println(helloWorld3==helloWorld4);
        }
    }

    log4j:WARN No appenders could be found for logger (org.springframework.context.support.FileSystemXmlApplicationContext).
    log4j:WARN Please initialize the log4j system properly.
    true
    false


    4.Bean的propetry

    4.Bean的property

    在Spring的依赖注入中,是应用Bean的子元素<property>来为属性进行设值的:

    <bean id="HelloWorld" class="org.model.HelloWorld">

    <property name="message" >

    <value>Hello World!</value>

    </property>

    </bean>

    如果要为属性设置“null”,有两种方法。第一种直接用value元素指定:

    <bean id="HelloWorld" class="org.model.HelloWorld">

    <property name="message" >

    <value>null</value>

    </property>

    </bean>

    第二种方法直接用<null/>:

    <bean id="HelloWorld" class="org.model.HelloWorld">

    <property name="message" >

    <null/>

    </property>

    </bean

               3.Bean的生命周期

    1.Bean的定义

    Bean的定义在前面的实例中已经应用很多了,从基本的HelloWorld程序中就可以基本看出Bean的定义,这里就不再列举其定义形式,但值得一提的是,在一个大的应用中,会有很多的Bean需要在配置文件中定义,这样配置文件就会很大,变得不易阅读及维护,这时可以把相关的Bean放置在一个配置文件中,创建多个配置文件

    2.Bean的初始化

    在Spring中,Bean完成全部属性的设置后,Spring 中的bean的初始化回调有两种方法,一种是在配置文件中声明“init-method="init"”,然后在HelloWorld类中写一个init()方法来初始化;另一种是实现InitializingBean 接口,然后覆盖其afterPropertiesSet()方法。知道了初始化过程中会应用这两种方法,就可以在Bean的初始化过程中让其执行特定行为。

    下面介绍这两种方法的使用方式。第一种方式如下:

    (1)在HelloWorld类中增加一个init()方法。代码如下:

    package org.model;

    public class HelloWorld {

    private String message;

    public String getMessage() {

    return message;

    }

    public void setMessage(String message) {

    this.message = message;

    }

    public void init(){

    //利用该方法修改message的值

    this.setMessage("Hello Yabber");

    }

    }

    (2修改配置文件config.xml,指定Bean中要初始化的方法为init(),代码如下:

    <?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-2.5.xsd">

    <bean id="HelloWorld" class="org.model.HelloWorld" init-method="init">

    <property name="message">

    <value>HelloWorld</value>

    </property>

    </bean>

    </beans>

    (3)编写测试类,输出HelloWorld中message的值,代码如下:

    package org.test;

    import org.model.HelloWorld;

    import org.springframework.context.ApplicationContext;

    import org.springframework.context.support.FileSystemXmlApplicationContext;

    public class Test {

    public static void main(String[] args) {

    ApplicationContext ac=

    new FileSystemXmlApplicationContext("/WebRoot/WEB-INF/classes/config.xml");

    HelloWorld helloWorld=(HelloWorld) ac.getBean("HelloWorld");

    System.out.println(helloWorld.getMessage());

    }

    }

    运行该程序,控制台输出如图14.2所示。

    可以发现,初始化方法的调用是在Bean初始化的后期执行的,改变了message的赋值,故输出为“Hello Yabber”。

    image

    第二种方式,实现InitializingBean接口,并覆盖其“afterPropertiesSet()”方法。

    (1)修改HelloWorld.java,让其实现InitializingBean接口,并覆盖其“afterPropertiesSet()”方法。代码实现为:

    package org.model;

    import org.springframework.beans.factory.InitializingBean;

    public class HelloWorld implements InitializingBean{

    private String message;

    public String getMessage() {

    return message;

    }

    public void setMessage(String message) {

    this.message = message;

    }

    public void afterPropertiesSet() throws Exception {

    this.setMessage("Hello Yabber");

    }

    }

    (2)修改config.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-2.5.xsd">

    <bean id="HelloWorld" class="org.model.HelloWorld">

    <property name="message">

    <value>HelloWorld</value>

    </property>

    </bean>

    </beans>

    运行结果相同都会输出“hello world”

    3.Bean的应用

    Bean的应用非常简单,在Spring中有两种使用Bean的方式。

    第一种,使用BeanFactory:

    //在ClassPath下寻找,由于配置文件就是放在ClassPath下,故可以直接找到

    ClassPathResource res=new ClassPathResource("config.xml");

    XmlBeanFactory factory=new XmlBeanFactory(res);

    HelloWorld helloWorld=(HelloWorld)factory.getBean("HelloWorld");

    System.out.println(helloWorld.getMessage());

    第二种,使用ApplicationContext:

    ApplicationContext ac=

    new FileSystemXmlApplicationContext("/WebRoot/WEB-INF/classes/config.xml");

    HelloWorld helloWorld=(HelloWorld) ac.getBean("HelloWorld");

    System.out.println(helloWorld.getMessage());

    首先介绍第一种方式。

    (1)在HelloWorld类中增加一个cleanup()方法。代码如下:

    package org.model;

    public class HelloWorldDestroy{

    private String message;

    public String getMessage() {

    return message;

    }

    public void setMessage(String message) {

    this.message = message;

    }

    public void cleanup(){

    this.setMessage("HelloWorld!");

    System.out.println("销毁之前要调用!");

    }

    }

    (2)修改config.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-2.5.xsd">

    <bean id="HelloWorld" class="org.model.HelloWorldDestroy" destroy-method="cleanup">

    <property name="message">

    <value>HelloWorld</value>

    </property>

    </bean>

    </beans>

    (3)编写测试类,输出message的值,代码如下:

    package org.test;

    import org.model.HelloWorldDestroy;

    import org.springframework.context.support.AbstractApplicationContext;

    import org.springframework.context.support.FileSystemXmlApplicationContext;

    public class Test {

    public static void main(String[] args) {

    AbstractApplicationContext ac=

    new FileSystemXmlApplicationContext("/WebRoot/WEB-INF/classes/config.xml");

    HelloWorldDestroy helloWorld=(HelloWorldDestroy) ac.getBean("HelloWorld");

    System.out.println(helloWorld.getMessage());

    //为Spring容器注册关闭钩子,程序将会在推出JVM之前关闭Spring容器

    ac.registerShutdownHook();

    }

    }

    image

    第二种方式,实现DisposableBean接口,并覆盖其destroy()方法。

    (1)修改HelloWorldDestroy.java,让其实现DisposableBean接口,并覆盖其“destroy ()”方法。代码实现为:

    package org.model;

    import org.springframework.beans.factory.DisposableBean;

    public class HelloWorldDestroy implements DisposableBean{

    private String message;

    public String getMessage() {

    return message;

    }

    public void setMessage(String message) {

    this.message = message;

    }

    public void destroy() throws Exception {

    System.out.println("该句在销毁之前要显示!");

    }

    }

    (2)配置文件config.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-2.5.xsd">

    <bean id="HelloWorld" class="org.model.HelloWorldDestroy">

    <property name="message">

    <value>HelloWorld</value>

    </property>

    </bean>

    </beans>结果同第一种结果

          4.Bean的管理

                Spring对Bean的管理有两种方式,分别使用BeanFactory管理Bean和使用ApplicationContext管理Bean

    1.BeanFactory

    在Spring中有几种BeanFactory的实现,其中最常用的是org.springframework.bean. factory.xml.XmlBeanFactory。它根据XML文件中的定义装载Bean。

    要创建XmlBeanFactory,需要传递一个ClassPathResource对象给构造方法。例如,下面的代码片段获取一个BeanFactory对象:

    //在ClassPath下寻找,由于配置文件就是放在ClassPath下,故可以直接找到

    ClassPathResource res=new ClassPathResource("config.xml");

    BeanFactory factory=new XmlBeanFactory(res);

    为了从BeanFactory得到Bean,只要简单地调用getBean()方法,把需要的Bean的名字当做参数传递进去就行了。由于得到的是Object类型,所以要进行强制类型转化:

    HelloWorld helloWorld=(HelloWorld)factory.getBean("HelloWorld");

    2.ApplicationContext

    BeanFactory对简单应用来说已经很好了,但是为了获得Spring框架的强大功能,需要使用Spring更加高级的容器ApplicationContext(应用上下文)。表面上看,ApplicationContext和BeanFactory差不多,两者都是载入Bean的定义信息,装配Bean,根据需要分发Bean,但是ApplicationContext提供了更多的功能:

    应用上下文提供了文本信息解析工具,包括对国际化的支持。

    应用上下文提供了载入文本资源的通用方法,如载入图片。

    应用上下文可以向注册为监听器的Bean发送事件。

    在ApplicationContext的诸多实现中,有三个常用的实现:

    ClassPathXmlApplicationContext:从类路径中的XML文件载入上下文定义信息,把上下文定义文件当成类路径资源。

    FileSystemXmlApplicationContext:从文件系统中的XML文件载入上下文定义信息。

    XmlWebApplicationContext:从Web系统中的XML文件载入上下文定义信息。

    例如:

    ApplicationContext context=new FileSystemXmlApplicationContext ("c:/server.xml");

    ApplicationContext context=new ClassPathApplicationContext ("server.xml ");

    ApplicationContext context= WebApplicationContextUtils.getWebApplicationContext (request.getSession().getServletContext ());

    FileSystemXmlApplicationContext和ClassPathXmlApplicationContext的区别是:FileSystemXmlApplicationContext只能在指定的路径中寻找server.xml 文件,而ClassPathXml ApplicationContext可以在整个类路径中寻找foo.xml

          5.Bean的依依赖关系

    Bean的依赖关系是指当为一个Bean的属性赋值时要应用到另外的Bean,这种情况也称Bean的引用。

    例如,有这样的一个类DateClass.java:

    package org.model;

    import java.util.Date;

    public class DateClass {

    private Date date;

    public Date getDate() {

    return date;

    }

    public void setDate(Date date) {

    this.date = date;

    }

    }

    在配置文件中为其注入“date”值时,引用了其他Bean,代码为:

    <?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-2.5.xsd">

    <bean id="getDate" class="org.model.DateClass">

    <property name="date">

    <ref local="d"/>

    </property>

    </bean>

    <bean id="d" class="java.util.Date"></bean>

    </beans>

    编辑测试程序Test.java:

    package org.test;

    import org.model.DateClass;

    import org.springframework.context.ApplicationContext;

    import org.springframework.context.support.FileSystemXmlApplicationContext;

    public class Test {

    public static void main(String[]args){

    ApplicationContext ac=

    new FileSystemXmlApplicationContext("/WebRoot/WEB-INF/classes/config.xml");

    DateClass dc=(DateClass)ac.getBean("getDate");

    System.out.println(dc.getDate());

    }

    }

    运行程序,控制台输出如图14.4所示。

    控制台打印出了本机的当前时间,在“getDate”的Bean中引用了“d”Bean,也就为DateClass类中的属性“date”赋值为“d”Bean,即该Bean的对象,故打印出了当前时间。

    image

    从上例可以看出,Spring中是用“ref”来指定依赖关系的,用“ref”指定依赖关系有3中方法:local、bean和parent。前面的例子中应用了“local”方法指定,其实也可以应用其他两种方法,例如上例的配置文件若应用“bean”可以修改为:

    还可以直接应用property中的ref属性,例如上例可以修改为:

    <?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-2.5.xsd">

    <bean id="getDate" class="org.model.DateClass">

    <property name="date" ref="d"></property>

    </bean>

    <bean id="d" class="java.util.Date"></bean>

    </beans>

    补充:韩 项目myspring1或自:hsp_spring_1

    image

    image

            6 Bean的自动装配

             通过自动装配,开发人员可以减少属性的操作

              bean元素的自动装配是通过autowire属性来指定的,共有5种取值,也就是自动装配的5种模式,即byname,bytype,costurctor,autodetect和no

    1.byName模式

    使用byName模式在Bean的初始化时会通过Bean的属性名字进行自动装配,在Spring的配置文件中,查找一个与将要装配的属性同样名字的Bean。

    例如,DateClass.java为:

    package org.model;

    import java.util.Date;

    public class DateClass {

    private Date date;

    public Date getDate() {

    return date;

    }

    public void setDate(Date date) {

    this.date = date;

    }

    }

    配置文件config.xml中可以用“byName”自动装配模式来为属性“date”自动装配值,配置文件可以配置为:

    <?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-2.5.xsd">

    <bean id="getDate" class="org.model.DateClass" autowire="byName">

    </bean>

    <bean id="date" class="java.util.Date"></bean>

    </beans>

    可以发现,在“getDate”Bean中没有为属性指定值,但指定了“autowire="byName"”。编辑测试类Test.java:

    package org.test;

    import org.model.DateClass;

    import org.springframework.context.ApplicationContext;

    import org.springframework.context.support.FileSystemXmlApplicationContext;

    public class Test {

    public static void main(String[]args){

    ApplicationContext ac=

    new FileSystemXmlApplicationContext("/WebRoot/WEB-INF/classes/config.xml");

    DateClass dc=(DateClass)ac.getBean("getDate");

    System.out.println(dc.getDate());

    }

    }

    运行后查看结果,输出为:

    Wed Jul 28 16:56:40 CST 2009

    2.使用byType模式

    byType模式指如果配置文件中正好有一个与属性类型一样的Bean,就自动装配这个属性,如果有多于一个这样的Bean,就抛出一个异常。例如在上例中,DateClass类的属性date为“Date”类型,而在配置文件中也有一个“Date”类型的Bean,这时若配置了自动装配的byType模式,就会自动装配DateClass类中的属性date值。例如,把上例的配置文件稍微修改,其他的不改变:

    <?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-2.5.xsd">

    <bean id="getDate" class="org.model.DateClass" autowire="byType">

    </bean>

    <bean id="date" class="java.util.Date"></bean>

    </beans>

    3.使用constructor模式

    constructor模式指的是根据构造方法的参数进行自动装配。例如,把DateClass.java修改为:

    package org.model;

    import java.util.Date;

    public class DateClass {

    private Date date;

    public DateClass(Date date){

    this.date=date;

    }

    public Date getDate() {

    return date;

    }

    public void setDate(Date date) {

    this.date = date;

    }

    }

    4.使用autodetect模式

    autodetect模式指的是通过检查类的内部来选择使用constructor或byType模式。例如,把使用constructor模式的实例的配置文件修改为:

    <?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-2.5.xsd">

    <bean id="getDate" class="org.model.DateClass" autowire="autodetect">

    </bean>

    <bean id="date" class="java.util.Date"></bean>

    </beans>

    5.使用no模式

    使用no模式就是不使用自动装配,这时为属性赋值就必须通过ref来引用其他Bean。例如,DateClass.java修改为:

    package org.model;

    import java.util.Date;

    public class DateClass {

    private Date date;

    public DateClass(Date date){

    this.date=date;

    }

    public Date getDate() {

    return date;

    }

    public void setDate(Date date) {

    this.date = date;

    }

    }

    配置文件修改为:

    <?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-2.5.xsd">

    <bean id="getDate" class="org.model.DateClass" autowire="no">

    <property name="date">

    <ref bean="date"/>

    </property>

    </bean>

    <bean id="date" class="java.util.Date"></bean>

    </beans>

    3. Bean中对集合的注入

              3.1 对list的注入

    对list集合的注入非常简单,如果类中有list类型的属性,在为其依赖注入值的时候就需要在配置文件中的<property>元素下应用其子元素<list>。下面举例说明。

    创建类ListBean.java,其有一个List类型的属性,代码如下:

    package org.model;

    import java.util.List;

    public class ListBean {

    private List list;

    public List getList() {

    return list;

    }

    public void setList(List list) {

    this.list = list;

    }

    }

    配置文件中Bean的配置为:

    <?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-2.5.xsd">

    <bean id="listBean" class="org.model.ListBean">

    <property name="list">

    <list>

    <value>java</value>

    <value>c++</value>

    <value>php</value>

    </list>

    </property>

    </bean>

    </beans>

    编写测试类,对ListBean类的“list”属性进行输入,测试是否注入成功。

    package org.test;

    import java.util.Iterator;

    import java.util.List;

    import org.model.ListBean;

    import org.springframework.context.ApplicationContext;

    import org.springframework.context.support.FileSystemXmlApplicationContext;

    public class Test {

    public static void main(String[]args){

    ApplicationContext ac=

    new FileSystemXmlApplicationContext("/WebRoot/WEB-INF/classes/config.xml");

    ListBean listbean=(ListBean)ac.getBean("listBean");

    List l=listbean.getList();

    System.out.println(l);

    }

    }

    运行程序,控制台信息为:

    [java, c++, php]

           3.2 对set的注入

    创建类SetBean.java,代码编写为:

    package org.model;

    import java.util.Set;

    public class SetBean {

    private Set set;

    public Set getSet() {

    return set;

    }

    public void setSet(Set set) {

    this.set = set;

    }

    }

            

                    配置文件config.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-2.5.xsd">

    <bean id="setbean" class="org.model.SetBean">

    <property name="set">

    <set>

    <value>java</value>

    <value>c++</value>

    <value>php</value>

    </set>

    </property>

    </bean>

    </beans>

    编写测试类,代码如下:

    package test;

    import org.model.SetBean;

    import org.springframework.context.ApplicationContext;

    import org.springframework.context.support.FileSystemXmlApplicationContext;

    public class Test {

    public static void main(String[]args){

    ApplicationContext ac=

    new FileSystemXmlApplicationContext("/WebRoot/WEB-INF/classes/config.xml");

    SetBean setbean=(SetBean)ac.getBean("setbean");

    System.out.println(setbean.getSet());

    }

    }

    运行程序,输出结果为:

    [java, c++, php]

    3 对Map的注入

    创建类MapBean.java,代码编写为:

    package org.model;

    import java.util.Map;

    public class MapBean {

    private Map map;

    public Map getMap() {

    return map;

    }

    public void setMap(Map map) {

    this.map = map;

    }

    }

    配置文件config.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-2.5.xsd">

    <bean id="mapbean" class="org.model.MapBean">

    <property name="map">

    <map>

    <entry key="java">

    <value>Java EE实用教程</value>

    </entry>

    <entry key="c++">

    <value>c++实用教程</value>

    </entry>

    <entry key="php">

    <value>PHP实用教程</value>

    </entry>

    </map>

    </property>

    </bean>

    </beans>

    编写测试类:

    package org.test;

    import java.util.Map;

    import org.model.MapBean;

    import org.springframework.context.ApplicationContext;

    import org.springframework.context.support.FileSystemXmlApplicationContext;

    public class Test {

    public static void main(String[]args){

    ApplicationContext ac=

    new FileSystemXmlApplicationContext("/WebRoot/WEB-INF/classes/config.xml");

    MapBean mapbean=(MapBean)ac.getBean("mapbean");

    Map map=mapbean.getMap();

    System.out.println(map);

    }

    }

    运行程序,控制台输出结果为:

    {java=Java EE实用教程, c++=c++实用教程, php=PHP实用教程}

    5 两种后处理器

             spring框架提供了良好的扩展性,它允许通过两种后处理器对IOC容器进行扩展,这两种后处理器分别是Bean后处理器及容器后处理器

              1. bean后处理器是一个特殊的bean,该bean不对外提供服务,所以无须定义ID属性,它主要是对容器中的其他Bean执行后处理

                  Bean后处理器必须实现BeanPostProcessor接口,并覆盖该接口中的两个方法:objectpostprocessafterliitializtion(Object bean,String beanname)throws BeansEXCEPTIONEY

                 objectposprocessbeforeInitialization方法这两种方法中的第一个参数是系统即将进行后处理的Bean实例,第二参数是该bean实例的名称,其中,第一种方法在目标Bean初妈化之前被调

                用,第二种方法是在初始化之后被调用.

    下面举例说明Bean后处理器的应用。

    建立项目,添加Spring核心类库后,在src下建立包“org.beanpost”,在该包下建立类MyBeanPost.java,代码编写如下:

    package org.beanpost;

    import org.springframework.beans.BeansException;

    import org.springframework.beans.factory.config.BeanPostProcessor;

    public class MyBeanPost implements BeanPostProcessor{

    public Object postProcessAfterInitialization(Object bean, String beanname)

    throws BeansException {

    System.out.println("Bean后处理器在初始化之前对"+beanname+"进行处理");

    return bean;

    }

    public Object postProcessBeforeInitialization(Object bean, String beanname)

    throws BeansException {

    System.out.println("Bean后处理在初始化之后对"+beanname+"进行处理");

    return bean;

    }

    }

    编写HelloWorld.java类,代码如下:

    package org.model; //该类放在org.model包中

    public class HelloWorld {

    private String message;

    public String getMessage() {

    return message;

    }

    public void setMessage(String message) {

    this.message = message;

    }

    //该方法会在初始化过程中被执行

    public void init(){

    System.out.println("该句在Bean初始化过程中执行");

    }

    }

    编写配置文件config.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-2.5.xsd">

    <!-- 配置初始化方法属性,在初始化过程中就会执行init方法 -->

    <bean id="HelloWorld" class="org.model.HelloWorld" init-method="init">

    <property name="message" >

    <value>Hello World!</value>

    </property>

    </bean>

    <!-- 该Bean可以配置id属性,也可以不配置id属性 -->

    <bean class="org.beanpost.MyBeanPost"></bean>

    </beans>

    编写测试类,完成Bean的实例化,代码如下:

    package org.test;

    import org.model.HelloWorld;

    import org.springframework.context.ApplicationContext;

    import org.springframework.context.support.FileSystemXmlApplicationContext;

    public class HelloWorldTest {

    public static void main(String[] args) {

    ApplicationContext ac=

    new FileSystemXmlApplicationContext("/WebRoot/WEB-INF/classes/config.xml");

    HelloWorld helloWorld=(HelloWorld) ac.getBean("HelloWorld");

    System.out.println(helloWorld.getMessage());

    }

    }

    使用ApplicationContext作为容器,无须手动注册BeanPostProcessor,因此如需要使用Bean后处理器,Spring容器建议使用ApplicationContext容器。运行程序,观察控制台打印出的信息。

    Bean后处理在初始化之后对HelloWorld进行处理

    该句在Bean初始化过程中执行

    Bean后处理器在初始化之前对HelloWorld进行处理

    Hello World!

    Spring的AOP及事务支持

    Spring的其他功能

  • 相关阅读:
    Linux 命令详解(二)awk 命令
    Linux 命令详解(一)export 命令
    ngx_lua_API 指令详解(六)ngx.thread.spawn、ngx.thread.wait、ngx.thread.kill介绍
    ngx_lua_API 指令详解(五)coroutine.create,coroutine.resume,coroutine.yield 等集合指令介绍
    Git与GitHub学习笔记(三).gitignore文件忽略和删除本地以及远程文件
    高性能服务器架构(三):分布式缓存
    Kubernetes的node,NotReady 如何查问题,针对问题解决
    K8S 报 ErrImagePull k8s.gcr.io国内无法连接解决方法
    Quick deployment of Kubernetes
    Kubernetes 部署笔记
  • 原文地址:https://www.cnblogs.com/elite-2012/p/4366838.html
Copyright © 2011-2022 走看看