[spring]從頭開始-Configuration Using Java Classes

開發工具:IntelliJ IDEA 13

開發環境:jdk1.6.0_45

Framework:spring 3

之前都用xml的方式來配置spring configuration file,現在我們使用java code 的方式來達成一樣的效果,建立一個 Provider 相依於 Renderer 的範例。先建立一個 Provider:

MessageProvider.java

package foo.bar;

/**

 * Created by Hsu on 2014/7/16.

 */

public interface MessageProvider {

    public String getMessage();

}

再建立一個implement 類別:

ConfigurableMessageProvider.java

package foo.bar;

/**

 * Created by Hsu on 2014/7/16.

 */

public class ConfigurableMessageProvider implements MessageProvider {

    private String message = "Default message";

    public ConfigurableMessageProvider() {

    }

    public ConfigurableMessageProvider(String message) {

        this.message = message;

    }

    public void setMessage(String message) {

        this.message = message;

    }

    @Override

    public String getMessage() {

        return this.message;

    }

}

接著建立 Renderer 類:

MessageRenderer.java

package foo.bar;

/**

 * Created by Hsu on 2014/7/16.

 */

public interface MessageRenderer {

    public void render();

    public void setMessageProvider(MessageProvider provider);

    public MessageProvider getMessageProvider();

}

一樣再建立一個 Renderer 的 implement 類:

StandardOutMessageRenderer.java

package foo.bar;

/**

 * Created by Hsu on 2014/7/16.

 */

public class StandardOutMessageRenderer implements MessageRenderer {

    private MessageProvider messageProvider = null;

    public void render() {

        if (messageProvider == null) {

            throw new RuntimeException(

                    "You must set the property messageProvider of class:"

                            + StandardOutMessageRenderer.class.getName());

        }

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

    }

    public void setMessageProvider(MessageProvider provider){

        this.messageProvider = provider;

    }

    public MessageProvider getMessageProvider() {

        return this.messageProvider;

    }

}

接著使用 xml 配置出上面的相依關係

spring-config.xml

..

..標頭的部分省略

    <bean id="messageRenderer"

          class="foo.bar.StandardOutMessageRenderer"

          p:messageProvider-ref="messageProvider"/>

    <bean id="messageProvider"

          class="foo.bar.ConfigurableMessageProvider"

          c:message="This is a configurable message"/>

..結尾省略

上面配置檔的部分有使用 p 標籤 及 c 標籤,記得要引入相關的標頭,這邊順道回憶一下它們的主要作用:

p: The pnamespace provides a simpler DI configuration for Setter Injection. 

c: New in Spring 3.1, the cnamespace provides a more simple DI configuration for Constructor Injection.

p 就是使用在 setter 的部份,c是使用在 Constructor inject 的部份。

最後是演繹類別的部份:

JavaConfigSimpleExample.java

package foo.bar;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

/**

 * Created by Hsu on 2014/7/16.

 */

public class JavaConfigSimpleExample {

    public static void main(String[] args) {

        ApplicationContext ctx = new

                ClassPathXmlApplicationContext("classpath:spring-config.xml");

        MessageRenderer renderer =

                ctx.getBean("messageRenderer", MessageRenderer.class);

        renderer.render();

    }

}

簡單介紹一下上面範例的概念,提供者 provider 可以有很多種不同的提供者(看implement出哪種提供者),而 renderer(渲染器或稱為解析器)也可以有很多種,依照 provider 的不同而選擇不同的 renderer 將資訊送出。

上述範例的執行結果:

This is a configurable message

就是我們在 xml 配置檔中所 inject 的訊息。接著我們使用 java code 來配置。

AppConfig.java

package foo.bar;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

/**

 * Created by Hsu on 2014/7/16.

 */

// 宣告這個類別是一個配置檔

@Configuration

public class AppConfig {

    // XML:

    // <bean id="messageProvider"  class="foo.bar.ConfigurableMessageProvider"/>

    // new ConfigurableMessageProvider("Test Message") like c:message="This is a configurable message"

    @Bean

    public MessageProvider messageProvider() {

        return new ConfigurableMessageProvider("Test Message");

    }

    // XML:

    // <bean id="messageRenderer" class=""foo.bar.StandardOutMessageRenderer"

