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

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

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

    ALL is Well!

    敏捷是一條很長的路,摸索著前進著

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      30 隨筆 :: 23 文章 :: 71 評論 :: 0 Trackbacks
    當我們在使用Spring進行開發時,我們經常使用占位符引用屬性文件的屬性值來簡化我們的配置及使我們的配置具有更高的靈活性和通用性。
    使用這種方式的好處這里就不贅述了,這里要講的是怎樣對此外部屬性文件的屬性值進行加密、解密。
    以下是我們熟悉的配置:jdbc.properties
    driver=oracle.jdbc.OracleDriver
    dburl
    =jdbc:oracle:thin:@127.0.0.1:1521:root
    username
    =myusr
    password
    =mypassword

    applicationContext.xml
        <bean id="propertyConfigurer"
            class
    ="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
            
    <property name="locations">
                
    <list>      
                    
    <value>classpath:jdbc.properties</value>
                
    </list>
            
    </property>
            
    <property name="fileEncoding" value="utf-8"/>
        
    </bean> 
        
    <bean id="proxoolDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
            
    <property name="driverClassName" value="${driver}" />
            
    <property name="url" value="${dburl}" />
            
    <property name="username" value="${username}" /> 
            
    <property name="password" value="${password}" />
        
    </bean>


    但當我們配置一個應用的時候,假設打成myapp.jar文件,并不希望將一些配置文件一同打在jar里。
    原因是:
    有的配置文件要經常改動,例如:由于環境的不同,數據庫的連接信息要經常變動,出于安全方面的考慮,密碼要經常變換。
    一旦配置文件有了修改,就要停止myapp.jar程序,重新打包,再啟動myapp.jar,這樣無疑對于維護人員來說是很杯具的。

    如果我們將配置文件放在myapp.jar外面,那么每次修改配置文件后,只要重啟myapp.jar即可。

    在配置一些敏感屬性的時候(例如密碼等),需要對其進行加密。
    我們期望看到的jdbc.properties的內容是這樣的:

    jdbc.properties
    driver
    =oracle.jdbc.OracleDriver
    dburl
    =jdbc:oracle:thin:@127.0.0.1:1521:root
    username
    =myusr
    password
    ={3DES}VwHsU01hJOqskgCppbmTXg==
    對password屬性值進行3DES加密(這里提供了對加密方式的配置),其他的屬性值不變。
    既達到了安全的效果,又讓配置清晰明了。

    好了,讓我們開始來實現我們的需求吧。
    我們從org.springframework.beans.factory.config.PropertyPlaceholderConfigurer這個類入手。
    因為之前我們都是用這個類來完成對外部屬性文件的引用的。
    讀了一下這個類的代碼,沒發現能入手的地方,繼續找它的父類。
    最終,PropertiesLoaderSupport.java 這個抽象類被我們發現了。其中的loadProperties方法便是我們的入口。
    看此方法的注釋大意是:加載屬性到已給出的實例(翻譯的很白癡,汗)。
    原來Spring先是生成一個Properties的實例,然后通過這個loadProperties方法,將屬性的鍵值對設置到該實例中。該實例相當于一個籃子,進入方法時,是一個空籃子,待方法返回時,將籃子裝滿。
    以下請看代碼,對該段代碼進行簡單理解:

        /**
         * Load properties into the given instance.
         * 
    @param props the Properties instance to load into
         * 
    @throws java.io.IOException in case of I/O errors
         * 
    @see #setLocations
         
    */

        
    protected void loadProperties(Properties props) throws IOException {
            
    if (this.locations != null{
                
    for (int i = 0; i < this.locations.length; i++// 遍歷屬性文件列表
                    Resource location = this.locations[i]; // 取得一個屬性文件句柄
                    if (logger.isInfoEnabled()) {
                        logger.info(
    "Loading properties file from " + location);
                    }

                    InputStream is 
    = null;
                    
    try {
                        is 
    = location.getInputStream();
                        
    if (location.getFilename().endsWith(XML_FILE_EXTENSION)) // 判斷該屬性文件是否為.xml文件
                            this.propertiesPersister.loadFromXml(props, is);   // 此處略過,我們只考慮.properties文件
                        }

                        
    else {
                            
    if (this.fileEncoding != null// 加載屬性文件 入口1
                                this.propertiesPersister.load(props, new InputStreamReader(is, this.fileEncoding));
                            }

                            
    else {  // 加載屬性文件 入口2
                                this.propertiesPersister.load(props, is);
                            }

                        }

                    }

                    
    catch (IOException ex) {
                        
    if (this.ignoreResourceNotFound) {
                            
    if (logger.isWarnEnabled()) {
                                logger.warn(
    "Could not load properties from " + location + "" + ex.getMessage());
                            }

                        }

                        
    else {
                            
    throw ex;
                        }

                    }

                    
    finally {
                        
    if (is != null{
                            is.close();
                        }

                    }

                }

            }

        }

    在入口1、入口2處實現load接口的是org.springframework.util.DefaultPropertiesPersister.java。
    分別看一下這兩個方法:
    1.void load(Properties props, Reader reader) // 入口1分支
    2.load(Properties props, InputStream is)     // 入口2分支

    先看入口2的方法吧,因為它將是被我們淘汰的方法。原因是它不適合我們改造
    以下是入口load方法的實現:
        public void load(Properties props, InputStream is) throws IOException {
            props.load(is); 
    // props為java.util.Properties對象。
        }

    props為java.util.Properties對象,所以想要在這里做文章會比較麻煩。

    所以我選擇入口1.

    public void load(Properties props, Reader reader) throws IOException {
            
    if (loadFromReaderAvailable) {
                
    // On JDK 1.6+
                props.load(reader); // 入口3
            }

            
    else {
                
    // Fall back to manual parsing.
                doLoad(props, reader); // 入口4
            }

        }

    入口3也被放棄,理由同放棄入口2。
    讓我們看看入口4的具體實現:
        protected void doLoad(Properties props, Reader reader) throws IOException {
            BufferedReader in 
    = new BufferedReader(reader);
            
    while (true{
                String line 
    = in.readLine();
                
    if (line == null{
                    
    return;
                }

                line 
    = StringUtils.trimLeadingWhitespace(line);
                
    if (line.length() > 0{
                    
    char firstChar = line.charAt(0);
                    
    if (firstChar != '#' && firstChar != '!'{
                        
    while (endsWithContinuationMarker(line)) {
                            String nextLine 
    = in.readLine();
                            line 
    = line.substring(0, line.length() - 1);
                            
    if (nextLine != null{
                                line 
    += StringUtils.trimLeadingWhitespace(nextLine);
                            }

                        }

                        
    int separatorIndex = line.indexOf("=");
                        
    if (separatorIndex == -1{
                            separatorIndex 
    = line.indexOf(":");
                        }

                        
    // 從這里開始便是我們要改造的地方了。
                        
    // 得到value后,我們將value進行解密,然后再裝到props這個籃子里。
                        String key = (separatorIndex != -1 ? line.substring(0, separatorIndex) : line);
                        String value 
    = (separatorIndex != -1? line.substring(separatorIndex + 1) : "";
                        key 
    = StringUtils.trimTrailingWhitespace(key);
                        value 
    = StringUtils.trimLeadingWhitespace(value);
                        props.put(unescape(key), unescape(value));
                    }

                }

            }

        }


    知道了要改造的地方,那么我們寫代碼吧。
    新建類:DecryptPropertyPlaceholderConfigurer.java繼承 PropertyPlaceholderConfigurer.java
    新建類:DecryptPropertiesPersister.java繼承DefaultPropertiesPersister.java

    由于
    locations、propertiesPersister、fileEncoding、ignoreResourceNotFound 這些變量在抽象類PropertiesLoaderSupport.java中并沒有提供set方法。
    所以我們在DecryptPropertyPlaceholderConfigurer.java聲明這些成員變量并將父類的覆蓋。

    其中propertiesPersister變量用我們寫的DefaultPropertiesPersister類來實現。
    具體代碼:
    DecryptPropertyPlaceholderConfigurer.java

    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.util.Properties;

    import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
    import org.springframework.core.io.Resource;

    public class DecryptPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {
        
    private Resource[]                 locations;
        
    private DecryptPropertiesPersister propertiesPersister    = new DecryptPropertiesPersister();
        
    private String                     fileEncoding = "utf-8";
        
    private boolean                    ignoreResourceNotFound = false;

        @Override
        
    public void setLocations(Resource[] locations) {
            
    this.locations = locations;
        }


        @Override
        
    public void setFileEncoding(String encoding) {
            
    this.fileEncoding = encoding;
        }


        @Override
        
    public void setIgnoreResourceNotFound(boolean ignoreResourceNotFound) {
            
    this.ignoreResourceNotFound = ignoreResourceNotFound;
        }


        @Override
        
    public void loadProperties(Properties props) throws IOException {
            
    if (this.locations != null{
                
    for (int i = 0; i < this.locations.length; i++{
                    Resource location 
    = this.locations[i];
                    InputStream is 
    = null;
                    
    try {
                        is 
    = location.getInputStream();
                        
    if (location.getFilename().endsWith(XML_FILE_EXTENSION)) {
                            
    this.propertiesPersister.loadFromXml(props, is);
                        }
     else {
                            
    this.propertiesPersister.doLoad(props, new InputStreamReader(is,
                                
    this.fileEncoding));
                        }

                    }
     catch (IOException ex) {
                        
    if (this.ignoreResourceNotFound) {
                            
    if (logger.isWarnEnabled()) {
                                logger.warn(
    "Could not load properties from " + location + ""
                                    
    + ex.getMessage());
                            }

                        }
     else {
                            
    throw ex;
                        }

                    }
     finally {
                        
    if (is != null{
                            is.close();
                        }

                    }

                }

            }

        }

    }

    DecryptPropertiesPersister.java
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.Reader;
    import java.util.Properties;

    import org.springframework.util.DefaultPropertiesPersister;
    import org.springframework.util.StringUtils;

    public class DecryptPropertiesPersister extends DefaultPropertiesPersister {
        @Override
        
    protected void doLoad(Properties props, Reader reader) throws IOException {
            BufferedReader in 
    = new BufferedReader(reader);
            
    while (true{
                String line 
    = in.readLine();
                
    if (line == null{
                    
    return;
                }

                line 
    = StringUtils.trimLeadingWhitespace(line);
                
    if (line.length() == 0{
                    
    continue;
                }

                
    char firstChar = line.charAt(0);
                
    if (firstChar != '#' && firstChar != '!'{
                    
    while (endsWithContinuationMarker(line)) {
                        String nextLine 
    = in.readLine();
                        line 
    = line.substring(0, line.length() - 1);
                        
    if (nextLine != null{
                            line 
    += StringUtils.trimLeadingWhitespace(nextLine);
                        }

                    }

                    
    int separatorIndex = line.indexOf("=");
                    
    if (separatorIndex == -1{
                        separatorIndex 
    = line.indexOf(":");
                    }

                    String key 
    = (separatorIndex != -1 ? line.substring(0, separatorIndex) : line);
                    String value 
    = (separatorIndex != -1? line.substring(separatorIndex + 1) : "";
                    key 
    = StringUtils.trimTrailingWhitespace(key);

            
    // 從這里開始,我們要關注了。
                    value = StringUtils.trimLeadingWhitespace(value);
                    
    // 對加密的屬性進行3DES解密
                    value = decrypt("key", value);// 解密方法略 密鑰配置的方法略
                    props.put(unescape(key), unescape(value));
                }

            }

        }

        
        
    private String decrypt(String key, String str) {
            
    if(org.apache.commons.lang.StringUtils.isEmpty(str)) {
                
    return "";
            }

            
    // 解密方法
            if(key.startsWith("{3DES}")) {
                
    // 解密 略
            }
     
            
    return str;
        }

    }

    修改applicationContext.xml文件如下:
        <bean id="propertyConfigurer"
            
    class="com.jn.spring.DecryptPropertyPlaceholderConfigurer">
            
    <property name="locations">
                
    <list>      
                    
    <value>classpath:jdbc.properties</value>
                
    </list>
            
    </property>
            
    <property name="fileEncoding" value="utf-8"/>
        
    </bean> 
        
    <bean id="proxoolDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
            
    <property name="driverClassName" value="${driver}" />
            
    <property name="url" value="${dburl}" />
            
    <property name="username" value="${username}" /> 
            
    <property name="password" value="${password}" />
        
    </bean>

    這樣就完成了。在Spring進行加載的時候,debug看看是否解析對了就OK了。

    注:由于這里主要講解的是如果通過擴展Spring而實現對外部屬性文件的屬性值進行加密,而不是介紹加密解密方法,所以關于加密解密方法略。
    google一下到處都是。

    本文為原創,歡迎轉載,轉載請注明出處BlogJava。

    posted on 2010-09-30 14:34 李 明 閱讀(2744) 評論(0)  編輯  收藏 所屬分類: Spring
    主站蜘蛛池模板: 韩国日本好看电影免费看| 永久在线免费观看| 免费jlzzjlzz在线播放视频| 亚洲免费电影网站| 日本免费网址大全在线观看| 亚洲精品韩国美女在线| ww在线观视频免费观看| 亚洲国产日韩综合久久精品| 久久精品女人天堂AV免费观看| 日韩亚洲国产高清免费视频| 大陆一级毛片免费视频观看| 亚洲AV无码一区二区一二区| a毛片全部免费播放| 黄色一级视频免费观看| 亚洲av永久无码精品国产精品| 亚洲视频在线观看| 精品久久久久亚洲| 亚洲成人高清在线| a视频在线观看免费| 亚洲视频在线观看一区| 操美女视频免费网站| 一级毛片完整版免费播放一区| 国产AV无码专区亚洲AV漫画| 午夜精品一区二区三区免费视频 | 国产色无码精品视频免费| 亚洲第一福利网站| 成人免费视频小说| 国产无遮挡又黄又爽免费网站| 亚洲视频在线观看视频| 免费看又爽又黄禁片视频1000 | 免费高清国产视频| 亚洲人成激情在线播放| 亚洲av午夜成人片精品电影| 久艹视频在线免费观看| 国产精品亚洲专区在线观看| 亚洲精品乱码久久久久久不卡| 亚洲中文字幕无码av| 免费在线观看视频a| 99re这里有免费视频精品 | 亚洲国产av一区二区三区丶| 免费国产高清视频|