Spring配置

Spring:

--1 使用jar包:
spring.jar
commons-logging.jar

使用aop
aspectjweaver.jar
aspectjrt.jar
cglib-nodep-2.1_3.jar

使用註解:
common-annotations.jar


--2 實例化容器:

ApplicationContext ctx =
new ClasspathXmlApplicationContext("applicationContext.xml");

ApplicationContext context=
new FileSystemXmlApplicationContext(new String[]{"d:\\beans.xml"});

--3 使用ContextLoaderListener
從ServletContext取得web.xml中初始化的ApplicationContext

首先在web.xml中配置listener。

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath*:spring/*.xml</param-value>
</context-param>
<listener>
    <listener-class>
     org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>
            

然後從ServletContext中獲得ApplicationContext。

ApplicationContext context =
WebApplicationContextUtils.getWebApplicationContext(application);          

對於無法獲得ServletContext的環境,最好自定義一個listener,
將生成的ApplicationContext放入一個單例中,以便日後使用。

--Spring配置要點:
(1) 在xml中使用spring-2.x的DTD。

   <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
   "http://www.springframework.org/dtd/spring-beans-2.0.dtd">

   相比schema真是方便了很多,這樣可以在必須使用特定schema的時候,再讓他重裝上陣。

   spring-2.x中去掉了singleton屬性,使用scope屬性做替代。
   如果還想使用singleton屬性,必須配置成spring-1.x格式的DTD。

   提示:
   spring中已不再推薦使用singleton屬性,因爲單例在多jvm,
   遠程調用,集羣的情況下難以掌控,還是爲實例指明生存的scope比較好。

(2)default-lazy-init

   懶惰加載,系統啓動的時候並不加載xml中定義的bean,
   而是等到實際調用的時候纔去加載,這樣可以縮短系統初始化時間,
   在測試系統部分功能的情況下有極大的好處。

   注意,PropertityPlaceHolderConfigurer,springmvc,
   xfire,quartz等的配置文件不能聲明爲懶惰加載,否則會出問題。

(3) default-autowire="byName"
    按名稱自動綁定。設置了這個,只要定義bean的時候名稱與需要綁定的屬性名相同,
    在實例化對象的時候,spring就會將這些實例自動綁定,
    不需要再去聲明綁定哪些property。減少xml代碼量,使得結構更清晰。

    在使用compass的時候要注意,不能使用按名稱自動綁定,
    會自動爲compass綁定dataSource導致錯誤。

(4) import  (????)
    將xml統一放在classpath下,這樣更有利於進行單元測試,
    對於多個模塊的xml使用import進行導入,層次更清晰。

    <import resource="classpath:jbpm/applicationContext-jbpm4.xml"/>
            
(5) CharacterEncodingFilter
    spring提供的編碼過濾器,好處一是不用自己動手寫了,
    好處二是保證每次請求只過濾一次。配置如下:(web.xml)

    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>
        org.springframework.web.filter.CharacterEncodingFilter
        </filter-class>
        <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
            

(6) IntrospectorCleanupListener
    spring提供的監聽器,避免Struts,Quartz的內存泄露導致ClassLoader不能加載。
    配置如下:(web.xml)

    <listener>
    <listener-class>
    org.springframework.web.util.IntrospectorCleanupListener
    </listener-class>
    </listener>
            

(5) PropertyPlaceholderConfigurer
   讀取properties中的變量,在xml中可以通過${變量名}的方式調用。配置如下:

    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
        <list>
            <value>classpath*:conf/jdbc.properties</value>
        </list>
        </property>
    </bean>

   <bean id="userManager" class="com.family168.manager.UserManager">
        <property name="username" value="${jdbc.username}"/>
   </bean>

  解析:jdbc.properties文件,內有對應的(key)username配置。

(6)PropertyOverrideConfigurer

   與PropertyPlaceholderConfigurer不同,
   PropertyOverrideConfigurer會在ApplicationContext初始化後,
   根據properties中的定義,修改對應屬性的值。

   配置如下:

   <bean id="testPropertyConfigurer" class="org.springframework.beans.factory.config.PropertyOverrideConfigurer">
       <property name="locations" value="classpath*:override.properties"/>
       <property name="ignoreInvalidKeys" value="true"/>
   </bean>
            

    用來在測試環境下覆蓋已有的配置,比如在override.properties中
    有userManager.username=111,那麼id="userManager"的bean的username屬性
    就會被修改爲111。


(7)  Spring-2.x對AOP和事務管理的簡化配置:

    1. 首先要使用schema

    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:tx="http://www.springframework.org/schema/tx"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
                
     
    2.然後要聲明標記(不知道是不是必要的)

    <!-- 支持annotation @Transactional 標記 -->
    <tx:annotation-driven/>

    <!-- 支持annotation @AspectJ 標記-->
    <aop:aspectj-autoproxy/>

    3. 配置aop

    <aop:config proxy-target-class="true">
        <aop:advisor pointcut="execution(* com.family168.manager..*Manager.*(..))" advice-ref="txAdvice"/>
    </aop:config>
                
    注意:
    name-pattern千萬不要寫成*..*Manager ,
    這樣子會把所有第三方類庫的Manager比如Spring的PlatformTranstationManager
    也加入aop,非常危險。所以最好還是加上項目的package前綴,
    如"com.family168.manager..*Manager"

    因爲有*,會修飾所有方法,有些hibernateTemplate的final的方法不能被cglib修改,
    會拋warning,無害。事務定義一般默認的PROPAGATION_REQUIRED即可,
    另提供的幾個選擇很少使用。值得注意的是一個PROPAGATION_NESTED,
    嵌入式事務的意義在於多級事務,如果出錯只rollback子事務自己,不rollback主事務的所有操作。
    這需要JDBC3.0 SavePoint功能的支持。 而一般service間互相嵌入調用時,
    如果都定義爲PROPAGATION_REQUIRED,有其中一個操作出錯,rollback全部操作。
----------------
    4  配置txAdvice處理事務

    <tx:advice id="txAdvice">
        <tx:attributes>
        <tx:method name="get*" read-only="true"/>
        <tx:method name="find*" read-only="true"/>
        <tx:method name="pagedQuery*" read-only="true"/>
        <tx:method name="load*" read-only="true"/>
        <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>
                
    解析:

    tx這個命名空間會要求咱們提供一個名字爲transactionManager的bean,用這個來作爲默認的事務管理器。
    Spring參考文檔 7.3 chema-based AOP support 提供了aspect,advisor,advide三種組裝方法的解釋,
    其中aspect是aspectJ原裝,但稍複雜,這裏唯一有點難懂的是pointcut裏的語法,其實也很好學,
    Spring參考文檔7.2.3.4裏有完整說明 ,其實一排子過去是:
    
   

     execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)
         throws-pattern?)

    modifiers-pattern:(public/protected)  可以不填
    ret-type-pattern:返回值可任意
    declaring-type-pattern 可以不填
    name-pattern  路徑
    param-pattern  參數
    throws-pattern    可以不填

     eg1:
    //返回值任意,com.family168.manager路徑下的,類名結尾爲Manager類的任意參數類型方法
    * com.family168.manager..*Manager.*(..)
   
    eg2:
    execution(* *..BookManager.save(..))
    第一顆* //ret-type-pattern 返回值可任意,


    eg2:
    *..*Manager //任意Package裏的以Manager結尾的類。
    
    eg3:
    如果寫成com.xyz.service.* //com.xyz.service下的任意類

    eg4:
    com.xyz.service..* com.xyz.service//com.xyz.service及其子package下的任意類

    save代表save方法,也可以寫save* 代表saveBook()等方法

    (..) 匹配0個參數或者多個參數的,任意類型

    (x,..) 第一個參數的類型必須是X

    (x,*,*,s,..) 匹配至少4個參數,第一個參數必須是x類型,
    第二個和第三個參數可以任意,第四個必須是s類型。
    
--------------------
(8) Spring中的零配置

    其實也不是完全的零配置,我們需要在xml中制定規範,然後在java中使用註解進行標註。

    首先要在xml中配置如下標記:

    <context:component-scan base-package="com.family168.manager" />
        

    這裏需要使用Spring的schema命名空間進行配置,例子中使用的是springside中提供的例子,
    指定了默認在哪個包下查找需要進行注入的類。在Service類中使用@Service註釋,
    Dao類中使用@Repository註釋,通過pacakge掃描加入Spring的applicationContext。

    在私有屬性或注入方法(不需要嚴格按setter命名)上 使用@Autowired 註釋 進行byType注入,
    如果需要byName注入,增加@Qualifier註釋。另@auwowired默認隱含了@Required特性

    使用@Required註釋非@Autowired的屬性,保證autowired下對象必然被注入,
    如果對象沒有被注入則報錯。使用JSR250的@PostConstruct來定義在執行完
    所有setter注入後必須執行的函數,比以往的實現接口或者在applicationContext.xml中
    配置init-method的方式更爲標準。

    爲提高效率,還是需要在xml中默認配置default-lazy-load和default-autowire byName。
                 
------------------------
(9)  Spring中的資源訪問(????)

    1.  ResourceLoader
    ResourceLoader 可以獲得ClassPath, File,URL中的文件,返回類型爲Resource的統一資源定義。
    ApplicationContext中就擁有ResourceLoader。
    實現resourceLoaderAware接口可以獲得ResourceLoader。

    2. ResourcePatternResolver
    ResourcePatternResolver 是ResourceLoader的升級版子接口,能解決ant-style的文件模糊批量定義,
    如applicationContext-*.xml。

    ApplicationContext中的ResourceLoader其實是ResourcePatternResolver ,
    可以通過強制轉型獲得,友好一點的做法是使用ResourcePatternUtils來轉換。

    public class RescManager implements InitializingBean, BeanNameAware,
        ResourceLoaderAware {
        private ResourceLoader resourceLoader;

        public void demo() throws IOException {
        ResourcePatternResolver resolver = ResourcePatternUtils
            .getResourcePatternResolver(resourceLoader);
        Resource[] rescs = resolver.getResources(
            "classpath*:spring/applicationContext*.xml");
        System.out.println(rescs);
        }
    }
            
-------------------------------
(10)Spring的微內核與FactoryBean擴展機制
 1. 微內核的功能
  1.1. DI(依賴注入)與Singleton管理

    利用POJO setter的DI機制,估計每位同學隨手都能寫一個簡單版本,不多說了。
    Singleton管理說白了就是先到一個map中按id找找看有沒有已存在的實例。

  1.2. BeanName與BeanFactory注入

     除了DI注入的屬性,微內核還有什麼能賣給POJO呢?就是Bean在xml 定義裏的id和BeanFactory自己了。
     賣的機制是讓POJO 實現 BeanNameAware和BeanFactoryAware接口。
     BeanFactory用 if(pojo instance of BeanFactoryAware)判斷到POJO需要注入BeanFactory,
     就調用setBeanFactory(this)將自己注入。

  1.3. DI後的初始化函數調用

     比如屬性A,B注入之後,需要同時根據A和B來對A,B進行加工或者裝配一個內部屬性C,
     這樣就需要在所有屬性注入後再跑一個init()函數。

     Spring提供兩種方式:
     一種是和上面的原理一樣,實現InitializingBean接口的afterPropertiesSet()函數供Spring調用。
     一種是在xml定義文件裏面自行定義init函數名。

    懶得每次在xml文件裏定義的就採用第1種方式,不想與spring耦合的pojo就採用第2種方式。
    本來就是爲了擴展Spring而存在的FactoryBean多采用第一種。

    所謂微內核,就是僅提供以上三種功能的DI容器。
    但作爲輕量級容器,還需要以下兩種方式,向容器內的POJO 附加各種服務。

 2. FactoryBean擴展機制

Spring的AOP、ORM、事務管理、JMX、Quartz、Remoting、Freemarker、Velocity,
都靠FacotryBean的擴展,FacotryBean幾乎遍佈地上:

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"/>
<bean id="baseDAOService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"/>
            

這原理說出來好簡單,所有FactoryBean 實現FactoryBean接口的getObject()函數。
Spring容器getBean(id)時見到bean的定義是普通class時,就會構造該class的實例來獲得bean,
而如果發現是FactoryBean接口的實例時,就通過調用它的getObject()函數來獲得bean,
僅此而以.......可見,很重要的思想,可以用很簡單的設計來實現。


 3. Bean Post-Processor擴展機制(???)

如果說FactoryBean 是一種Factory、Wrapper式的擴展,
Bean Post-Processor就是另一種AOP、visitor式的機制,所以也多用於spring的AOP架構。

Post-Processor的原理就是BeanFactory在前文裏的調用afterPropertiesSet()/init-method前後,
調用在工廠裏註冊了的post-processor的postProcessBeforeInitialization()和postProcessAfterInitialization()。

那怎麼註冊登記呢?又分請不請禮儀公司兩類。
如果是ApplicationContext,你把繼承BeanPostProcessor 的bean往xml裏一擱就行了,
application context自會打理。如果是BeanFacotry,就要顯式的註冊,代碼大概像:

XmlBeanFactory factory = new XmlBeanFactory("C:/beans.xml");
BeanPostLogger logger = new BeanPostLogger();
factory.addBeanPostProcessor(logger);
            
           
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章