    // p:messageProvider-ref="messageProvider"/>

    @Bean

    public MessageRenderer messageRenderer() {

        MessageRenderer renderer = new StandardOutMessageRenderer();

        // Setter injection

        renderer.setMessageProvider(messageProvider());

        return renderer;

    }

}

上面我們可以看到要完成 java code 來配置,需引入 org.springframework.context.annotation.Bean 及 org.springframework.context.annotation.Configuration ,類別中使用 @Configuration 宣告該類別為一個配置檔,接著在類別中使用 @Bean 來宣告 bean,bean 的內容同我們之前的 xml 配置檔內容,相關的對應都已經註明在程式中,看到就應該可以了解

最後我們來完成演繹類別

JavaConfigSimpleExample1.java

public class JavaConfigSimpleExample1 {

    public static void main(String[] args) {

       

        ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);

        // 採用 Autowire

        //ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig2.class);

        MessageRenderer renderer =

                ctx.getBean("messageRenderer", MessageRenderer.class);

        renderer.render();

    }

}

執行結果:

Test Message

上面的演繹類別有注意到還有一個 AppConfig2.class 被註解起來了,這是準備使用 Autowire 來完成同樣效果的。

檔案內容如下:

AppConfig2.java

package foo.bar;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.context.annotation.*;

import org.springframework.core.env.Environment;

import org.springframework.transaction.annotation.EnableTransactionManagement;

/**

 * Created by Hsu on 2014/7/16.

 */

@Configuration

//

// @Import(OtherConfig.class)

// XML: <import resource="classpath:spring-config2.xml")

@ImportResource(value="classpath:spring-config2.xml")

// XML: <context:property-placeholder location="classpath:message.properties"/>

@PropertySource(value="classpath:message.properties")

// XML: <context:component-scan base-package="foo.bar"/>

@ComponentScan(basePackages={"foo.bar"})

// @EnableTransactionManagement defines that we will use Spring’s transaction management feature

@EnableTransactionManagement

public class AppConfig2 {

    @Autowired

    // spring 3.1.x new add

    Environment env;

    // XML:

    // <bean id="messageProvider" class="foo.bar.ConfigurableMessageProvider"/>

    @Bean(name="messageProvider")

    //XML <bean .... lazy-init="true"/> The @Lazy annotation instructs Spring to instantiate the bean only when requested

    @Lazy(value=true)

    public MessageProvider messageProvider() {

    // Constructor injection

        return new ConfigurableMessageProvider(env.getProperty("message"));

    }

    // XML:

    // <bean id="messageRenderer" class="foo.bar.StandardOutMessageRenderer"

    // p:messageProvider-ref="messageProvider"/>

    @Bean(name="messageRenderer")

    @Scope(value="prototype") // XML: <bean ... scope="prototype"/>

    @DependsOn(value="messageProvider") // XML: <bean ... depends-on="messageProvider"/>

    public MessageRenderer messageRenderer() {

        MessageRenderer renderer = new StandardOutMessageRenderer();

        // Setter injection

        renderer.setMessageProvider(messageProvider());

        return renderer;

    }

}

搭配的 spring configuration file:

spring-config2.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:context="http://www.springframework.org/schema/context"

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

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

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

    <context:annotation-config />

    <context:component-scan base-package="foo.bar"/>

</beans>

message.properties 的內容

        message=Spring 3 Java Configuration Rocks!

範例執行結果:

        Spring 3 Java Configuration Rocks!

可以看到上面是完全使用 Annotation 來完成 java config code 的設定,並由 message.properties 讀取 provider 的 message,程式碼中皆有註解,可以輕易了解用途,其中注意的是 使用 env.getProperty("message") 來讀取 properties 的資料,跟我們之前所用的 ctx.getMessage("msg", null, english) 有些許的不同,需要特別注意一下

from: http://docs.spring.io/spring/docs/3.1.x/javadoc-api/index.html?org/springframework/core/env/Environment.html

getProperty

String getProperty(String key)

Return the property value associated with the given key, or null if the key cannot be resolved.

Parameters:

key - the property name to resolve

See Also:

getProperty(String, String), getProperty(String, Class), getRequiredProperty(String)

demo程式(右鍵另開視窗下載)