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

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

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

    無線&移動互聯網技術研發

    換位思考·····
    posts - 19, comments - 53, trackbacks - 0, articles - 283
      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

    Spring IOC/DI/注解-理論與實例并存

    Posted on 2010-05-27 00:04 Gavin.lee 閱讀(2472) 評論(0)  編輯  收藏 所屬分類: SSH2 --Spring

    一、定義Spring 是一個開源的控制反轉(Inversion of Control,IoC/DI)和面向切面(AOP)的容器框架,它的主要目的是簡化企業開發

    二、實例化Spring容器:

        方法一:在類路徑下尋找配置文件來實例化容器

    ApplicationContext ctx =

    new ClassPathXmlApplicationContext(new String[]{“beans.xml”});

        方法二:在文件系統路徑下尋找配置文件來實例化容器

    ApplicationContext ctx =

    new FileSystemXmlApplicationContext(new String[]{“d:""beans.xml”});

    注:文件可指定多個

    可建立單元測試來測試Spring容器的初始化

    三、編寫Spring 配置文件時,不能出現幫助信息的解決辦法添加schema文件

    由于Springschema文件位于網絡上,如果機器不能連接到網絡,那么在寫配置文件的時候就無法出現提示信息,解決辦法有兩種:

    1. 讓機器上網,Eclipse會自動從網絡上下載schema文件并緩存在硬盤上

    2手動添加schema文件,方法如下:

    windows->preferences->myeclipse->files and editors->xml->xmlcatalog

    a. 我們可以選擇將schema文件放到User Specified Entries然后點擊‘add’,在出現的窗口中的Key Type中選擇URL ‘Location’中選擇‘File System’,然后在Spring解壓目錄的dist/resources目錄中選擇spring-beans-2.5.xsd

    b. 回到設置窗口時候不要急于關閉窗口,應把窗口中的Key Type改為schema location

    c. key改為:

    http://www.springframework.org/schema/beans/spring-beans-2.5.xsd

    四、Spring 配置文件一個小插曲

    <bean id=”” name=””></bean>,在這里,id name都是為這個bean取的名字,其實這兩者意思相同,只是如果選擇使用的是id,那么id命名則不能有特殊字符,如果使用的是name則可以使用特殊字符作為name。如

    <bean id=”beanId” /> && <bean name=”bean-name”/>

    五、Spring容器如何管理bean

    首先讀取beans.xml里的bean配置所有的idclass的值,作為String形式保存至對應一個Bean,形成bean列表

    利用反射機制,將bean列表遍歷,生成對象,如下:

    package junit.test;

    import java.net.URL;

    import java.util.ArrayList;

    import java.util.HashMap;

    import java.util.HashSet;

    import java.util.List;

    import java.util.Map;

    import org.dom4j.Document;

    import org.dom4j.Element;

    import org.dom4j.XPath;

    import org.dom4j.io.SAXReader;

    /**

     *傳智傳客版容器

     *

     */

    publicclass ItcastClassPathXMLApplicationContext {

        private List<BeanDefinition> beanDefines = new ArrayList<BeanDefinition>();

        private Map<String, Object> sigletons = new HashMap<String, Object>();

       

        public ItcastClassPathXMLApplicationContext(String filename){

            this.readXML(filename);

            this.instanceBeans();

        }

        /**

         *完成bean的實例化

         */

        privatevoid instanceBeans() {

            for(BeanDefinition beanDefinition : beanDefines){

                try {

                    if(beanDefinition.getClassName()!=null && !"".equals(beanDefinition.getClassName().trim()))

                        sigletons.put(beanDefinition.getId(), Class.forName(beanDefinition.getClassName()).newInstance());

                } catch (Exception e) {

                    e.printStackTrace();

                }

            }

        }

        /**

         *讀取xml配置文件

         *@paramfilename

         */

        privatevoid readXML(String filename) {

            SAXReader saxReader = new SAXReader();

            Document document = null;

            try {

                URL xmlpath = this.getClass().getClassLoader().getResource(filename);

                document = saxReader.read(xmlpath);

                Map<String, String> nsMap = new HashMap<String, String>();

                nsMap.put("ns", "http://www.springframework.org/schema/beans");// 加入命名空間

                XPath xsub = document.createXPath("http://ns:beans/ns:bean");// 創建beans/bean查詢路徑

                xsub.setNamespaceURIs(nsMap);// 設置命名空間

                List<Element> beans = xsub.selectNodes(document);// 獲取文檔下所有bean節點

                for (Element element : beans) {

                    String id = element.attributeValue("id");// 獲取id屬性值

                    String clazz = element.attributeValue("class"); // 獲取class屬性值

                    BeanDefinition beanDefine = new BeanDefinition(id, clazz);

                    beanDefines.add(beanDefine);

                }

            } catch (Exception e) {

                e.printStackTrace();

            }

        }

        /**

         *獲取bean實例

         *@parambeanName

         *@return

         */

        public Object getBean(String beanName){

            returnthis.sigletons.get(beanName);

        }

    }

    六、Spring的三種實例化Bean方式

    1使用構造器實例化

    <bean id="personService" class="cn.itcast.service.impl.PersonServiceBean"></bean>

        這種就是利用默認的構造器進行的實例化

    2. 靜態工廠方法實例化

    <bean id="personService2" class="cn.itcast.service.impl.PersonServiceBeanFactory" factory-method="createPersonServiceBean"/>

    3. 使用實例工廠方法實例化

    <bean id="personServiceFactory" class="cn.itcast.service.impl.PersonServiceBeanFactory"/>

    <bean id="personService3" factory-bean="personServiceFactory" factory-method="createPersonServiceBean2"/>

    七、bean的作用域-屬性scope

    singleton:(默認)在每個Spring IOC容器中一個bean定義只有一個對象實例,默認情況下會在容器啟動時初始化bean。但我們可以指定bean節點lazy-init=”true” 則表示不需要在容器初始化時候對bean進行初始化,只有在第一次getBean時候進行初始化,如果需要所有的bean都應用延遲初始化,可以在根節點<beans>設置default-lazy-init=”true”(不推薦,不利于觀察bean初始化情況)

    prototype:每次從容器中獲取的bean都是新的對象

    request

    session

    global session

    七、Spring管理的bean的生命周期

    默認情況下容器初始化的時候對bean進行實例化

    如果scopeprototype時,在調用getBean方法時候對bean進行實例化

    如果lazy-inittrue時,容器初始化時候不會對bean進行實例化

    綜上所述,Spring管理的bean初始化點根據設定的條件不同而不同

    init-method:在bean被實例化的后即會執行的方法

    destroy-method:在bean被銷毀的時候執行的方法(如果沒有手動的銷毀該bean,則只有在容器關閉的時候才會銷毀)

    正常的關閉Spring容器

    AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");

    ctx.close();

    八、控制反轉IoC 定義:

    Public class PersonServiceBean {

    Private PersonDao personDao = new PersonDaoBean();

    Public void save (Person person) {

    personDao.save(person);

    }

    }

    PersonDaoBean是在應用內部創建和維護的,所謂的控制反轉就是應用本身不負責依賴對象的創建和維護,依賴對象的創建及維護是由外部容器負責的,這樣控制權就由應用轉移到了外部容器,控制權的轉移就是所謂的反轉。

    九、依賴注入(Dependency Injection)的定義:

    當我們把依賴對象交給外部容器負責創建,那么PersonServiceBean類可以改成如下:

    public class PersonServiceBean{

    private PersonDao personDao;

    //通過構造器參數,讓容器把創建好的依賴對象注入進PersonServiceBean,當然也可以使用setter方法進行注入

    public PersonServiceBean(PersonDao personDao) {

    this.personDao = personDao;

    }

    Public void save(Person person) {

    personDao.save(person);

    }

    }

    所謂的依賴注入就是指:在運行期,由外部容器動態地將依賴對象注入到組件中

    十、依賴注入:

    1.使用構造器注入

    private PersonDao personDao;

        private String name;   

        public PersonServiceBean(PersonDao personDao, String name) {

            this.personDao = personDao;

            this.name = name;

        }

    beans.xml配置:

    <bean id="personService" class="cn.itcast.service.impl.PersonServiceBean">

    <constructor-arg index="0" type="cn.itcast.dao.PersonDao" ref=""></constructor-arg>

        <constructor-arg index="1" type="paramValue"></constructor-arg>

    </bean>

    2.使用setter方法注入

    ref形式注入:

        <bean id="personService" class="cn.itcast.service.impl.PersonServiceBean">

            <property name="personDao" ref="personDaoBean" />

        </bean>

    可以采用內部bean方式進行注入,不同過ref方式的是,這種內部bean注入對于bean的重用性效果不好:

        <bean id="personService" class="cn.itcast.service.impl.PersonServiceBean">

            <property name="personDao">

                <bean class="cn.itcast.dao.impl.PersonDaoBean" />

            </property>

        </bean>

    bean基本類型的注入:

        <bean id="personService" class="cn.itcast.service.impl.PersonServiceBean">

            <property name="personDao">

                <bean class="cn.itcast.dao.impl.PersonDaoBean" />

            </property>

            <property name="name" value="itcast" />

            <property name="id" value="100" />

        </bean>

    集合類的注入:

    <bean id="personService" class="cn.itcast.service.impl.PersonServiceBean" >

            <property name="sets">

                <set>

                    <value>第一個</value>

                    <value>第二個</value>

                    <value>第三個</value>

                </set>

            </property>

            <property name="lists">

                <list>

                    <value>第一個list元素</value>

                    <value>第二個list元素</value>

                    <value>第三個list元素</value>

                </list>

            </property>

            <property name="properties">

                <props>

                    <prop key="key1">value1</prop>

                    <prop key="key2">value2</prop>

                    <prop key="key3">value3</prop>

                </props>

            </property>

            <property name="maps">

                <map>

                    <entry key="key-1" value="value-1" />

                    <entry key="key-2" value="value-2" />

                    <entry key="key-3" value="value-3" />

                </map>

            </property>

    </bean>

    3.使用Field注入(用于注解方式)

    注入依賴對象,可以采用手工裝配或者自動裝配,在實際應用中建議使用手工裝配,因為自動裝配會產生未知情況,開發人員無法預見最終裝配的結果

    1.     手工裝配依賴對象

    a)       xml配置文件中,通過在bean節點下配置

    b)       java代碼中使用@Autowired@Resource注解方式進行裝配。但我們需要在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"      

           xsi:schemaLocation="http://www.springframework.org/schema/beans         

    http://www.springframework.org/schema/beans/spring-beans-2.5.xsd

    http://www.springframework.org/schema/context

    >

    <!-- 相當于啟用解析注解的處理器 -->

    <context:annotation-config/>

    </beans>

    這個配置隱式注冊了多個注釋進行解析處理的處理器:

    注解本身不做任何事情,只是利用這些處理器來達到配置一樣的效果

    AutowiredAnnotationBeanPostProcessor,

    CommonAnnotationBeanPostProcesor,

    PersistenceAnnotationBeanPostProcessor,

    RquiredAnnotationBeanPostProcessor

    注:@Resource注解在spring安裝目錄的lib/j2ee/common-annotations.jar

    jar文件:

    dist/spring.jar

    lib/Jakarta-commons/commons-logging.jar

    lib/aspectjaspectjweaver.jaraspectjrt.jar//aop

    lib/cglib/cglib-nodep-2.1_3.jar

    lib/j2ee/common-annotations.jar

    java代碼中使用@Autowired@Resource注解方式進行裝配,這兩個注解的區別是:

    @Autowired默認按類型裝配,@Resource默認按照名稱裝配,當找不到與名稱匹配的bean才會匹配的bean才會按類型裝配

    @Autowired

    private PersonDao personDao;    //用于字段上

    @Autowired

    public void setOrderDao(OrderDao orderDao) {    //用于屬性的setter方法上

        this.orderDao = orderDao;

    }

    @Autowired注解是按類型裝配依賴對象,默認情況下它要求依賴對象必須存在,如果允許null值,可以設置它required屬性為false(默認是true),如果我們想按名稱裝配,可以結合@Qualifier注解一起使用,如下:

    @Autowired @Qualifier(“personDaoBean”)

    private PersonDao personDao;

    如上面的注解,則@Autowired本身是按照類型裝配,現在將會按名稱裝配

    @Resource注解和@Actowired一樣,也可以標注在字段或者屬性的setter方法上,但他默認按照名稱裝配。名稱可以通過@Resourcename屬性指定,如果沒有指定name屬性,當注解標注在字段上,即默認取字段的名稱作為bean名稱尋找依賴對象,當注解標注在屬性的setter方法上,即默認取屬性名作為bean名稱尋找依賴對象。

    @Resource(name=”personDaoBean”)

    private PersonDao personDao;

    注意:如果沒有指定name屬性,并且暗號默認的名稱仍然找不到依賴對象時,“Resource注解會回退到按類型裝配,但一旦指定了name屬性,就只能按名稱裝配了

    2.自動裝配依賴對象

    對于自動裝配,作為了解

    byType:按類型裝配,可以根據屬性的類型,在容器中尋找跟該類型匹配的bean。如果發現多個,那么將會拋出異常。如果沒有找到,即屬性值為null

    byName:按名稱裝配,可以根據屬性的名稱在容器中尋找跟該屬性名相同的bean,如果沒有找到,即屬性值為null

    constructorbyType的方式類似,不同之處在于它應用于構造器參數。如果在容器中沒有找到與構造器參數類型一致的bean,那么將會拋出異常

    autodetect:通過bean類的自省機制(introspection)來決定是使用constructor還是byType方式進行自動裝配。如果發現默認的構造器,那么將使用byType方式

    十一、依賴注入的原理

    Spring容器管理bean原理的實例中進行改造,該例子涉及到兩個實體類:BeanDefinition{id,class}PropertyDefinition{name,ref}

    package junit.test;

    import java.beans.IntrospectionException;

    import java.beans.Introspector;

    import java.beans.PropertyDescriptor;

    import java.lang.reflect.Method;

    import java.net.URL;

    import java.util.ArrayList;

    import java.util.HashMap;

    import java.util.List;

    import java.util.Map;

    import org.dom4j.Document;

    import org.dom4j.Element;

    import org.dom4j.XPath;

    import org.dom4j.io.SAXReader;

    /**

     *傳智傳客版容器

     *

     */

    publicclass ItcastClassPathXMLApplicationContext {

        private List<BeanDefinition> beanDefines = new ArrayList<BeanDefinition>();

        private Map<String, Object> sigletons = new HashMap<String, Object>();

       

        public ItcastClassPathXMLApplicationContext(String filename){

            this.readXML(filename);

            this.instanceBeans();

            this.injectObject();

        }

        /**

         *bean對象的屬性注入值

         */

        privatevoid injectObject() {

            for(BeanDefinition beanDefinition : beanDefines){

                Object bean = sigletons.get(beanDefinition.getId());

                if(bean!=null){

                    try {

                        PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();

                        for(PropertyDefinition propertyDefinition : beanDefinition.getPropertys()){

                            for(PropertyDescriptor properdesc : ps){

                                if(propertyDefinition.getName().equals(properdesc.getName())){

                                    Method setter = properdesc.getWriteMethod();//獲取屬性的setter方法 ,private

                                    if(setter!=null){

                                        Object value = sigletons.get(propertyDefinition.getRef());

                                        setter.setAccessible(true);

                                        setter.invoke(bean, value);//把引用對象注入到屬性

                                    }

                                    break;

                                }

                            }

                        }

                    } catch (Exception e) {

                    }

                }

            }

        }

        /**

         *完成bean的實例化

         */

        privatevoid instanceBeans() {

            for(BeanDefinition beanDefinition : beanDefines){

                try {

                    if(beanDefinition.getClassName()!=null && !"".equals(beanDefinition.getClassName().trim()))

                        sigletons.put(beanDefinition.getId(), Class.forName(beanDefinition.getClassName()).newInstance());

                } catch (Exception e) {

                    e.printStackTrace();

                }

            }

           

        }

        /**

         *讀取xml配置文件

         *@paramfilename

         */

        privatevoid readXML(String filename) {

               SAXReader saxReader = new SAXReader();  

                Document document=null;  

                try{

                 URL xmlpath = this.getClass().getClassLoader().getResource(filename);

                 document = saxReader.read(xmlpath);

                 Map<String,String> nsMap = new HashMap<String,String>();

                 nsMap.put("ns","http://www.springframework.org/schema/beans");//加入命名空間

                 XPath xsub = document.createXPath("http://ns:beans/ns:bean");//創建beans/bean查詢路徑

                 xsub.setNamespaceURIs(nsMap);//設置命名空間

                 List<Element> beans = xsub.selectNodes(document);//獲取文檔下所有bean節點

                 for(Element element: beans){

                    String id = element.attributeValue("id");//獲取id屬性值

                    String clazz = element.attributeValue("class"); //獲取class屬性值       

                    BeanDefinition beanDefine = new BeanDefinition(id, clazz);

                    XPath propertysub = element.createXPath("ns:property");

                    propertysub.setNamespaceURIs(nsMap);//設置命名空間

                    List<Element> propertys = propertysub.selectNodes(element);

                    for(Element property : propertys){                 

                     String propertyName = property.attributeValue("name");

                     String propertyref = property.attributeValue("ref");

                     PropertyDefinition propertyDefinition = new PropertyDefinition(propertyName, propertyref);

                     beanDefine.getPropertys().add(propertyDefinition);

                    }

                    beanDefines.add(beanDefine);

                 }

                }catch(Exception e){  

                    e.printStackTrace();

                }

        }

        /**

         *獲取bean實例

         *@parambeanName

         *@return

         */

        public Object getBean(String beanName){

            returnthis.sigletons.get(beanName);

        }

    }

    Spring 開發的好處

    a)       降低組件之間的耦合度,實現軟件各層之間的解耦

     Controller -- Service -- Dao

    b) 可是使用容器提供的眾多服務

    可使用容器提供的眾多服務:事務管理服務(事務傳播,無需手工控制事務)、JMS服務、Spring core核心服務、持久化服務、其他……

    c) 容器提供單例模式支持,開發人員不再需要自己編寫實現代碼

    d) 容器提供了AOP技術,利用它狠容易實現如權限攔截,運行期監控等功能

    e) 容器提供了眾多的輔助類,使用這些類,能夠加快應用的開發,如:Jdbc TemplateHibernate Template

    f) Spring 對于主流的應用框架提供了集成支持,如:集成HibernateJPAStruts等,這樣更便于應用的開發

    十三、 Spring DI配置文件減肥(Spring2.0 –Spring2.5的升級)

    1@Resource注解

    2.注解使Spring 自動掃描和管理bean

    掃描路徑:<context:component-scan base-package=”cn.itcast” />,將會掃描該包下包括其子包的類

    @Component:泛指組件、當組件不好歸類的時候,我們可以使用這個注解進行標注

    @Service:用于標注業務層組件

    @Controller:用于標注控制層組件(如struts中的action

    @Repository:用于標注數據訪問組件,即DAO組件

    此時bean默認的名稱為類全名首寫字母小寫,也可指定bean名稱,如

    @Service(“personService”)

    下面有幾個例子:

    service組件的注解

    package cn.itcast.service.impl;

    import javax.annotation.PostConstruct;

    import javax.annotation.PreDestroy;

    import org.springframework.stereotype.Service;

    import cn.itcast.dao.PersonDao;

    import cn.itcast.service.PersonService;

    @Service("personService") @Scope("prototype")    //這樣可以修改bean作用域

    public class PersonServiceBean implements PersonService {

        //@Autowired(required=false) @Qualifier("personDaoxxxx")

        private PersonDao personDao;

       

        //初始化bean時會執行該方法的注解(ejb3中同樣應用)

        @PostConstruct

        public void init(){

            System.out.println("初始化");

        }

       

        //銷毀bean之前會執行該方法的注解(ejb3中同樣應用)

        @PreDestroy

        public void destory(){

            System.out.println("開閉資源");

        }

       

        public void setPersonDao(PersonDao personDao) {

            this.personDao = personDao;

        }

        public void save(){

            personDao.add();

        }

    }

    dao組件的注解

    package cn.itcast.dao.impl;

    import org.springframework.stereotype.Repository;

    import cn.itcast.dao.PersonDao;

    @Repository

    public class PersonDaoBean implements PersonDao {

        public void add(){

            System.out.println("執行PersonDaoBean中的add()方法");

        }

    }

    小結:@PostConstruct @PreDestroy的補充

    Spring 容器中的 Bean 是有生命周期的,Spring 允許在 Bean 在初始化完成后以及 Bean 銷毀前執行特定的操作,您既可以通過實現 InitializingBean/DisposableBean 接口來定制初始化之后 / 銷毀之前的操作方法,也可以通過 <bean> 元素的 init-method/destroy-method 屬性指定初始化之后 / 銷毀之前調用的操作方法

    使用時只需要在方法前標注 @PostConstruct @PreDestroy,這些方法就會在 Bean 初始化后或銷毀之前被 Spring容器執行了,我們知道,不管是通過實現 InitializingBean/DisposableBean 接口,還是通過 <bean> 元素的 init-method/destroy-method 屬性進行配置,都只能為 Bean 指定一個初始化 / 銷毀的方法。但是使用 @PostConstruct @PreDestroy 注釋卻可以指定多個初始化 / 銷毀方法,那些被標注 @PostConstruct @PreDestroy 注釋的方法都會在初始化 / 銷毀時被執行。

    主站蜘蛛池模板: 精品成人一区二区三区免费视频| 亚洲人成人无码网www国产| 1区2区3区产品乱码免费| 日本免费在线观看| 久久精品视频免费播放| 欧洲人成在线免费| 久久午夜伦鲁片免费无码| 污视频在线观看免费| 最近中文字幕2019高清免费| 91成人在线免费观看| 男女免费观看在线爽爽爽视频| 91黑丝国产线观看免费| 成人a视频片在线观看免费| 色www永久免费视频| 免费看国产一级片| 国产成人精品亚洲精品| 亚洲熟妇无码八AV在线播放| 亚洲VA中文字幕不卡无码| 亚洲美女视频免费| 亚洲最大的成人网站| 男女超爽视频免费播放| 亚洲精品偷拍视频免费观看| 波多野结衣免费一区视频| 最好看最新的中文字幕免费 | 亚洲第一香蕉视频| 亚洲国产日韩精品| 曰批免费视频播放在线看片二 | 欧洲 亚洲 国产图片综合| 亚洲精华国产精华精华液| 菠萝菠萝蜜在线免费视频| 精品无码一级毛片免费视频观看 | 日本中文字幕免费看| a级成人毛片免费图片| **真实毛片免费观看| 国产在线国偷精品产拍免费| 亚洲国产成人爱av在线播放| 久久国产亚洲电影天堂| 国产亚洲玖玖玖在线观看| 免费无码AV一区二区| 小日子的在线观看免费| 全免费a级毛片免费看无码|