Changes between Version 29 and Version 30 of waue/2011/spring


Ignore:
Timestamp:
Aug 29, 2011, 5:12:06 PM (13 years ago)
Author:
waue
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • waue/2011/spring

    v29 v30  
    343343}}}
    344344
    345 == 附錄 ==
    346 === 資料集合 ===
     345
     346
     347= xml 與 properties =
     348
     349 == 不用 bean.xml ==
     350
     351注意!此段原文可編譯但無法執行,以下編碼已經完全修正,請注意各檔案的路徑
     352
     353假設 AaBean 的內容如下:
     354
     355 * src/waue/one/AaBean.java
     356
     357{{{
     358#!java
     359package waue.one;
     360
     361public class AaBean {
     362    private String helloWord;
     363   
     364    public AaBean() {
     365    }
     366   
     367    public void setHelloWord(String helloWord) {
     368        this.helloWord = helloWord;
     369    }
     370    public String getHelloWord() {
     371        return helloWord;
     372    }
     373}
     374}}}
     375
     376 === 只用 properties  ===
     377
     378XML檔案的階層格式適用於於組態設定,也因此許多的開源專案都將XML作為預設的組態定義方式,但通常也會提供非XML定義檔的方式,像屬性檔案. properties
     379
     380Spring也可以讓您使用屬性檔案定義Bean,例如定義一個 waue_one.properties:
     381
     382注意! waue_one.properties 放在src 目錄底下,而非根目錄(非beans-config.xml 的目錄)
     383
     384注意! aaBean.(class) 的()符號不可省略,否則運算時出錯
     385
     386 * src/waue_one.properties
     387
     388{{{
     389#!java
     390aaBean.(class)=waue.one.AaBean
     391aaBean.helloWord=Properties Welcome!
     392}}}
     393
     394
     395 * src/waue/one/SpringDemo.java
     396
     397{{{
     398#!java
     399package waue.one;
     400
     401import org.springframework.beans.factory.BeanFactory;
     402import org.springframework.beans.factory.support.BeanDefinitionRegistry;
     403import org.springframework.beans.factory.support.DefaultListableBeanFactory;
     404import org.springframework.beans.factory.support.PropertiesBeanDefinitionReader;
     405import org.springframework.core.io.ClassPathResource;
     406
     407public class SpringDemo {
     408    public static void main(String[] args) {
     409        BeanDefinitionRegistry reg =
     410            new DefaultListableBeanFactory();
     411        PropertiesBeanDefinitionReader reader =
     412            new PropertiesBeanDefinitionReader(reg);
     413        reader.loadBeanDefinitions(
     414                new ClassPathResource("waue_one.properties"));
     415       
     416        BeanFactory factory = (BeanFactory) reg;
     417        AaBean hello = (AaBean) factory.getBean("aaBean");
     418        System.out.println(hello.getHelloWord());
     419    }
     420}
     421}}}
     422
     423 === main中直接綁值 ===
     424
     425不用 xml , 也不用 properties 來設定值,好處是,客戶端與定義檔是隔離的,他們無法接觸定義檔的內容,直接來看個例子:
     426
     427注意!以下 SpringDemo.java 引用上面的 waue.one.AaBean.java ,
     428
     429 * src/waue/two/SpringDemo.java
     430
     431{{{
     432#!java
     433
     434package waue.two;
     435
     436import org.springframework.beans.MutablePropertyValues;
     437import org.springframework.beans.factory.BeanFactory;
     438import org.springframework.beans.factory.support.BeanDefinitionRegistry;
     439import org.springframework.beans.factory.support.DefaultListableBeanFactory;
     440import org.springframework.beans.factory.support.RootBeanDefinition;
     441
     442import waue.one.AaBean;
     443
     444public class SpringDemo {
     445        public static void main(String[] args) {
     446                // 設置屬性
     447                MutablePropertyValues properties = new MutablePropertyValues();
     448                properties.addPropertyValue("helloWord", "Hello! Waue!");
     449
     450                // 設置Bean定義
     451                RootBeanDefinition definition = new RootBeanDefinition(AaBean.class,
     452                                properties);
     453
     454                // 註冊Bean定義與Bean別名
     455                BeanDefinitionRegistry reg = new DefaultListableBeanFactory();
     456                reg.registerBeanDefinition("fooBean", definition);
     457
     458                BeanFactory factory = (BeanFactory) reg;
     459                AaBean hello = (AaBean) factory.getBean("fooBean");
     460                System.out.println(hello.getHelloWord());
     461        }
     462}
     463}}}
     464
     465
     466 == properties / xml  ==
     467
     468藉由這個類別,您可以在.properties中設定一些優先屬性設定,這個設定如果與XML中的屬性定義有相衝突,則以.properties中的設定為主
     469
     470注意! 此時 properties 檔必須跟 xml 檔放在一起
     471
     472注意! xml 內的value 值無意義,因為都已 properties 為主,而 properties 也不可以因為 xml 已經設定了該property 屬性,而不給 aaBean.helloWord
     473
     474
     475 * /waue_one.properties
     476
     477{{{
     478#!java
     479aaBean.helloWord=Setup Properties with beans-config
     480}}}
     481
     482 * /beans-config.xml
     483
     484{{{
     485#!xml
     486
     487<?xml version="1.0" encoding="UTF-8"?>
     488<beans xmlns="http://www.springframework.org/schema/beans"
     489        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     490        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
     491    <bean id="configBean"
     492  class="org.springframework.beans.factory.config.PropertyOverrideConfigurer">
     493        <property name="location">
     494            <value>waue_one.properties</value>
     495        </property>
     496    </bean>
     497
     498    <bean id="aaBean" class="waue.one.AaBean">
     499        <property name="helloWord">
     500            <value> </value>
     501        </property>
     502    </bean>
     503
     504</beans>
     505}}}
     506
     507 * src/waue/one/SpringDemo.java (同前)
     508
     509{{{
     510#!java
     511package waue.one;
     512
     513import org.springframework.context.ApplicationContext;
     514import org.springframework.context.support.FileSystemXmlApplicationContext;
     515
     516public class SpringDemo {
     517    public static void main(String[] args) throws InterruptedException {
     518        ApplicationContext context =
     519            new FileSystemXmlApplicationContext("beans-config.xml");
     520         
     521        AaBean hello =
     522            (AaBean) context.getBean("aaBean");
     523        System.out.println(hello.getHelloWord());
     524    }
     525}
     526}}}
     527
     528 * src/waue/one/AaBean.java (同前)
     529
     530{{{
     531#!java
     532package waue.one;
     533
     534public class AaBean {
     535    private String helloWord;
     536   
     537    public AaBean() {
     538    }
     539   
     540    public void setHelloWord(String helloWord) {
     541        this.helloWord = helloWord;
     542    }
     543    public String getHelloWord() {
     544        return helloWord;
     545    }
     546}
     547}}}
     548
     549
     550
     551
     552
     553
     554= 進階 bean 設定 =
     555
     556
     557
     558
     559 == bean 給值的前後設定 ==
     560
     561在Bean的屬性被Spring容器設定之後,您還有機會自訂一些對Bean的修正,您可以實作org.springframework.beans.factory.config.BeanPostProcessor介面:
     562
     563{{{
     564#!java
     565package org.springframework.beans.factory.config;
     566public interface BeanPostProcessor {
     567    public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException;
     568    public Object postProcessAfterInitialization(Object bean, String name) throws BeansException;
     569}
     570}}}
     571
     572postProcessBeforeInitialization()方法會在Bean初始化動作之前(例如InitializingBean的 afterPropertiesSet()方法或自定義的init方法)被呼叫,而postProcessAfterInitialization()方法會在Bean初始化之後立即被呼叫。
     573
     574舉個例子來說,您可以實作一個大寫修正器,對於String型態的Bean屬性,無論在定義檔中是設定為大寫或小寫,在Bean屬性設定之後,您可以在大寫修正器中將所有的String改為大寫,例如:
     575
     576 * UpperCaseModifier.java
     577
     578{{{
     579#!java
     580package onlyfun.caterpillar;
     581
     582import java.lang.reflect.Field;
     583
     584import org.springframework.beans.BeansException;
     585import org.springframework.beans.factory.config.BeanPostProcessor;
     586
     587public class UpperCaseModifier implements BeanPostProcessor {
     588
     589    public Object postProcessBeforeInitialization(
     590                        Object bean, String name) throws BeansException {
     591        Field[] fields = bean.getClass().getDeclaredFields();
     592       
     593        for(int i = 0; i < fields.length; i++) {
     594            if(fields[i].getType().equals(String.class)) {
     595                fields[i].setAccessible(true);
     596                try {
     597                    String original = (String) fields[i].get(bean);
     598                    fields[i].set(bean, original.toUpperCase());
     599                } catch (IllegalArgumentException e) {
     600                    e.printStackTrace();
     601                } catch (IllegalAccessException e) {
     602                    e.printStackTrace();
     603                }
     604            }
     605        }
     606       
     607        return bean;
     608    }
     609
     610    public Object postProcessAfterInitialization(
     611                          Object bean, String name) throws BeansException {
     612        return bean;
     613    }
     614
     615}
     616}}}
     617
     618假設您定義了這麼一個Bean類別:
     619
     620 * HelloBean.java
     621
     622{{{
     623#!java
     624package onlyfun.caterpillar;
     625
     626public class HelloBean {
     627    private String helloWord;
     628   
     629    public HelloBean() {
     630    }
     631   
     632    public void setHelloWord(String helloWord) {
     633        this.helloWord = helloWord;
     634    }
     635    public String getHelloWord() {
     636        return helloWord;
     637    }
     638}
     639}}}
     640
     641ApplicationContext會自動偵測您是否在定義檔中定義了實作BeanPostProcessor介面的類別,例如:
     642
     643 * beans-config.xml
     644
     645{{{
     646#!java
     647<?xml version="1.0" encoding="UTF-8"?>
     648<!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN"
     649  "http://www.springframework.org/dtd/spring-beans.dtd">
     650
     651<beans> 
     652    <bean id="upperCaseModifier"
     653          class="onlyfun.caterpillar.UpperCaseModifier"/>
     654   
     655    <bean id="helloBean" class="onlyfun.caterpillar.HelloBean">
     656        <property name="helloWord">
     657            <value>Hello!</value>
     658        </property>
     659    </bean>
     660</beans>
     661}}}
     662
     663Spring容器會在每一個Bean被初始化之前之後分別呼叫upperCaseModifier的 postProcessBeforeInitialization()方法與postProcessAfterInitialization()方法,以對Bean進行指定的相關修正,可以實際來看看以下的測試程式:
     664
     665 * SpringDemo.java
     666
     667{{{
     668#!java
     669package onlyfun.caterpillar;
     670
     671import org.springframework.context.ApplicationContext;
     672import org.springframework.context.support.FileSystemXmlApplicationContext;
     673
     674public class SpringDemo {
     675    public static void main(String[] args) {
     676        ApplicationContext context =
     677            new FileSystemXmlApplicationContext("beans-config.xml");
     678         
     679        HelloBean hello =
     680            (HelloBean) context.getBean("helloBean");
     681        System.out.println(hello.getHelloWord());
     682    }
     683}
     684}}}
     685
     686執行結果如下:
     687{{{
     688HELLO!
     689}}}
     690雖然您在定義檔中的helloBean之helloWord屬性是設定小寫字母,但upperCaseModifier將之改為大寫字母了。
     691
     692== 資料集合 ==
    347693
    348694對於像 '''陣列、java.util.List、java.util.Set、java.util.Map''' 等'''集合物件''',在注入前必須填充入一些物件至集合中,然後再將集合物件注入至所需的Bean中,
     
    415761}}}
    416762
    417  === 自動綁定 ===
     763 == 自動綁定 ==
    418764
    419765測試後not work,也許與Spring 版本有關
     
    421767[http://caterpillar.onlyfun.net/Gossip/SpringGossip/AutoWiring.html autowire (詳細)]
    422768
    423  === bean 生命週期 ===
     769 == bean 生命週期 ==
    424770
    425771在Spring中,從BeanFactory或ApplicationContext取得的實例為 Singleton,預設是每一個Bean別名維持一個實例,對單執行緒的程式來說並不會有什麼問題,但對於多執行緒的程式,您必須注意到執行緒安全,您也可以設定每次取得Bean時都產生一個新的實例,例如:
     
    433779
    434780
    435 = xml 與 properties =
    436 
    437  == 不用 bean.xml ==
    438 
    439 注意!此段原文可編譯但無法執行,以下編碼已經完全修正,請注意各檔案的路徑
    440 
    441 假設 AaBean 的內容如下:
    442 
    443  * src/waue/one/AaBean.java
    444 
    445 {{{
    446 #!java
    447 package waue.one;
    448 
    449 public class AaBean {
    450     private String helloWord;
    451    
    452     public AaBean() {
    453     }
    454    
    455     public void setHelloWord(String helloWord) {
    456         this.helloWord = helloWord;
    457     }
    458     public String getHelloWord() {
    459         return helloWord;
    460     }
    461 }
    462 }}}
    463 
    464  === 只用 properties  ===
    465 
    466 XML檔案的階層格式適用於於組態設定,也因此許多的開源專案都將XML作為預設的組態定義方式,但通常也會提供非XML定義檔的方式,像屬性檔案. properties
    467 
    468 Spring也可以讓您使用屬性檔案定義Bean,例如定義一個 waue_one.properties:
    469 
    470 注意! waue_one.properties 放在src 目錄底下,而非根目錄(非beans-config.xml 的目錄)
    471 
    472 注意! aaBean.(class) 的()符號不可省略,否則運算時出錯
    473 
    474  * src/waue_one.properties
    475 
    476 {{{
    477 #!java
    478 aaBean.(class)=waue.one.AaBean
    479 aaBean.helloWord=Properties Welcome!
    480 }}}
    481 
    482 
    483  * src/waue/one/SpringDemo.java
    484 
    485 {{{
    486 #!java
    487 package waue.one;
    488 
    489 import org.springframework.beans.factory.BeanFactory;
    490 import org.springframework.beans.factory.support.BeanDefinitionRegistry;
    491 import org.springframework.beans.factory.support.DefaultListableBeanFactory;
    492 import org.springframework.beans.factory.support.PropertiesBeanDefinitionReader;
    493 import org.springframework.core.io.ClassPathResource;
    494 
    495 public class SpringDemo {
    496     public static void main(String[] args) {
    497         BeanDefinitionRegistry reg =
    498             new DefaultListableBeanFactory();
    499         PropertiesBeanDefinitionReader reader =
    500             new PropertiesBeanDefinitionReader(reg);
    501         reader.loadBeanDefinitions(
    502                 new ClassPathResource("waue_one.properties"));
    503        
    504         BeanFactory factory = (BeanFactory) reg;
    505         AaBean hello = (AaBean) factory.getBean("aaBean");
    506         System.out.println(hello.getHelloWord());
    507     }
    508 }
    509 }}}
    510 
    511  === main中直接綁值 ===
    512 
    513 不用 xml , 也不用 properties 來設定值,好處是,客戶端與定義檔是隔離的,他們無法接觸定義檔的內容,直接來看個例子:
    514 
    515 注意!以下 SpringDemo.java 引用上面的 waue.one.AaBean.java ,
    516 
    517  * src/waue/two/SpringDemo.java
    518 
    519 {{{
    520 #!java
    521 
    522 package waue.two;
    523 
    524 import org.springframework.beans.MutablePropertyValues;
    525 import org.springframework.beans.factory.BeanFactory;
    526 import org.springframework.beans.factory.support.BeanDefinitionRegistry;
    527 import org.springframework.beans.factory.support.DefaultListableBeanFactory;
    528 import org.springframework.beans.factory.support.RootBeanDefinition;
    529 
    530 import waue.one.AaBean;
    531 
    532 public class SpringDemo {
    533         public static void main(String[] args) {
    534                 // 設置屬性
    535                 MutablePropertyValues properties = new MutablePropertyValues();
    536                 properties.addPropertyValue("helloWord", "Hello! Waue!");
    537 
    538                 // 設置Bean定義
    539                 RootBeanDefinition definition = new RootBeanDefinition(AaBean.class,
    540                                 properties);
    541 
    542                 // 註冊Bean定義與Bean別名
    543                 BeanDefinitionRegistry reg = new DefaultListableBeanFactory();
    544                 reg.registerBeanDefinition("fooBean", definition);
    545 
    546                 BeanFactory factory = (BeanFactory) reg;
    547                 AaBean hello = (AaBean) factory.getBean("fooBean");
    548                 System.out.println(hello.getHelloWord());
    549         }
    550 }
    551 }}}
    552 
    553 
    554  == properties / xml  ==
    555 
    556 藉由這個類別,您可以在.properties中設定一些優先屬性設定,這個設定如果與XML中的屬性定義有相衝突,則以.properties中的設定為主
    557 
    558 注意! 此時 properties 檔必須跟 xml 檔放在一起
    559 
    560 注意! xml 內的value 值無意義,因為都已 properties 為主,而 properties 也不可以因為 xml 已經設定了該property 屬性,而不給 aaBean.helloWord
    561 
    562 
    563  * /waue_one.properties
    564 
    565 {{{
    566 #!java
    567 aaBean.helloWord=Setup Properties with beans-config
    568 }}}
    569 
    570  * /beans-config.xml
    571 
    572 {{{
    573 #!xml
    574 
    575 <?xml version="1.0" encoding="UTF-8"?>
    576 <beans xmlns="http://www.springframework.org/schema/beans"
    577         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    578         xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    579     <bean id="configBean"
    580   class="org.springframework.beans.factory.config.PropertyOverrideConfigurer">
    581         <property name="location">
    582             <value>waue_one.properties</value>
    583         </property>
    584     </bean>
    585 
    586     <bean id="aaBean" class="waue.one.AaBean">
    587         <property name="helloWord">
    588             <value> </value>
    589         </property>
    590     </bean>
    591 
    592 </beans>
    593 }}}
    594 
    595  * src/waue/one/SpringDemo.java (同前)
    596 
    597 {{{
    598 #!java
    599 package waue.one;
    600 
    601 import org.springframework.context.ApplicationContext;
    602 import org.springframework.context.support.FileSystemXmlApplicationContext;
    603 
    604 public class SpringDemo {
    605     public static void main(String[] args) throws InterruptedException {
    606         ApplicationContext context =
    607             new FileSystemXmlApplicationContext("beans-config.xml");
    608          
    609         AaBean hello =
    610             (AaBean) context.getBean("aaBean");
    611         System.out.println(hello.getHelloWord());
    612     }
    613 }
    614 }}}
    615 
    616  * src/waue/one/AaBean.java (同前)
    617 
    618 {{{
    619 #!java
    620 package waue.one;
    621 
    622 public class AaBean {
    623     private String helloWord;
    624    
    625     public AaBean() {
    626     }
    627    
    628     public void setHelloWord(String helloWord) {
    629         this.helloWord = helloWord;
    630     }
    631     public String getHelloWord() {
    632         return helloWord;
    633     }
    634 }
    635 }}}
    636 
    637 
    638 
    639 
    640 
    641 
    642 = 進階 bean 設定 =
    643 
    644 
    645 
    646 
    647  == bean 給值的前後設定 ==
    648 
    649 在Bean的屬性被Spring容器設定之後,您還有機會自訂一些對Bean的修正,您可以實作org.springframework.beans.factory.config.BeanPostProcessor介面:
    650 
    651 {{{
    652 #!java
    653 package org.springframework.beans.factory.config;
    654 public interface BeanPostProcessor {
    655     public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException;
    656     public Object postProcessAfterInitialization(Object bean, String name) throws BeansException;
    657 }
    658 }}}
    659 
    660 postProcessBeforeInitialization()方法會在Bean初始化動作之前(例如InitializingBean的 afterPropertiesSet()方法或自定義的init方法)被呼叫,而postProcessAfterInitialization()方法會在Bean初始化之後立即被呼叫。
    661 
    662 舉個例子來說,您可以實作一個大寫修正器,對於String型態的Bean屬性,無論在定義檔中是設定為大寫或小寫,在Bean屬性設定之後,您可以在大寫修正器中將所有的String改為大寫,例如:
    663 
    664  * UpperCaseModifier.java
    665 
    666 {{{
    667 #!java
    668 package onlyfun.caterpillar;
    669 
    670 import java.lang.reflect.Field;
    671 
    672 import org.springframework.beans.BeansException;
    673 import org.springframework.beans.factory.config.BeanPostProcessor;
    674 
    675 public class UpperCaseModifier implements BeanPostProcessor {
    676 
    677     public Object postProcessBeforeInitialization(
    678                         Object bean, String name) throws BeansException {
    679         Field[] fields = bean.getClass().getDeclaredFields();
    680        
    681         for(int i = 0; i < fields.length; i++) {
    682             if(fields[i].getType().equals(String.class)) {
    683                 fields[i].setAccessible(true);
    684                 try {
    685                     String original = (String) fields[i].get(bean);
    686                     fields[i].set(bean, original.toUpperCase());
    687                 } catch (IllegalArgumentException e) {
    688                     e.printStackTrace();
    689                 } catch (IllegalAccessException e) {
    690                     e.printStackTrace();
    691                 }
    692             }
    693         }
    694        
    695         return bean;
    696     }
    697 
    698     public Object postProcessAfterInitialization(
    699                           Object bean, String name) throws BeansException {
    700         return bean;
    701     }
    702 
    703 }
    704 }}}
    705 
    706 假設您定義了這麼一個Bean類別:
    707 
    708  * HelloBean.java
    709 
    710 {{{
    711 #!java
    712 package onlyfun.caterpillar;
    713 
    714 public class HelloBean {
    715     private String helloWord;
    716    
    717     public HelloBean() {
    718     }
    719    
    720     public void setHelloWord(String helloWord) {
    721         this.helloWord = helloWord;
    722     }
    723     public String getHelloWord() {
    724         return helloWord;
    725     }
    726 }
    727 }}}
    728 
    729 ApplicationContext會自動偵測您是否在定義檔中定義了實作BeanPostProcessor介面的類別,例如:
    730 
    731  * beans-config.xml
    732 
    733 {{{
    734 #!java
    735 <?xml version="1.0" encoding="UTF-8"?>
    736 <!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN"
    737   "http://www.springframework.org/dtd/spring-beans.dtd">
    738 
    739 <beans> 
    740     <bean id="upperCaseModifier"
    741           class="onlyfun.caterpillar.UpperCaseModifier"/>
    742    
    743     <bean id="helloBean" class="onlyfun.caterpillar.HelloBean">
    744         <property name="helloWord">
    745             <value>Hello!</value>
    746         </property>
    747     </bean>
    748 </beans>
    749 }}}
    750 
    751 Spring容器會在每一個Bean被初始化之前之後分別呼叫upperCaseModifier的 postProcessBeforeInitialization()方法與postProcessAfterInitialization()方法,以對Bean進行指定的相關修正,可以實際來看看以下的測試程式:
    752 
    753  * SpringDemo.java
    754 
    755 {{{
    756 #!java
    757 package onlyfun.caterpillar;
    758 
    759 import org.springframework.context.ApplicationContext;
    760 import org.springframework.context.support.FileSystemXmlApplicationContext;
    761 
    762 public class SpringDemo {
    763     public static void main(String[] args) {
    764         ApplicationContext context =
    765             new FileSystemXmlApplicationContext("beans-config.xml");
    766          
    767         HelloBean hello =
    768             (HelloBean) context.getBean("helloBean");
    769         System.out.println(hello.getHelloWord());
    770     }
    771 }
    772 }}}
    773 
    774 執行結果如下:
    775 {{{
    776 HELLO!
    777 }}}
    778 雖然您在定義檔中的helloBean之helloWord屬性是設定小寫字母,但upperCaseModifier將之改為大寫字母了。
    779 
    780 
    781 
    782781
    783782 = eclipse 開發環境 =