<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    [摘錄]Spring入門

    摘錄地址:http://www.codechina.net/resource/html/2006-04/07/150546.html
    Spring入門

    Spring是一個(gè)非常優(yōu)秀的輕量級(jí)框架,通過Spring的IoC容器,我們的關(guān)注點(diǎn)便放到了需要實(shí)現(xiàn)的業(yè)務(wù)邏輯上。對AOP的支持則能讓我們動(dòng)態(tài)增強(qiáng)業(yè)務(wù)方法。編寫普通的業(yè)務(wù)邏輯Bean是非常容易而且易于測試的,因?yàn)樗苊撾xJ2EE容器(如Servlet,JSP環(huán)境)單獨(dú)進(jìn)行單元測試。最后的一步便是在Spring框架中將這些業(yè)務(wù)Bean以XML配置文件的方式組織起來,它們就按照我們預(yù)定的目標(biāo)正常工作了!非常容易!

    本文將給出一個(gè)基本的Spring入門示例,并演示如何使用Spring的AOP將復(fù)雜的業(yè)務(wù)邏輯分離到每個(gè)方面中。

    1.開發(fā)環(huán)境配置
    2.編寫B(tài)ean接口及其實(shí)現(xiàn)
    3.在Spring中配置Bean并獲得Bean的實(shí)例
    4.編寫Advisor以增強(qiáng)ServiceBean
    5.總結(jié)

    1.開發(fā)環(huán)境配置

    首先,需要正確配置Java環(huán)境。推薦安裝JDK1.4.2,并正確配置環(huán)境變量:

    JAVA_HOME=<JDK安裝目錄>
    CLASSPATH=.
    Path=%JAVA_HOME%\\bin;……

    我們將使用免費(fèi)的Eclipse 3.1作為IDE。新建一個(gè)Java Project,將Spring的發(fā)布包spring.jar以及commons-logging-1.0.4.jar復(fù)制到Project目錄下,并在Project > Properties中配置好Java Build Path:

    src=uppic/20060407/1405270.jpg

    2.編寫B(tài)ean接口及其實(shí)現(xiàn)

    我們實(shí)現(xiàn)一個(gè)管理用戶的業(yè)務(wù)Bean。首先定義一個(gè)ServiceBean接口,聲明一些業(yè)務(wù)方法:

    /**
    ?* Copyright_2006, Liao Xuefeng
    ?* Created on 2006-3-9
    ?* For more information, please visit:
    http://www.crackj2ee.com
    ?*/
    package com.crackj2ee.example.spring;
    /**
    ?* Interface of service facade.
    ?*
    ?* @author Xuefeng
    ?*/
    public interface ServiceBean {
    ??? void addUser(String username, String password);
    ??? void deleteUser(String username);
    ??? boolean findUser(String username);
    ??? String getPassword(String username);
    }

    然后在MyServiceBean中實(shí)現(xiàn)接口:

    /**
    ?* Copyright_2006, Liao Xuefeng
    ?* Created on 2006-3-9
    ?*
    ?* For more information, please visit:
    http://www.crackj2ee.com
    ?*/
    package com.crackj2ee.example.spring;
    import java.util.*;
    public class MyServiceBean implements ServiceBean {
    ??? private String dir;
    ??? private Map map = new HashMap();
    ??? public void setUserDir(String dir) {
    ??????? this.dir = dir;
    ??????? System.out.println(Set user dir to: + dir);
    ??? }
    ??? public void addUser(String username, String password) {
    ??????? if(!map.containsKey(username))
    ??????????? map.put(username, password);
    ??????? else
    ??????????? throw new RuntimeException(User already exist.);
    ??? }
    ??? public void deleteUser(String username) {
    ??????? if(map.remove(username)==null)
    ??????????? throw new RuntimeException(User not exist.);
    ??? }
    ??? public boolean findUser(String username) {
    ??????? return map.containsKey(username);
    ??? }
    ??? public String getPassword(String username) {
    ??????? return (String)map.get(username);
    ??? }
    }

    為了簡化邏輯,我們使用一個(gè)Map保存用戶名和口令。

    現(xiàn)在,我們已經(jīng)有了一個(gè)業(yè)務(wù)Bean。要測試它非常容易,因?yàn)榈侥壳盀橹梗覀冞€沒有涉及到Spring容器,也沒有涉及到任何Web容器(假定這是一個(gè)Web應(yīng)用程序關(guān)于用戶管理的業(yè)務(wù)Bean)。完全可以直接進(jìn)行Unit測試,或者,簡單地寫個(gè)main方法測試:

    /**
    ?* Copyright_2006, Liao Xuefeng
    ?* Created on 2006-3-9
    ?* For more information, please visit:
    http://www.crackj2ee.com
    ?*/
    package com.crackj2ee.example.spring;
    public class Main {
    ??? public static void main(String[] args) throws Exception {
    ??????? ServiceBean service = new MyServiceBean();
    ??????? service.addUser("bill", "hello");
    ??????? service.addUser("tom", "goodbye");
    ??????? service.addUser("tracy", "morning");
    ??????? System.out.println("tom\'s password is: " + service.getPassword("tom"));
    ??????? if(service.findUser("tom")) {
    ??????????? service.deleteUser("tom");
    ??????? }
    ??? }
    }

    執(zhí)行結(jié)果:
    src=uppic/20060407/1405271.jpg

    3.在Spring中配置Bean并獲得Bean的實(shí)例

    我們已經(jīng)在一個(gè)main方法中實(shí)現(xiàn)了業(yè)務(wù),不過,將對象的生命周期交給容器管理是更好的辦法,我們就不必為初始化對象和銷毀對象進(jìn)行硬編碼,從而獲得更大的靈活性和可測試性。

    想要把ServiceBean交給Spring來管理,我們需要一個(gè)XML配置文件。新建一個(gè)beans.xml,放到src目錄下,確保在classpath中能找到此配置文件,輸入以下內(nèi)容:

    <?xml version=1.0 encoding=UTF-8?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
    "http://www.springframework.org/dtd/spring-beans.dtd">
    <beans>
    ??? <bean id="service" class="com.crackj2ee.example.spring.MyServiceBean" />
    </beans>

    以上XML聲明了一個(gè)id為service的Bean,默認(rèn)地,Spring為每個(gè)聲明的Bean僅創(chuàng)建一個(gè)實(shí)例,并通過id來引用這個(gè)Bean。下面,我們修改main方法,讓Spring來管理業(yè)務(wù)Bean:

    /**
    ?* Copyright_2006, Liao Xuefeng
    ?* Created on 2006-3-9
    ?* For more information, please visit:
    http://www.crackj2ee.com
    ?*/
    package com.crackj2ee.example.spring;
    import org.springframework.beans.factory.xml.XmlBeanFactory;
    import org.springframework.core.io.ClassPathResource;
    public class Main {
    ??? public static void main(String[] args) throws Exception {
    ??????? // init factory:
    ??????? XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("beans.xml"));
    ??????? // use service bean:
    ??????? ServiceBean service = (ServiceBean)factory.getBean("service");
    ??????? service.addUser("bill", "hello");
    ??????? service.addUser("tom", "goodbye");
    ??????? service.addUser("tracy", "morning");
    ??????? System.out.println("tom\'s password is \\" + service.getPassword("tom") + "\\");
    ??????? if(service.findUser("tom")) {
    ??????????? service.deleteUser("tom");
    ??????? }
    ??????? // close factory:
    ??????? factory.destroySingletons();
    ??? }
    }

    執(zhí)行結(jié)果:
    ?src=uppic/20060407/1405272.jpg

    由于我們要通過main方法啟動(dòng)Spring環(huán)境,因此,首先需要初始化一個(gè)BeanFactory。紅色部分是初始化Spring的BeanFactory的典型代碼,只需要保證beans.xml文件位于classpath中。

    然后,在BeanFactory中通過id查找,即可獲得相應(yīng)的Bean的實(shí)例,并將其適當(dāng)轉(zhuǎn)型為合適的接口。

    接著,實(shí)現(xiàn)一系列業(yè)務(wù)操作,在應(yīng)用程序結(jié)束前,讓Spring銷毀所有的Bean實(shí)例。

    對比上一個(gè)版本的Main,可以看出,最大的變化是不需要自己管理Bean的生命周期。另一個(gè)好處是在不更改實(shí)現(xiàn)類的前提下,動(dòng)態(tài)地為應(yīng)用程序增加功能。

    4.編寫Advisor以增強(qiáng)ServiceBean

    所謂AOP即是將分散在各個(gè)方法處的公共代碼提取到一處,并通過類似攔截器的機(jī)制實(shí)現(xiàn)代碼的動(dòng)態(tài)織入。可以簡單地想象成,在某個(gè)方法的調(diào)用前、返回前、調(diào)用后和拋出異常時(shí),動(dòng)態(tài)插入自己的代碼。在弄清楚Pointcut、Advice之類的術(shù)語前,不如編寫一個(gè)最簡單的AOP應(yīng)用來體驗(yàn)一下。

    考慮一下通常的Web應(yīng)用程序都會(huì)有日志記錄,我們來編寫一個(gè)LogAdvisor,對每個(gè)業(yè)務(wù)方法調(diào)用前都作一個(gè)記錄:

    /**
    ?* Copyright_2006, Liao Xuefeng
    ?* Created on 2006-3-9
    ?* For more information, please visit:
    http://www.crackj2ee.com
    ?*/
    package com.crackj2ee.example.spring;
    import java.lang.reflect.Method;
    import org.springframework.aop.MethodBeforeAdvice;
    public class LogAdvisor implements MethodBeforeAdvice {
    ??? public void before(Method m, Object[] args, Object target) throws Throwable {
    ??????? System.out.println("[Log] " + target.getClass().getName() + ". "+ m.getName() + "()");
    ??? }
    }

    然后,修改beans.xml:

    <?xml version=1.0 encoding=UTF-8?>
    <!DOCTYPE beans PUBLIC -//SPRING//DTD BEAN//EN
    http://www.springframework.org/dtd/spring-beans.dtd>
    <beans>
    ??? <bean id="serviceTarget" class="com.crackj2ee.example.spring.MyServiceBean" />
    ??? <bean id="logAdvisor" class="com.crackj2ee.example.spring.LogAdvisor" />
    ??? <bean id="service" class="org.springframework.aop.framework.ProxyFactoryBean">
    ??????? <property name="proxyInterfaces"><value>com.crackj2ee.example.spring.ServiceBean</value></property>
    ??????? <property name="target"><ref local="serviceTarget/></property>
    ??????? <property name="interceptorNames">
    ??????????? <list>
    ??????????????? <value>logAdvisor</value>
    ??????????? </list>
    ??????? </property>
    ??? </bean>
    </beans>

    注意觀察修改后的配置文件,我們使用了一個(gè)ProxyFactoryBean作為service來與客戶端打交道,而真正的業(yè)務(wù)Bean即MyServiceBean被聲明為serviceTarget并作為參數(shù)對象傳遞給ProxyFactoryBean,proxyInterfaces指定了返回的接口類型。對于客戶端而言,將感覺不出任何變化,但卻動(dòng)態(tài)加入了LogAdvisor,關(guān)系如下:
    ?src=uppic/20060407/1405273.jpg

    運(yùn)行結(jié)果如下,可以很容易看到調(diào)用了哪些方法:
    ?src=uppic/20060407/1405274.jpg

    要截獲指定的某些方法也是可以的。下面的例子將修改getPassword()方法的返回值:

    /**
    ?* Copyright_2006, Liao Xuefeng
    ?* Created on 2006-3-9
    ?* For more information, please visit:
    http://www.crackj2ee.com
    ?*/
    package com.crackj2ee.example.spring;
    import org.aopalliance.intercept.MethodInterceptor;
    import org.aopalliance.intercept.MethodInvocation;
    public class PasswordAdvisor implements MethodInterceptor {
    ??? public Object invoke(MethodInvocation invocation) throws Throwable {
    ??????? Object ret = invocation.proceed();
    ??????? if(ret==null)
    ??????????? return null;
    ??????? String password = (String)ret;
    ??????? StringBuffer encrypt = new StringBuffer(password.length());
    ??????? for(int i=0; i<password.length(); i++)
    ??????????? encrypt.append("\'*\'");
    ??????? return encrypt.toString();
    ??? }
    }

    這個(gè)PasswordAdvisor將截獲ServiceBean的getPassword()方法的返回值,并將其改為***。繼續(xù)修改beans.xml:

    <?xml version=1.0 encoding=UTF-8?>
    <!DOCTYPE beans PUBLIC -//SPRING//DTD BEAN//EN
    http://www.springframework.org/dtd/spring-beans.dtd>
    <beans>
    ??? <bean id="serviceTarget" class="com.crackj2ee.example.spring.MyServiceBean" />
    ??? <bean id="logAdvisor" class="com.crackj2ee.example.spring.LogAdvisor" />
    ??? <bean id="passwordAdvisorTarget" class="com.crackj2ee.example.spring.PasswordAdvisor" />
    ??? <bean id="passwordAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    ??????? <property name="advice">
    ??????????? <ref local="passwordAdvisorTarget"/>
    ??????? </property>
    ??????? <property name="patterns">
    ??????????? <list>
    ??????????????? <value>.*getPassword</value>
    ??????????? </list>
    ??????? </property>
    ??? </bean>
    ??? <bean id="service" class="org.springframework.aop.framework.ProxyFactoryBean">
    ??????? <property name="proxyInterfaces"><value>com.crackj2ee.example.spring.ServiceBean</value></property>
    ??????? <property name="target"><ref local="serviceTarget"/></property>
    ??????? <property name="interceptorNames">
    ??????????? <list>
    ??????????????? <value>logAdvisor</value>
    ??????????????? <value>passwordAdvisor</value>
    ??????????? </list>
    ??????? </property>
    ??? </bean>
    </beans>

    利用Spring提供的一個(gè)RegexMethodPointcutAdvisor可以非常容易地指定要截獲的方法。運(yùn)行結(jié)果如下,可以看到返回結(jié)果變?yōu)?*****:
    ?src=uppic/20060407/1405275.jpg

    還需要繼續(xù)增強(qiáng)ServiceBean?我們編寫一個(gè)ExceptionAdvisor,在業(yè)務(wù)方法拋出異常時(shí)能做一些處理:

    /**
    ?* Copyright_2006, Liao Xuefeng
    ?* Created on 2006-3-9
    ?* For more information, please visit:
    http://www.crackj2ee.com
    ?*/
    package com.crackj2ee.example.spring;
    import org.springframework.aop.ThrowsAdvice;
    public class ExceptionAdvisor implements ThrowsAdvice {
    ??? public void afterThrowing(RuntimeException re) throws Throwable {
    ??????? System.out.println("[Exception]" + re.getMessage());
    ??? }
    }

    將此Advice添加到beans.xml中,然后在業(yè)務(wù)Bean中刪除一個(gè)不存在的用戶,故意拋出異常:

    service.deleteUser("not-exist");

    再次運(yùn)行,注意到ExceptionAdvisor記錄下了異常:
    ?src=uppic/20060407/1405276.jpg

    5.總結(jié)

    利用Spring非常強(qiáng)大的IoC容器和AOP功能,我們能實(shí)現(xiàn)非常靈活的應(yīng)用,讓Spring容器管理業(yè)務(wù)對象的生命周期,利用AOP增強(qiáng)功能,卻不影響業(yè)務(wù)接口,從而避免更改客戶端代碼。

    為了實(shí)現(xiàn)這一目標(biāo),必須始終牢記:面向接口編程。而Spring默認(rèn)的AOP代理也是通過Java的代理接口實(shí)現(xiàn)的。雖然Spring也可以用CGLIB實(shí)現(xiàn)對普通類的代理,但是,業(yè)務(wù)對象只要沒有接口,就會(huì)變得難以擴(kuò)展、維護(hù)和測試。



    歡迎大家訪問我的個(gè)人網(wǎng)站 萌萌的IT人

    posted on 2006-04-21 10:41 見酒就暈 閱讀(166) 評(píng)論(0)  編輯  收藏 所屬分類: SPRING

    <2025年7月>
    293012345
    6789101112
    13141516171819
    20212223242526
    272829303112
    3456789

    導(dǎo)航

    統(tǒng)計(jì)

    常用鏈接

    留言簿(3)

    我參與的團(tuán)隊(duì)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    收藏夾

    BLOG

    FRIENDS

    LIFE

    搜索

    最新評(píng)論

    閱讀排行榜

    評(píng)論排行榜

    主站蜘蛛池模板: 久久久久久一品道精品免费看| 亚洲熟女精品中文字幕| 久久亚洲精品成人777大小说| 国产精品亚洲A∨天堂不卡| 亚洲无码精品浪潮| 内射干少妇亚洲69XXX| 亚洲黄色激情视频| 久久er国产精品免费观看2| 最近最新MV在线观看免费高清| 国产一区二区免费在线| 国产精品国产亚洲精品看不卡| 亚洲av日韩av无码av| 成人网站免费大全日韩国产| 成人免费大片免费观看网站| 日本一道本高清免费| 国产av天堂亚洲国产av天堂| 国内精品免费视频精选在线观看| 国产亚洲成AV人片在线观黄桃 | va天堂va亚洲va影视中文字幕| 国产成人精品免费视频大全麻豆 | jizz免费在线观看| 免费阿v网站在线观看g| 国产V亚洲V天堂无码久久久| 久久青草免费91线频观看不卡 | 国产1024精品视频专区免费| 亚洲区日韩精品中文字幕| 九九精品成人免费国产片| 久久久久久亚洲AV无码专区| 日韩一区二区a片免费观看 | 国产精品免费久久| 亚洲av激情无码专区在线播放| 亚洲免费一级视频| 无码色偷偷亚洲国内自拍| 亚洲精品视频免费看| 国产v亚洲v天堂无码网站| 日本三级2019在线观看免费| 香蕉97碰碰视频免费| 热99re久久精品精品免费| 亚洲一区免费视频| 免费在线观看你懂的| 亚洲jizzjizz少妇|