標籤: 南投搬家

  • 如何提高web應用的吞吐量

    如何提高web應用的吞吐量

    這篇博文所列舉的優化手段是針對比較傳統項目,但是想提高系統的吞吐量現在時髦的技術還是那些前後端未分離, 使用nginx當成靜態資源服務器去代理我們的靜態資源

    是誰限制了Throughput?

    當我們對一個傳統的項目進行壓力測試時,很容器就發現,系統的Throughput被數據庫(mysql)限制的死死的,儘管代碼看起來確實沒毛病,邏輯也沒有錯誤,但是過多的請求都被打向了數據庫,數據庫自個開啟大量的IO操作,這樣大的負載甚至會使Linux系統的整體負載驟然飆升,但是反觀我們的系統的吞吐量,呵呵…

    將目光投向緩存

    既然mysql的抗壓能力限制了我們的系統,那就將數據緩存起來,盡一切可能減少用戶和數據庫之間的直接接觸的次數,這樣我們的系統的吞吐量,同一時間能處理器的請求數量自然會升上去

    市面上的緩存技術很多, 比較火爆的是兩款緩存數據庫 Memcache 和 Redis ,

    Redis 和 Memcahe的區別

    • Redis不僅僅支持key-value鍵值對類型的數據,同時還支持list,set,hash等數據結構
    • redis支持數據的備份,即master-slaver模式的集群備份
    • Redis是支持數據持久化的,它可以將內存中的數據保存在磁盤中,支持RDB和AOF兩種持久化形式

    對Redis進行壓測

    # 挨個測試redis中的命令
    # 每個數據包大小是3字節
    # 100個併發, 發起10萬次請求
    redis-benchmark -h 127.0.0.1 -p 6379 -c 100 -n 100000
    
    [root@139 ~]# redis-benchmark -h 127.0.0.1 -p 9997 -c 100 -n 100000
    ====== PING_INLINE ======
      100000 requests completed in 1.04 seconds
      100 parallel clients
      3 bytes payload
      keep alive: 1
    
    98.68% <= 1 milliseconds // 百分之98.68的請求在1毫秒內完成了
    99.98% <= 2 milliseconds 
    100.00% <= 2 milliseconds
    96525.09 requests per second  // 每秒完成的請求數在9萬六左右
    
    
    -d  指定數據包的大小,看下面redis的性能還是很強大的
    -q  簡化輸出的參數
    [root@139 ~]# redis-benchmark -h 127.0.0.1 -p 9997 -q -d 100 -c 100 -n 100000
    PING_INLINE: 98619.32 requests per second
    PING_BULK: 95877.28 requests per second
    SET: 96153.85 requests per second
    GET: 95147.48 requests per second
    INCR: 95238.10 requests per second
    LPUSH: 95328.88 requests per second
    RPUSH: 95877.28 requests per second
    LPOP: 95328.88 requests per second
    RPOP: 97276.27 requests per second
    SADD: 96339.12 requests per second
    HSET: 98231.83 requests per second
    SPOP: 94607.38 requests per second
    LPUSH (needed to benchmark LRANGE): 92165.90 requests per second
    LRANGE_100 (first 100 elements): 97181.73 requests per second
    LRANGE_300 (first 300 elements): 96153.85 requests per second
    LRANGE_500 (first 450 elements): 94428.70 requests per second
    LRANGE_600 (first 600 elements): 95969.28 requests per second
    MSET (10 keys): 98231.83 requests per second
    
    只測試 指定的命令
    -t 跟多個命令參數
    [root@139 ~]# redis-benchmark -p 9997 -t set,get -q -n 100000 -c 100 
    SET: 97276.27 requests per second
    GET: 98135.42 requests per second

    從上面的壓力測試中,可以看到,Redis的性能是絕對實力, 相當強悍,和mysql相比不是一個量級的, 所以結論很明顯,如果我們在用戶和mysql中鍵加一層redis做緩存,系統的吞吐量自然會上去

    於是為了提高系統的抗壓能力,我們將壓力從mysql逐步轉移到redis中

    頁面緩存技術

    在說頁面緩存之前,我們先說一下在一個傳統的項目中,一個請求的生命周期大概是這樣的: 從瀏覽器發出到服務端, 服務端查詢數據庫獲取結果, 再將結果數據傳遞給模板引擎將數據渲染進html頁面

    想提高這個過程的速度,我們可以這樣搞, 頁面緩存, 顧名思義就是將 html 頁面緩存到緩存數據庫中

    示例如下:

    一開始我們會先嘗試從緩存中獲取出已經渲染好的html源碼響應給客戶端, 響應的格式通過@ResponseBody和produces中的屬性進行控制,告訴瀏覽器自己會返回給它html文本

    優點: 將用戶的請求的壓力從mysql轉移到redis, 這點強度對redis單機來說根本不是事

    缺點: 很明顯,將請求擴大到頁面級別,數據一致性難免會受到影響, 這也是使用頁面緩存不得不考慮的一點

    特點1 : 嚴格控制緩存的時間, 一定別忘了添加過期時間…

    特點2 : 原來都是讓thymeleaf自動完成數據的渲染,現在的話,很明顯是我們手動在渲染數據

        @RequestMapping(value = "/to_list",produces = "text/html;charset=UTF-8")
        @ResponseBody
        public String toLogin(Model model, User user, HttpServletResponse response, HttpServletRequest request) {
    
            // 先從redis緩存中獲取數據
            String html = redisService.get(GoodsKey.goodsList, "", String.class);
            if (html != null)
                return html;
    
            // 查詢商品列表
            List<GoodsVo> goodsList = goodsService.getGoodsList();
            model.addAttribute("goodsList", goodsList);
    
            // 使用Thymeleaf模板引擎手動渲染數據
            WebContext springWebContext = new WebContext(request,response,request.getServletContext(),request.getLocale(),model.asMap());
            String goods_list = thymeleafViewResolver.getTemplateEngine().process("goods_list", springWebContext);
    
            // 存入redis
            if (goods_list!=null){
                redisService.set(GoodsKey.goodsList,"",goods_list);
            }
            return goods_list;
        }

    既然都說到這裏了, 就接着說還能怎麼玩吧…

    你看, 上面通過手動控制模板引擎的api竟然得到的已經渲染好的html源代碼了, 什麼叫做已經渲染好的? 說白了就是原來我在前端寫:th ${user},這樣的佔位符,現在已經被thymeleaf替換成了 張三 … (說的夠直接吧)

    拿到了已經渲染好的源代碼,我們就能通過IO操作,將這個文件寫到系統的某個目錄上去,不知道大家有沒有發現,去逛京東淘寶瀏覽某個商品頁面時,就會發現url是類似這樣的 www.jjdd.com/aguydg/ahdioa/1235345.html

    這個後綴123145.html 大概率說明京東使用靜態頁的技術, 這太明智了,面對如此巨大數量的商品信息後綴用数字來表示也不錯,而且速度還快不是?

    怎麼實現這種效果呢?

    就是上面說的,通過IO將這些源碼的數據寫到Linux中的某一個目錄下面, 文件名就是上面URL中的最後的数字, 通過Nginx做靜態資源服務器將這些xxx.html代理起來, 用戶再訪問的話就走這個靜態頁, 同樣不會接觸數據庫, 而且nginx還支持零拷貝,併發數5萬不是事…
    還有,後綴數組最好也別亂寫,直接使用商品id會更好,畢竟是先點擊商品獲取到id,再進入到靜態頁

    對象緩存技術

    緩存java中的對象, 比如將用戶的信息持久化進redis, 每次用戶查詢自己的信息先從redis中查詢,有的話直接返回,沒有的話再去查詢數據庫, 這樣同樣實現了在用戶和數據庫之間多添加出一層緩存,也可以大大的提高系統的吞吐量

    一般會怎麼玩呢?

    用戶的請求在查詢數據庫之前先嘗試從redis中獲取對象信息, redis中不存在的話就去數據庫中查詢, 查詢完結果后將這個結果換存進redis

    // todo 使用redis做緩存,減少和數據庫的接觸次數
    public Label findById(Long labelId) {
    
        // 先嘗試從緩存中查詢當前對象
        Label label = (Label) redisTemplate.opsForValue().get("label_id" + labelId);
    
        if (label==null){
            Optional<Label> byId = labelRepository.findById(labelId);
            if (!byId.isPresent()) {
                // todo 異常
            }
            label = byId.get();
    
            // 將查出的結果存進緩存中
            redisTemplate.opsForValue().set("label_id"+label.getId(),label);
        }
        return label;
    }

    當用戶update數據 ,先更新數據庫,再刪除/更新redis中響應的緩存

    public void update(Long labelId, Label label) {
        label.setId(labelId);
        Label save = labelRepository.save(label);
    
        // todo 數據庫修改成功后, 將緩存刪除
        redisTemplate.delete("label_id"+save.getId());
        }

    當用戶刪除數據,先刪除數據庫中的數據,再刪除redis中的緩存

    public void delete(Long labelId) {
        labelRepository.deleteById(labelId);
    
        // todo 數據庫修改成功后, 將緩存刪除
        redisTemplate.delete("label_id"+labelId);
    }

    模仿Vue實現頁面靜態化

    大家都在說頁面靜態化, 它真的有那麼神奇嗎? 其實也沒有那麼神奇, 說白了吧,傳統的網頁上的數據是通過模板引擎渲染上去的,(比如JSP或者是說thymeleaf這類模板引擎), 做了靜態化的網頁中數據的渲染通過js完成, 而且這個網頁和項目中的 靜態資源比如js,css 這類的文件放在一個目錄下面, 地位和普通的靜態資源相同, 還有個好處就是, 瀏覽器給的福利, 因為瀏覽器對靜態資源是有緩存的, 如果你善於觀察,就會發現有時候重複請求某個網頁,網頁正常显示,但是狀態碼是304… 請求依然會到達服務端,但是服務端會告訴瀏覽器它想訪問的頁面其實沒有變化, 於是瀏覽器就找到本地的緩存使用

    時下國內 最火爆的玩靜態頁面時下最火爆的技術就是 Angular.js 以及 Vue.js , 也確實好用, 前幾個月我寫過有關vue的筆記, 感興趣的同學可以去看看

    在本篇博客中恰恰好沒用到VUE, 但是實現靜態頁的思路和vue是大差不差的, 同樣是通過js代碼實現頁面的靜態化

    • 首先說後端的代碼怎麼寫?

    前後端分離嘛, 自然是json交互,後端通過@ResponseBody控制返回給前端json對象, 而且, 推薦大家也整一個VO對象,用這個VO對象將各式各樣的數據封裝在一起,一次性返回給前端, 這樣看上去,後端確實是簡單,也就是返回一個json對象

    • 前端怎麼寫呢?

    第一件事就是將html文件從template文件夾下move到static文件夾下面, 讓這個html文件和js/css文件稱兄道弟

    然後是給這個xxx.html該名字, 為啥要改名換目錄呢? 因為SpringBoot是約定大於編碼的, 在什麼目錄下面就是什麼文件, 此外Thymeleaf部分默認的配置信息如下

    @ConfigurationProperties(prefix = "spring.thymeleaf")
    public class ThymeleafProperties {
    
        private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;
    
        public static final String DEFAULT_PREFIX = "classpath:/templates/";
    
        public static final String DEFAULT_SUFFIX = ".html";
    

    沒辦法,這些配置信息默認就認為類路徑下的templates中都是xxx.html的文件

    第二件事是將html標籤中引入的類似thymeleaf這中命名空間都去掉,靜態頁不需要

    <!DOCTYPE HTML>
    <html xmlns:th="http://www.thymeleaf.org">
    <head>
        <title>商品列表</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <!-- jquery -->
        <!--<script type="text/javascript" th:src="@{/js/jquery.min.js}"></script>-->
        <script type="text/javascript" th:src="js/jquery.min.js"></script>

    第三件事寫一個ajax,當頁面一加載就觸發向後台發請求,獲取數據, 通過jQuery操作各個節點完成數據的渲染

    三步打完收工, 看上也不是很複雜, 但是我們的頁面就是已然成為了靜態頁面, 從此她會被瀏覽器緩存起來,只要這個頁面不發生變動,瀏覽器就會一直使用自己的緩存,在網絡上的數據傳輸量有多帶勁自己腦補,系統RT絕對飆升幾個數量級

    靜態資源的優化手段

    說一下市面上常見的靜態資源優化技術吧:

    • js/css 的壓縮與優化,減少流量
    • 多個js/css組合在一起,減少連接數量
    • Tengine 技術
    • webPack , 使用vue開發時,它就會將一整套vue的依賴打包一個js一個html文件,豈不是爽歪歪?
    • CDN加速技術, 很多雲服務廠商都有提供,而且價格也不貴,將體型大的靜態資源放在CDN上進行加速也是不錯的選擇
    • 使用Nginx做靜態資源代理,而且Nginx就支持零拷貝,還支持將數據文件壓縮后在網絡上傳輸 ,自身的併發量也很強大,當靜態資源服務器它絕對是不二首選, 相信我,你會愛上它的

    另外當多個用戶併發修改庫存時,竟然將庫存修改成了負數, 本身使用的數據庫引擎是 innodb是存在行級鎖的, 我們只要修改一下我們的sql就行 加條件 and stock_number > 0

    為了防止同一個用戶發送兩次請求,偶爾秒殺到多個商品的情況,我們去miaosha_user表中去建立一個唯一的索引,將userId建立唯一索引,不允許相同的userId出現兩次,從而避免上述的情況

    驗證碼技術

    • 好處

    讓用戶去輸入驗證碼的好處有很多, 除了驗證用戶的身份信息之外, 最明顯的好處就是分散用戶對系統的壓力, 前端如果不添加圖片驗證碼的可能在1s內系統需要承載1萬併發, 但是添加了圖片驗證碼, 就能將這1萬併發分散到10秒以內,甚至更多

    • 整體的思路:

      圖片驗證碼不過是個image, 所以說前端想展示它,肯定需要一個img標籤, 一個比較不好想的地方是啥呢? 就是這個圖片的路徑,src=啥的問題, 我們可以怎麼做呢? 可以直接通過這個往src中寫入後端的生成imge的Controller的路徑, 每次刷新頁面,它就會往這個路徑中發起請求, Controller中去生成一個image, 通過HttpServletResponse的獲取到輸出流, 將生成的圖片用流的發送會瀏覽器,再加上他是img標籤,這不就ok了?

    百度一下如何生成圖片驗證碼一類的技術,確實真的很多,我就不貼代碼了, 感興趣的同學自行百度,代碼一片片的

    • 如何實現點擊圖片完成刷新操作呢?

    因為這種圖片是靜態資源,如果你不禁用緩存,這個圖片就會被緩存下來, 要想每次點擊圖片都實現更換驗證碼的話,參考下面的js實現, 添加時間戳

       function refreshImageCode() {
            $("#verifyCodeImg").attr("src","/path/verifyCode?goodsId="+$("#goodsId").val()+"&timestamp="+new Date());
        }

    接口限流技術

    • 什麼是接口限流?

    舉個例子: 如說我們想限制在一分鐘內單個用戶訪問 A Controller中的a方法的次數不能超過30次, 這其實就是一種接口限流的需求, 可以有效的防止用戶的惡意訪問

    • 如何實現接口限流呢?

    其實這件事結合緩存來實現並非是一件難事,比如我就用上面的例子: 不是想對a方法進行限流嗎? 我們就在a方法中添加下面的邏輯

    偽代碼如下:

    public void a(User user){
        // 校驗user合法性
        // 限流
       Integer count = redis.get(user.getId());
        if(count!=null&&count>15)
          return ; // 到達了指定的闋值,直接返回不允許繼續訪問
        if(count==null){
            redis.set(user.getId(),30,1); // 表示當前用戶訪問了1次, 當前key的有效時間為30s
        }else{
            redis.incr(user.getId());
        }
    }
    • 如何不讓限流的邏輯侵染業務代碼呢

    我們可以使用攔截器技術, 如果我們的重寫了攔截器的preHandler()方法,它就會在執行Controller中的方法前進行回調, 再配合自定義註解技術, 後面簡直就是為所以為…

    示例:

    @Component
    public class AccessIntercepter extends HandlerInterceptorAdapter {
        // 在方法執行之前進行攔截
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            if (handler instanceof HandlerMethod){
                HandlerMethod hd = (HandlerMethod) handler;
                LimitAccess methodAnnotation = hd.getMethodAnnotation(LimitAccess.class);
                if (methodAnnotation==null)
                    return true;
    
                // 解析註解
                int maxCount = methodAnnotation.maxCount();
                boolean needLogin = methodAnnotation.needLogin();
                int second = methodAnnotation.second();
                // todo
            }
            return true;
        }
    }

    結語: 最近又到考試周了,今個周六,下周三考試運籌學… 希望自己能平安度過…

    我是bloger 賜我白日夢, 歡迎點贊支持

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

    ※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

    ※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

    南投搬家前需注意的眉眉角角,別等搬了再說!

  • 美國環團告川普政府 不滿未考量台塑建廠風險

    摘錄自2020年1月16日中央社報導

    美國環保團體及社區組織今(15日)控告川普政府,抗議發放環境許可讓台灣塑膠公司在南部路易斯安那州建造塑膠廠區;根據計畫,這項建案規模達94億美元(約新台幣2837億元)。

    美聯社報導,這起向華盛頓聯邦法院提起的訴訟指控美國陸軍工兵署(US Army Corps of Engineers)未公開這項建廠計畫對環境造成的傷害及對公眾的健康風險,也未適當考量台灣塑膠公司給環境帶來的損害。

    位於紐奧良的環保團體「健康灣」(Healthy Gulf)是原告團體之一,執行主任沙爾托(Cyn Sarthou)在新聞稿中表示:「陸軍工兵署正加速發放許可給台塑,這家公司2019年因傾倒數十億顆塑膠粒到德州水道及墨西哥灣沿岸水域而被認定有罪,這完全令人無法接受。」

    根據訴訟文書,「健康灣」及其他團體成員擔心破壞濕地會傷害野生生物,讓鄰近地區面對洪澇更加脆弱;也擔心有毒排放物有害健康和環境,和貨車和駁船往來頻繁,會增加噪音、汙染及危險發生的機率。

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

    ※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

    ※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

    南投搬家前需注意的眉眉角角,別等搬了再說!

  • Uber響應環保 在中國大陸推出「電動車日」

    中國大陸霧霾嚴重,交通工具被視為兇手之一,故中央政府已開始推出電動車推廣政策,希望能減輕霾害問題。線上叫車業者Uber響應減碳,首度在北京、上海、廣州、成都等中國大陸的13個城市啟動「電動車日」,只要駕駛開電動車載客,就能享受額外獎勵。

    中國Uber表示,「電動車日」的活動是為了響應環保減碳而推出。叫車用戶可透過Uber叫車平台呼叫特斯拉、北汽新能源等電動車,或者豐田Corolla Hybrid或Levin等油電混和車。此外,在今年底前以電動車車款加入共乘的車主將可享有額外獎勵,將能鼓勵中國大陸民眾購置電動車。

    據統計,Uber上海平台上已有30%的車主駕駛電動車,Uber未來也將與更多電動車品牌合作,透過共乘與綠能發展計畫推廣環保。

    根據中新財經網報導,目前中國大陸汽車數量已達2.76億輛,所排放的廢氣對霾害影響甚大。若能以電動車取代燃油車,對於霾害會有正面幫助。中國大陸官方已陸續在各地推出電動公車,並祭出電動車補助措施以及產業補貼,希望能增加民眾採用電動車的比例。

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

    ※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

    ※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

    南投搬家前需注意的眉眉角角,別等搬了再說!

  • 痞子衡嵌入式:串行EEPROM接口事實標準及SPI EEPROM簡介

    痞子衡嵌入式:串行EEPROM接口事實標準及SPI EEPROM簡介

      大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家介紹的是EEPROM接口標準及SPI EEPROM

      痞子衡之前寫過一篇文章 ,介紹過并行NOR Flash基本概念。眾所周知,現如今嵌入式非易失性存儲器基本被NOR Flash一統江湖了,但在Flash技術發明之前,EEPROM才是非易失性存儲器的霸主。EEPROM的全稱是”電可擦除可編程只讀存儲器”,即Electrically Erasable Programmable Read-Only Memory,EEPROM技術的發明可是拯救過一大批嵌入式工程師的,畢竟在這之前非易失性存儲器技術的演進分別是ROM(只讀), PROM(只能寫一次), EPROM(紫外線可擦除),擦除方式都不太友好,直到EEPROM的出現才變得人性化。雖說現在Flash是主流,但在較低容量(2Mb以下)尤其是超低容量(1Kb以下)的市場,EEPROM仍然有其不可替代的應用場合。今天痞子衡就來好好聊一聊EEPROM:

    一、EEPROM背景簡介

      聊到EEPROM發展史,不得不提浮柵MOSFET,這是一項發明於1967年的技術,它是所有閃存的基礎。1970年,第一款成功的浮柵型器件-EPROM被發明。1979年,大名鼎鼎的SanDisk(閃迪)創始人Eli Harari,發明了世界上首個電可擦除的浮柵型器件即EEPROM。
      講到EEPROM必然要將它和與其相愛相殺的Flash一起對比。關於Flash大家都很熟悉,但其實Flash全稱應該叫Flash EEPROM,它屬於廣義的EEPROM。而本文主角EEPROM,指的是狹義的EEPROM,Flash和EEPROM最大的區別是:Flash按扇區操作,EEPROM按字節操作。Flash的特點是結構簡單,容量可以做得比較大且在大數據量下的操作速度更快,但缺點是操作過程麻煩,所以Flash適於當不需頻繁改寫的程序存儲器。而在有些應用中往往需要頻繁的改寫某些小量數據且需掉電非易失,傳統結構的EEPROM則非常適合。
      EEPROM不像NOR, NAND Flash技術演進得那麼複雜,因此實際上關於EEPROM並沒有成文的標準,即使最知名的电子行業標準之一JEDEC也沒有關於EEPROM的標準出台,不過各大廠商生產的EEPROM似乎都遵從某種約定的事實標準,這在後面介紹的EEPROM接口命令里顯得尤為明顯。

    二、Serial EEPROM原理

    2.1 Serial EEPROM分類

      從軟件驅動開發角度而言,Serial EEPROM可以從以下幾個方面進一步細分:

    地址碼長度:1byte / 2byte / 3byte
    通信接口類型:I2C / SPI / Microwire / UNIO Bus / Single-Wire

      本文的主要研究對象是SPI接口的EEPROM。

    2.2 SPI EEPROM內存模型

      EEPROM內存單元從大到小一般分為如下4層:Device、Sector、Page、Byte,其中Sector不是必有的,並且Page也只是個結構概念,跟NOR Flash里的Page/Sector意義不一樣,因為Byte就是EEPROM讀寫的最小單元(即可以任意地址隨機訪問),所以你可以把EEPROM當做一個非易失性的RAM。當然有些高端EEPROM中集成了Page/Sector操作命令,這隻是為了讓EEPROM操作效率更高而已。

    2.3 SPI EEPROM信號與封裝

      SPI EEPROM一般有8個腳,除去電源Vcc,地GND/Vss,以及SPI四根信號線(CS#, SCK, SI, SO)不言而喻之外,還有兩根特殊的控制信號,即WP#(寫保護)和HOLD#(掛起)。WP#信號主要是從硬件層面上對EEPROM內存進行保護,防止電路上的噪聲干擾篡改了EEPROM里的內容;而HOLD#則提供EEPROM寫操作暫停的功能,當該信號有效的時候,SI信號輸入將被忽略,因此主機可以做其他更高優先級的事情。

      SPI EEPROM雖然只有8pin,但是封裝種類還是比較齊全的,這其中最經典的當屬JEDEC定義的8-lead SOIC,此外還有TSSOP8, UDFN8, WLCSP8,下圖羅列了常見封裝:

    2.4 SPI EEPROM接口命令

    2.4.1 事實標準

      痞子衡在文章開頭的時候講過,SPI EEPROM並沒有什麼成文的接口命令標準,但是各大廠商生產的SPI EEPROM無一例外都支持下錶的6條命令,即READ(讀內存)、WRITE(寫內存)、WREN(寫使能)、WRDI(寫禁止)、RDSR(讀狀態寄存器)、WRSR(寫狀態寄存器),所以從軟件接口層面而言,這6條命令就是SPI EEPROM事實上的接口命令標準。

      除了6條標準命令外,SPI EEPROM內部還有一個8bit的狀態寄存器,用於反饋命令執行狀態,這8bit狀態寄存器的位定義也是存在如下錶所示的事實標準的:

      不考慮寫保護特性的話,bit0 – RDY#和bit1 – WEL是比較常用的,RDY#位主要用於標示所有涉及改變內存或狀態寄存器的命令的執行結果,WEL位則保存了上一次WREN和WRDI命令的執行結果。狀態寄存器中的其他兩處定義bit7 – WPEN, bit[3:2] – BP[1:0]則主要與寫保護特性有關,它們的具體作用如下:

    2.4.2 廠商個性化

      除了6條事實標準的命令外,有些廠商還實現了一些自定義的命令,這些命令並不一定通用,一般用於較大容量(3byte地址碼,512Kb以上)的EEPROM上。痞子衡找了一款非常經典的EEPROM,來自Microchip的25AA系列(25AA1024),讓我們看看它有啥個性化的命令。這顆EEPROM容量為1Mb,屬於大容量EEPROM,為了提高EEPROM操作效率,Microchip為這顆EEPROM增加了Page/Sector/Chip Erase命令,使得擦除操作效率變高了,如果沒有這些個性化擦除命令,那麼只能通過標準WRITE命令去手動實現擦除操作,既麻煩又低效。

    2.5 SPI EEPROM數據速率

      數據存取速率是個重要的技術指標,咱們來看看SPI EEPROM的讀寫時序,前面痞子衡在講EEPROM分類的時候提到過EEPROM地址碼有1byte/2byte/3byte之分,地址碼的區別主要體現了EEPROM讀寫時序上。對於讀時序,在SPI總線發完READ(0x03)命令后,緊接着要發送想要讀取的內存地址,地址碼不同,發送的地址字節數也不同。對於容量大於512Kb的EEPROM(即地址碼為3byte),顯然要發送3byte的地址,才能確定要讀的數據所在地址,然後才能進行讀數據操作。

      而對於容量小於等於512Kb的EEPROM,關於1byte和2byte地址碼區分,有一個特殊的設計,即對於512byte容量的EEPROM,按容量來說其屬於2byte地址碼範疇,READ命令后需要發送2byte地址,但實際上只需要發送1byte地址(A7-A0),而最高地址位A8放在了READ命令碼bit3里,這樣可以節省1個字節的地址碼。因此1Kb – 512Kb容量的EEPROM地址碼為2byte,512byte及以下容量的EEPROM地址碼為1byte,如下圖所示:

      從上面讀時序可以看出,READ命令碼和地址碼發完之後幾乎沒有等待周期,就可以直接讀取EEPROM中數據,因此EEPROM讀數據速率完全取決於SPI總線速率,所以我們只需要打開EEPROM數據手冊,看看它最高能支持多高的SPI總線速率即可(常見的有2MHz/5MHz/10MHz/20MHz)。
      對於寫時序,就稍微複雜一些了,這裏不考慮地址碼區別,以2byte地址為例。首先在發送WRITE命令之前需要發送一個WREN命令使能寫操作,因為默認EEPROM在執行完上一次寫操作後會恢複寫禁止狀態,在發送WRITE命令進行寫操作之前必須保證EEPROM處於寫使能狀態。

      確保EEPROM進入寫使能狀態后,開始發送WRITE命令,然後是地址碼,接着是要寫入的數據,痞子衡前面講過Page在EEPROM是個結構概念,但其實也跟WRITE命令有關,因為EEPROM既可以按byte去寫,也可以按Page去寫,如果需要存入連續的數據,顯然按Page去寫效率比按Byte寫入更高。這裏需要注意的是,WRITE命令後面跟的字節數不能超過要寫入的首地址所在Page剩餘的字節數。下圖示例的Page寫時序最大byte數為16/32,是因為示例EEPROM的page size即16/32 byte。

      當一次WRITE時序內要寫入的數據全部發送完成之後,底下便進入等待周期,與READ時序不同的是,WRITE時序有等待周期,因為EEPROM內部要將緩存在page buffer里的數據編程到真正的內存空間里,這需要時間。用戶只能通過不斷地發送如下RDSR命令去讀取狀態寄存器bit0 – RDY#來判斷WRITE等待周期是否結束。因此寫時序速率不僅僅取決於SPI總線速率,還取決於等待周期時長。

      如果想快捷地了解SPI EEPROM的性能,最簡單的就是打開SPI EEPROM手冊,看首頁的feature介紹,如下是25AA080的簡要feature:

    • Max. Clock 10 MHz
    • 1024 x 8-bit Organization
    • 16 Byte Page (‘C’ version devices)
    • 32 Byte Page (‘D’ version devices)
    • Self-Timed Erase and Write Cycles (5 ms max.)
    • Block Write Protection:
      - Protect none, 1/4, 1/2 or all of array
    • Built-In Write Protection:
      - Power-on/off data protection circuitry
      - Write enable latch
      - Write-protect pin
    • Sequential Read
    • High Reliability:
      - Endurance: > 1M erase/write cycles
      - Data retention: > 200 years

    三、SPI EEPROM產品

      最後痞子衡收集了可以售賣SPI EEPROM芯片的廠商及產品系列:

    廠商 芯片系列 官方網址
    Microchip
    Atmel
    25AA, 25LC
    AT25
    ST M95
    Onsemi CAT25
    Renesas R1EX25
    Rohm BR25A, BR25G, BR25H, BR25S
    Fudan Micro FM25

      至此,EEPROM接口標準及SPI EEPROM痞子衡便介紹完畢了,掌聲在哪裡~~~

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

    ※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

    ※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

    南投搬家前需注意的眉眉角角,別等搬了再說!

  • 前端Leader你應該知道的NPM包管理機制

    前端Leader你應該知道的NPM包管理機制

    npm install 命令

    首先總結下npm 安裝一個模塊包的常用命令。

    /* 模塊依賴會寫入 dependencies 節點 */
    
    npm install moduleName
    
    npm install -save moduleName
    
    npm install -S moduleName 
    
    /* 模塊依賴會寫入 devDependencies 節點 */
    
    npm install -save-dev moduleName
    
    npm install -D moduleName
    
    /* 全局安裝模塊包 */
    
    npm install -g moduleName
    
    /* 安裝特定版本的包 */
    
    npm install 包名@版本號
    
    /* 通過地址安裝git倉庫 */
    
    npm install git+https://github.com/itwmike/axios.git
    
    npm install git+ssh://git@github.com:itwmike/axios.git
     
    /* 安裝特定分支或Tag的git倉庫 */
    
    npm install git+https://github.com/itwmike/axios.git#tag
    
    /* 通過用戶名安裝git倉庫 */ 
    
    npm install github:帳號/倉庫名 # npm install github:itwmike/axios
    
    npm install github:帳號/倉庫名
    

      

    npm 依賴包版本號

    npm 所有node包都使用語義化版本號,規則要求如下:  

    • 每個版本號都形如1.2.3,由三個部分組成,依次叫做“主版本號(major)”、“次版本號(minor)”和“修訂號(patch)” 。

    • 當新版本無法兼容基於前一版本的代碼時,則提高主版本號 。

    • 當新版本新增了功能與特性,但仍兼容前一版本的代碼時,則提高次版本號 。

    • 當新版本僅僅修正漏洞或者增強效率,仍然兼容前一版本代碼,則提高修訂號。

    默認使用 npm install -save 下載的都是最新版本,同時會在package.json 文件中登記一個最優版本號,如下形式:

    "dependencies": {
      "axios": "^0.19.0"
    },
    

      

    最優版本號前面會多出一個“標記”,這個標記有啥意義?它的寫法又有哪些?

     

    npm install 都做了哪些事?

    拿到一個node項目時首要做法是運行 npm install 命令,這個命令將 package.json 文件中的依賴包自動解析並安裝,這也是項目能夠本地運行的前置條件。那如此簡單的一條命令,npm 背後又做了哪些不為人知的事呢?

    Number One

    自 npm 5.0后,項目中如果沒有 package-lock.json 文件的時候,npm 會自動幫我們生成。該文件的主要作用是記錄依賴包之間的具體版本號,對包版本有一個鎖定的意義,項目開發中應該將此文件上傳到git等版本控制工具(博主為此經歷了血淋淋的慘痛教育)。

    Number Two

    檢測本地包是否已經下載。如果本地 node_modules 下已經存在和 package-lock.json 中版本一致的包,則不會重新下載。

    Number Three

    下載依賴節點中對應的模板包。下載規則是:如果 package-lock.json 文件存在,則按照該文件中記錄的版本號下載對應的模塊包;如果文件不存在或文件中沒有該包的記錄,此時會按照版本號的標記(上面已講)規範下載並同時更新到 package-lock.json。

    了解了 package-lock.json 的作用后,筆者有個疑問:手動修改 package.json 中的包版本號后運行 npm install 命令會下載新包么?

    帶着這個疑問,筆者做了實驗,得出如下結論:

    • 如果新舊版本號差距較大,比如從 ^2.5.2 變為 2.6.0 ,那麼會下載最新包並且更新 package-lock.json 。

    • 如果新舊版本號差距較小,比如從 ^2.5.2 變為 2.5.4,那麼不會更新。

    總之是否更新要看特定情況,取決於 package.json中版本號的標記和 package-lock.json 是否一致。

    cnpm install 探索

    cnpm 是淘寶 npm 鏡像,在國內很受歡迎,雖然筆者並不喜歡使用。那 cnpm 和 npm 對包的管理是否一樣呢?

    • cnpm install 並不會生成 package-lock.json

    • cnpm install 並不受 package-lock.json 的約束,它會按照版本號標記規則下載依賴包

     

    由此可見,我們在項目中使用 cnpm 的時候一定要慎重,因為很可能團隊成員每個人使用的依賴包版本都不相同,造成打包后的結果也不同。

    如果團隊要使用 cnpm,請使用固定版本號的方式安裝依賴包如:cnpm install -E moduleName

     

    本文轉載自:

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

    ※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

    ※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

    南投搬家前需注意的眉眉角角,別等搬了再說!

  • 從沒聽說過的併發的名詞-管程

    從沒聽說過的併發的名詞-管程

    在接觸併發之前,我只聽說過進程、線程,管程這個詞倒是頭回聽說,抱着認真好學的態度,去找了找關於 管程 的資料,不學不知道,原來併發里的兩大難題–互斥和同步都可以用管程來解決,可以說,管程是一把解決併發的萬能鑰匙。

     

    那什麼是管程呢?原來管程並不像進程、線程這樣來形容一個特指東西的名詞,管程是指管理共享變量以及讀共享變量的操作過程,讓他們支持併發。Java 中的 Monitor,我們經常將它翻譯成 “監視器”,其實它還有個更學術的名字就是管程。

     

    管程有三種模型,其中廣泛應用的是 MESA 模型,Java 管程實現參考的也是 MESA 模型,所以我就着重學習這個模型。前面提到了管程可以解決併發領域互斥和同步的兩大核心問題,下面我們先看看管程是如何解決互斥問題的。

     

    • 互斥問題的解決

     

    互斥指的同一時刻只允許有一個線程訪問共享資源,管程解決互斥問題的思路很簡單,就是將共享變量及對共享變量的操作統一都封裝起來,如圖:

     

     

    線程 A 和線程 B 如果想訪問共享變量 queue,只能通過管程提供的入隊和出隊操作,入隊和出隊操作保證互斥性,只允許一個線程進入,而對外暴露的就只有管程,看上去有點面向對象封裝的意思。

     

    • 同步問題的解決

     

    在管程解決互斥問題的解決方案中,我們看到了其實共享變量和對共享變量的操作都是被封裝起來的,要想訪問共享變量就要訪問管程,所以同步的解決辦法就是在管程的入口添加一個等待隊列,當多線程想同時進入管程內部時,只允許一個線程進入,其他線程在等待隊列中等待。

     

    進入到管程內部,有可能執行修改共享變量的方法還有條件,比如要執行入隊操作,必須保證隊列不滿;要執行出隊操作,必須保證隊列不空,管程對每個條件的變量還對應有一個等待隊列,如圖:

     

     

    這裏的入口等待隊列與條件等待隊列是完全不同的兩個隊列,當進入管程內部的線程因執行方法的條件不滿足會進入條件等待隊列,等待被其他線程喚醒,喚醒後會重新進入入口的等待隊列,競爭資源。

     

    Java 內置的管程

     

    Java 內置管程與 MESA 模型類似,在 MESA 模型中,條件變量可以有多個, Java 語言內置的管程里只有一個條件變量。

     

     

    Java 內置的管程方案就是 syncronized ,使用 syncronized 修飾的代碼塊,在編譯器會自動生成相關加鎖和解鎖代碼,但是只會支持一個條件變量。

     

     

    總結一下 :

     

     

     

    以上是管程的相關介紹,後續我們會進入 Java JUC 工具包的學習,看看除了 syncronized 其他強大的併發編程類都有哪些獨特的用處。

     

     這裡有一篇 

     

    感興趣的同學可以瀏覽一下哦~

        

     

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

    ※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

    ※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

    南投搬家前需注意的眉眉角角,別等搬了再說!

  • 【自然語言處理】利用LDA對希拉里郵件進行主題分析

    【自然語言處理】利用LDA對希拉里郵件進行主題分析

    首先是讀取數據集,並將csv中ExtractedBodyText為空的給去除掉

    import pandas as pd
    import re
    import os
    
    dir_path=os.path.dirname(os.path.abspath(__file__))
    data_path=dir_path+"/Database/HillaryEmails.csv"
    df=pd.read_csv(data_path)
    df=df[['Id','ExtractedBodyText']].dropna()

    對於這些郵件信息,並不是所有的詞都是有意義的,也就是先要去除掉一些噪聲數據:

    def clean_email_text(text):
        text = text.replace('\n'," ") #新行,我們是不需要的
        text = re.sub(r"-", " ", text) #把 "-" 的兩個單詞,分開。(比如:july-edu ==> july edu)
        text = re.sub(r"\d+/\d+/\d+", "", text) #日期,對主體模型沒什麼意義
        text = re.sub(r"[0-2]?[0-9]:[0-6][0-9]", "", text) #時間,沒意義
        text = re.sub(r"[\w]+@[\.\w]+", "", text) #郵件地址,沒意義
        text = re.sub(r"/[a-zA-Z]*[:\//\]*[A-Za-z0-9\-_]+\.+[A-Za-z0-9\.\/%&=\?\-_]+/i", "", text) #網址,沒意義
        pure_text = ''
        # 以防還有其他特殊字符(数字)等等,我們直接把他們loop一遍,過濾掉
        for letter in text:
            # 只留下字母和空格
            if letter.isalpha() or letter==' ':
                pure_text += letter
        # 再把那些去除特殊字符后落單的單詞,直接排除。
        # 我們就只剩下有意義的單詞了。
        text = ' '.join(word for word in pure_text.split() if len(word)>1)
        return text

    然後取出ExtractedBodyText的那一列,對每一行email進行噪聲過濾,並返回一個對象:

    docs = df['ExtractedBodyText']
    docs = docs.apply(lambda s: clean_email_text(s))  

    然後我們呢把裏面的email提取出來:

    doclist=docs.values

    接下來,我們使用gensim庫來進行LDA模型的構建,gensim可用指令pip install -U gensim安裝。但是,要注意輸入到模型中的數據的格式。例如:[[一條郵件字符串],[另一條郵件字符串], ...]轉換成[[一,條,郵件,在,這裏],[第,二,條,郵件,在,這裏],[今天,天氣,腫么,樣],...]。對於英文的分詞,只需要對空白處分割即可。同時,有些詞語(不同於噪聲)是沒有意義的,我們要過濾掉那些沒有意義的詞語,這裏簡單的寫一個停止詞列表:

    stoplist = ['very', 'ourselves', 'am', 'doesn', 'through', 'me', 'against', 'up', 'just', 'her', 'ours',
                'couldn', 'because', 'is', 'isn', 'it', 'only', 'in', 'such', 'too', 'mustn', 'under', 'their',
                'if', 'to', 'my', 'himself', 'after', 'why', 'while', 'can', 'each', 'itself', 'his', 'all', 'once',
                'herself', 'more', 'our', 'they', 'hasn', 'on', 'ma', 'them', 'its', 'where', 'did', 'll', 'you',
                'didn', 'nor', 'as', 'now', 'before', 'those', 'yours', 'from', 'who', 'was', 'm', 'been', 'will',
                'into', 'same', 'how', 'some', 'of', 'out', 'with', 's', 'being', 't', 'mightn', 'she', 'again', 'be',
                'by', 'shan', 'have', 'yourselves', 'needn', 'and', 'are', 'o', 'these', 'further', 'most', 'yourself',
                'having', 'aren', 'here', 'he', 'were', 'but', 'this', 'myself', 'own', 'we', 'so', 'i', 'does', 'both',
                'when', 'between', 'd', 'had', 'the', 'y', 'has', 'down', 'off', 'than', 'haven', 'whom', 'wouldn',
                'should', 've', 'over', 'themselves', 'few', 'then', 'hadn', 'what', 'until', 'won', 'no', 'about',
                'any', 'that', 'for', 'shouldn', 'don', 'do', 'there', 'doing', 'an', 'or', 'ain', 'hers', 'wasn',
                'weren', 'above', 'a', 'at', 'your', 'theirs', 'below', 'other', 'not', 're', 'him', 'during', 'which']

    然後我們將輸入轉換成gensim所需的格式,並過濾掉停用詞:

    texts = [[word for word in doc.lower().split() if word not in stoplist] for doc in doclist]

    再將這所有的單詞放入到一個詞袋中,把每個單詞用一個数字index指代:

    from gensim import corpora, models, similarities
    import gensim
    dictionary = corpora.Dictionary(texts)

    再分別統計每一篇email中每個詞語在這個詞袋中出現的次數,並返回一個列表:

    corpus = [dictionary.doc2bow(text) for text in texts]

     這個列表告訴我們,第14(從0開始是第一)個郵件中,一共6個有意義的單詞(經過我們的文本預處理,並去除了停止詞后)其中,51號單詞出現1次,505號單詞出現1次,以此類推。。。

    最後,就可以開始構建我們的模型了:

    lda = gensim.models.ldamodel.LdaModel(corpus=corpus, id2word=dictionary, num_topics=20)
    print(lda.print_topic(10, topn=5))

     可以看到,第11個主題最常用的單詞,接下來,我們看下所有的主題:

    for i in lda.print_topics(num_topics=20, num_words=5):
        print(i)

     我們再看下第一篇email屬於哪一個主題:

    print(lda.get_document_topics(corpus[0]))

     屬於第四個主題的概率是0.95

    相關代碼和數據:鏈接: https://pan.baidu.com/s/1sl1I5IeQFDHjVwf2a0C89g 提取碼: xqqf 

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

    ※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

    ※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

    南投搬家前需注意的眉眉角角,別等搬了再說!

  • 2016中國國際汽車新能源及技術應用展覽會|節能與新能源汽車產業發展規劃成果展覽會

    展會時間:2016年10月13-16日

    展會地點:北京-國家會議中心

    展會定位:
    唯一的國家級新能源汽車展覽展示平臺;中國參展企業最多、展覽面積最大、展品最為豐富的節能與新能源汽車展。

    展覽規模:30,000平方米(2015年)

    觀眾數量:60,000人次(2015年)

    展覽週期:每年一屆,2013年首屆

    支援單位:中華人民共和國工業和資訊化部

    批准單位:中華人民共和國科學技術部、中國國際貿易促進委員會

    主辦單位:中國國際貿易促進委員會機械行業分會、中國電工技術學會、汽車知識雜誌社、寰球時代汽車投資管理(北京)有限公司

    合作單位:北京盛大超越國際展覽有限公司

    展位價格:
    室內光地:1280元/平方米
    標準展位:11800元/個(3m*3m)

    參展範圍:

    整車類

    純電動車,混合動力車,燃料電池車,輕型電動車,天然氣(液化氣)車,醇類及其他代用燃料車和節能汽車。

    零部件類

    電池、電機、電控等核心零部件和先進技術應用;先進內燃機、高效變速器、輕量化材料、整車優化設計及混合動力等節能技術產品。

    充電設施

    充電樁、充電機、配電櫃、充換電池及電池管理系統、停車場充電設施、智慧監控、充電站供電解決方案、充電站-智慧電網解決方案等。

    新能源汽車發展成果展示;檢測,維修,監控,實驗,安全防護裝備及媒體等.

    連絡人:岳巍 先生  
    手機(微信):135 5286 5285
    郵箱:sales2@s-expo.com  

    附:其他推薦展會

    2016上海國際汽車新能源及智慧技術展覽會
    上海車展新能源姐妹展
    展會日期:2016年6月28日-30日
    展會地點:上海新國際博覽中心
    詳情請點擊

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

    ※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

    ※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

    南投搬家前需注意的眉眉角角,別等搬了再說!

  • 如何給HTML標籤中的文本設置修飾線

    如何給HTML標籤中的文本設置修飾線

    text-decoration屬性介紹

    • text-decoration屬性是用來設置文本修飾線呢,text-decoration屬性一共有4個值。

    text-decoration屬性值說明表

    作用
    none 去掉文本修飾線
    underline 設置下劃線
    overline 設置上劃線
    line-through 設置刪除線

    HTML標籤自帶修飾線

    • 在開始實踐text-decoration屬性之前,筆者先給大家普及下HTML中的標籤自帶修飾線如:u標籤s標籤,若有不全大家可以在下面評論中告訴筆者,畢竟筆者也是前端的一個小白,希望和大家相互交流,互幫互助,共同進步。

    u標籤

    • 下面讓我們進入u標籤的實踐,u標籤自帶的是文本下劃線。
    • 代碼塊

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>設置文本修飾線</title>
      
    </head>
    <body>
        <u>成功不是擊敗別人,而是改變自己</u>
    </body>
    </html>
    • 結果圖

    • 注意:u標籤也可以配合HTML中的其他標籤使用,舉例:將u標籤嵌套到h1標籤中使用。

    • 代碼塊

    <h1><u>成功不是擊敗別人,而是改變自己</u></h1>

    s標籤

    • 下面讓我們進入s標籤的實踐,s標籤自帶的是文本刪除線。
    • 代碼塊

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>設置文本修飾線</title>
      
    </head>
    <body>
        <s>成功不是擊敗別人,而是改變自己</s>
    </body>
    </html>
    • 結果圖

    • 注意:s標籤也可以嵌套,和u標籤一致,筆者就不過多的介紹了。

    none去除修飾線

    • 讓我們進入text-decoration屬性的none值實踐,實踐內容如:筆者將HTML頁面中的s標籤自帶的刪除線給去除掉。

    • 代碼塊

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>設置文本修飾線</title>
        <style>
            s{
                text-decoration: none;
            }
        </style>
    </head>
    <body>
        <s>成功不是擊敗別人,而是改變自己</s>
    </body>
    </html>
    • 結果圖

    • 注意:u標籤、s標籤、包括text-decoration屬性值的所有的修飾線都可以去掉哦。

    underline設置下劃線

    • 讓我們進入text-decoration屬性的underline值實踐,實踐內容如:筆者將HTML頁面中的h2標籤中的文本設置一個下劃線。
    • 代碼塊

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>設置文本修飾線</title>
        <style>
            h2{
                text-decoration: underline;
            }
        </style>
    </head>
    <body>
        <h2>成功不是擊敗別人,而是改變自己</h2>
    </body>
    </html>
    • 結果圖

    overline設置上劃線

    • 讓我們進入text-decoration屬性的overline值實踐,實踐內容如:筆者將HTML頁面中的h2標籤中的文本設置一個上劃線。

    • 代碼塊

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>設置文本修飾線</title>
        <style>
            h2{
                text-decoration: overline;
            }
        </style>
    </head>
    <body>
        <h2>成功不是擊敗別人,而是改變自己</h2>
    </body>
    </html>
    • 結果圖

    line-through設置刪除線

    • 讓我們進入text-decoration屬性的line-through值實踐,實踐內容如:筆者將HTML頁面中的h2標籤中的文本設置一個刪除線。

    • 代碼塊

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>設置文本修飾線</title>
        <style>
            h2{
                text-decoration: line-through;
            }
        </style>
    </head>
    <body>
        <h2>成功不是擊敗別人,而是改變自己</h2>
    </body>
    </html>
    • 結果圖

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

    ※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

    ※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

    南投搬家前需注意的眉眉角角,別等搬了再說!

  • Springboot 自動配置淺析

    Introduction

    我們知道,SpringBoot之所以強大,就是因為他提供了各種默認的配置,可以讓我們在集成各個組件的時候從各種各樣的配置文件中解放出來。

    拿一個最普通的 web 項目舉例。我們需要使用 servlet 容器,SpringBoot 就提供了嵌入式的 Tomcat 作為默認容器,不需要一行配置就能直接以最普通的 Java 程序的方式啟動:java -jar;接收請求需要一個網絡端口,默認配置好8080;處理請求需要 servlet 的多線程特性,默認配置好了最大線程數為200;處理好的請求以Restful 風格返回給調用方,SpringBoot 默認配置好了jackson進行 json 序列化,業務代碼需要做的只是返回一個 POJO 對象;連接池直接就默認配置了性能最好的的 Hikari,以及連接池的默認尺寸為10……在一個簡單的web應用中,這些配置我們甚至都可能不了解或者沒有意識到它們的存在,就可以讓程序正常運行。

    這就是自動配置的魔力——潤物細無聲。

    那麼自動配置是怎麼實現的呢?本文就從POM文件和 @SpringBootApplication 註解來簡單分析一下自動配置原理。

    真的只是簡單地,分析一下。

    POM文件

    環境

    • SpringBoot 2.0.6

    父項目

    在每一個 SpringBoot 項目一開始的 POM 文件中,就有一個父依賴

    <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.0.6.RELEASE</version>
      <relativePath/> <!-- lookup parent from repository -->
    </parent>

    點進artifactId之後來到 spring-boot-starter-parent-2.0.6.RELEASE.pom 文件,這個文件還有一個父依賴:

    <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-dependencies</artifactId>
      <version>2.0.6.RELEASE</version>
      <relativePath>../../spring-boot-dependencies</relativePath>
    </parent>

    再繼續點進去來到 spring-boot-dependencies-2.0.6.RELEASE.pom 文件中。在該文件的 <properties> 標籤中可以看到各種各樣的組件的版本信息, <dependencyManagement> 標籤中聲明了各個組件的maven坐標信息。其中,我數了一下,在 SpringBoot 2.0.6 中一個有177個帶有版本信息的組件名,包括了大家熟悉的 elasticsearch、activemq、redis、kafka等等。

    這裏(spring-boot-dependencies-2.0.6.RELEASE.pom文件)稱為 SpringBoot 的“版本仲裁中心”,它是用來管理 SpringBoot 應用裏面的所有依賴版本的地方。 它包含了大部分開發中會用到的一些組件的版本,所以我們導入依賴默認是不需要寫版本號的,SpringBoot 會自動幫我們配置需要的版本。這樣在引入某個組件的時候不用考慮這個組件和系統中已有的組件兼不兼容之類的問題,避免了煩人的版本衝突問題。(當然,沒有在 dependencies裏面管理的依賴自然需要聲明版本號)

    啟動器(Starters)

    父項目做版本仲裁,那麼真正的 jar 包是從哪裡導入進來的呢?這就要說到我們的starters了。點開web-starter可以看到它幫我們導入了web模塊正常運行所依賴的組件,就不用我們一個一個手動導入了。

    所以,所謂的Starters就是一系列依賴描述的組合,我們可以通過導入這些starters就會有相應的依賴了並可以基於他們進行相應的開發

    Springboot把開發中中會遇到的場景都抽象成一個個的starter,比如(),只需要在項目裏面引入這些starter 相關場景的所有依賴都會導入進來。要用什麼功能就導入什麼場景的啟動器

    @SpringBootApplication

    一個典型的 springboot 項目的入口類如下所示:

    @SpringBootApplication
    public class DemoApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args);
        }
    }

    只要運行main方法就能啟動該應用。main 中運行 run 方法時需要傳入一個類,這個類正是使用@SpringBootApplication註解標註的類,如果沒有這個註解程序是跑不起來的。

    這個註解標註在某個類上就說明這個類是 springboot 的主配置類,springboot 就應該運行這個類的 main 方法來啟動springboot應用

    點開這個註解的源碼,可以看到這是一個組合註解,最主要的是這兩個註解:

    • @SpringBootConfiguration

    • @EnableAutoConfiguration

    @SpringBootConfiguration標註在某個類上,表示這是一個 SpringBoot 的配置類,它的底層是@Configuration,屬於spring的底層註解,標註了這個註解的類表名這個類是一個配置類,取代以前開發中的xml文件配置,同時也表明這個類是 spring 容器中的組件,受容器管理。

    接下來是@EnableAutoConfiguration註解,它的用處是開啟自動配置,使用 spring 開發需要手動配置的東西,現在由 springboot 幫我們配置了,具體的實現就是通過這個註解來實現的。該組合註解有兩個。

    1. @AutoConfigurationPackage

    它的 註解中的核心代碼是 @Import({Registrar.class})

    @Import 的作用就是為容器中導入一個它指定的組件。

    Registrar 這個類中有一個方法叫registerBeanDefinitions,用於註冊一些 bean 定義信息:

    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
         AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());
    }

    打個斷點在這一行代碼上,運行

    (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName()

    得到的結果是主配置類所在的包名,目的就是將主配置類所在包及下面所有子包裏面的所有組件掃描到Spring容器中。同時也說明了,如果在主配置所在包的上層包添加組件的話是不會被掃描到的、不起作用的。

    2. @Import({AutoConfigurationImportSelector.class})

    該註解導入了一個自動配置的選擇器,真正地給容器中導入 springboot 自動幫我們配置好的配置類。在 AutoConfigurationImportSelector 這個選擇器中的 getAutoConfigurationEntry 方法中,以全限定類名的方式把所有需要的配置類導入 springboot 容器中。這些全限定類型所在文件路徑為:

    org/springframework/boot/spring-boot-autoconfigure/2.1.8.RELEASE/spring-boot-autoconfigure-2.1.8.RELEASE.jar!/META-INF/spring.factories

    上述兩個註解一個負責掃描我們將要加容器中的類,一個加入 springboot 為我們自動配置好的類,springboot 通過這兩種方式省略了我們大量的配置工作。

    總結

    本文從用於maven項目管理的pom.xml文件和標註在啟動類上的@SpringBootApplication註解,簡單分析了springboot 自動配置的實現。前者通過版本仲裁中心為我們維護項目組件的版本,防止依賴衝突;後者通過在加載程序的時候導入數以百計的自動配置類實現自動配置。

    原文發表於:https://pengcheng.site/2019/10/28/springboot-zi-dong-pei-zhi-qian-xi/

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

    ※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

    ※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

    南投搬家前需注意的眉眉角角,別等搬了再說!