Total Pageviews

2019/04/08

[Spring Boot] A simple example for Spring Boot Profile

Scenario


How-To
1. Create a WeatherService
package com.example.service;

public interface WeatherService {

    String getWeatherForecast();

}


2. Create a SunnyDayService and assign sunny & default
package com.example.service;

import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;

@Service
@Profile({"sunny", "default"})
public class SunnyDayService implements WeatherService {

    @Override
    public String getWeatherForecast() {
        return "Today is sunny day";
    }

}


3. Create a RainingDayService and assign raining profile
package com.example.service;

import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;

@Service
@Profile({"raining"})
public class RainyDayService implements WeatherService {

    @Override
    public String getWeatherForecast() {
        return "Today is raining day";
    }

}


4. Assign active profile in application.yml
spring:
  profiles:
    active: raining


5. Test code
package com.example.test;

import com.example.service.WeatherService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan(basePackages = "com.example")
@Slf4j
public class TestApplication {

    public static void main(String[] args) {
        SpringApplication.run(TestApplication.class, args);
    }
 
    @Bean
    CommandLineRunner testWeatherService(WeatherService weatherService) {
        return args -> {
            String output = weatherService.getWeatherForecast();
            log.debug("weather forecast = {}", output);
        };
    }

}



Console
2018-12-20 09:53:30.255 DEBUG 6920 --- [           main] com.example.test.TestApplication         : weather forecast = Today is raining day


2019/04/07

[HTML] Using DATA URI to show image in HTML

Here has a simple example to demonstrate how to use base64 string to show image in HTML instead of physical image file.

Steps
Step 1. Find a picture and upload to https://www.base64-image.de/


Step 2. Copy base64 string


Step 3. Go to https://plnkr.co/ to do test


Here has an url to demonstrate

https://plnkr.co/edit/xt2W5IFQgvqgOwwmgHUT?p=preview

2019/04/06

[閱讀筆記] Thinking in Systems: A Primer (1/9)


  1. 這本書的主要目的是要針對系統 (system) 提供不同的看法與想法,目標讀者是對系統這個字感到有興趣的與系統分析領域的人。作者會使用非技術性的語言來進行討論,不要使用數學或電腦領域的字眼,讓讀者理解系統。並且,由於一張圖可以抵萬語,作者會透過圖形來讓讀者更容易理解。
  2. 何謂系統 (system)一個系統是由一組事物 (例如人、細胞、分子等) 所組成,彼此間以某種方式互相連結,並產生某種行為模式。這個系統可能會受到外部力量的觸發、驅動、衝擊或限制,系統對於外部力量也會產生反饋 (feedback) 的力量。在真實世界中,系統對於外部力量所產生的反饋力量,很少是單純、可預測的。
  3. 系統可以是一棵樹、一個人、一家公司,甚至一個城市、經濟體、生態系或地球。系統在現實中形成,一旦形成,就無法順服於單一的意志之下,無法被預測和控制
  4. 日常生活常見的系統的例子
        4.1.     政治領導者通常無法造成經濟蕭條或經濟繁榮 (economic booms)。經濟的起伏源自於市場經濟的結構。
        4.2.     競爭者鮮少能造成一家公司失去市佔率。競爭者或許只是善用自己的競爭優勢,失敗的公司則是在商業決策上做了錯誤的決定。
        4.3.     石油輸出國無法獨自控制油價,他們無法自己驅動全球油價上揚,這還需要看石油消耗、定價與石油輸入國的投資政策等。
        4.4.     感冒病毒不會攻擊你,是你自己給了病毒一個可以發展的條件。
  1. 未來是不可預測的,但是人類可以想像未來,並且在人們的腦海中栩栩如生,呼之欲出;系統不可以被控制,但它們可以被設計和重構。
  2. 雖然不能掌控眼前的大千世界,讓它永遠風平浪靜,但是我們有機會預料各種可能的意外,聆聽系統的聲音,順應特性,創造出更美好的事物。
  3. 我們所面臨的世界,是一個複雜系統 (complex system)。我們的身體就是一個很好的例子,人體內平均有37.2 兆個細胞,體內的細胞會互相連結、整合、自我修復。我們所遇到的每個人、每個組織、每隻動物、花園、樹木與森林等,都是複雜系統。
  4. 由於在複雜系統中,系統的反饋 (feedback) 會有所延遲 (delay),當問題已經變得明顯易見時,通常都會變得非常棘手、難以處理
  5. 根據競爭排除原理 (competitive exclusion principle),兩個同時進行的活動,往往會因為有限的資源而競爭,這時只要有一個表現比較好,就會開始爭取到更多資源,產生正增強環路,同時排擠到另一邊產生負增強環路。兩個使用同一資源的活動同時展開,其中一個蒸蒸日上,另一個則陷於掙扎求生的狀態。最典型的例子就是富者越富、貧者越貧 (The rich get richer and the poor get poorer)
  6. 為了解決競爭排斥,領導者針對共同享用資源的分配時,除了績效表現,也要考量『整體均衡發展』的更上層目標,有些狀況應該要將『同一』資源予以『區分』規劃,以減少不必要的競爭。避免發生分到較多的資源者,產生較好的成果,因而又得到更多的資源;分到較少的資源者,產生較差的結果,因而分到的資源更少。
  7. 相較於較單純的系統 (uniform system)擁有多條路徑 (pathways) 與備餘 (redundancy) 的多元系統 (diverse system),對於外部衝擊 (external shock) 的反應一定較為穩定且較不脆弱 (less vulnerable)。例如,不要將所有的雞蛋放在同一個籃子 (don’t pull all you eggs in one basket)
  8. 飢荒、貧窮、環境汙染、經濟衰退、失業、慢性疾病、非法藥物成癮、戰爭等問題,都不是人們想製造的問題,但是這些問題卻存在許久,一直無法徹底解決。因為這些屬於根本的系統問題 (intrinsically systems problems),都是系統結構中有害的行為特徵所產生的系統問題。我們只能細心觀察造成這些系統問題的來源,將其重新設計與重構 (restructure)
  9. 在書本中,字與句子一定是逐一、線性的方式出現。但是在複雜系統中,則是一口氣全部出現,而且彼此間關聯方向不只單向,而是多個方向的方式同時發生。
  10. 這個世界變得比以前更混亂、更擁擠、更緊密結合、更互相依賴、更快速改變。系統思考 (systems thinking) 可以幫助我們了解整體系統與
      14.1.     磨練我們了解系統組成的能力 (hone our abilities to understand parts)
      14.2.     看出各個系統組成間的交互關係 (see interconnections)
      14.3.     對於可能的未來行為,詢問 "如果...會怎麼樣 ?" 的問題 (ask what-if questions about possible future behaviors)
      14.4.     對於系統重新設計保持創意與勇氣 (be creative and courageous about system redesign)
  1. 瞎子摸象的故事告訴我們,我們無法透過僅僅知曉幾個系統的組成元素,就了解整體系統的可能行為 (The behavior of a system cannot be known just by knowing the elements of which the system is made)
  2. 系統一定是由三樣事物所組成:組成元素 (elements)、相互關係 (interconnection) 與提供某個功能或達成某個目的 (function or purpose)。 
      16.1.     以消化系統 (digestive system) 為例,牙齒、酶、食道、胃與腸,都是消化系統的組成元素 (elements);組成元素間會互相合作,將食物往胃腸流動;這個系統的主要目的是要將食物分解成人體所需的基礎營養,並將這些養分 (nutrients) 轉換到血液中。
      16.2.     以足球團隊為例,球員、教練、球場與足球,都是系統的組成元素 (elements);足球規則、教練的戰術、球員間的溝通以及球員與球的物理限制,都是組成元素間的相互關係 (interconnection);足球團隊的目的可能是贏得比賽、好玩、運動健身或賺大錢等等。
  1. 有很多事物都是系統 (system),例如學校、城市、工廠、企業、國家經濟、動物、樹木等。森林則是一個更大的系統,可以包含樹木與動物,成為它的子系統。地球、太陽系、銀河等,也都是系統,系統還可以嵌入多個其他系統。 
  2. 什麼東西『不是』系統?一個由不同事物所組成的聚合體 (conglomeration),彼此間沒有任何交互關係 (interconnection),也沒有提供任何功能或要達成任何目的,此時就不能稱之為一個系統。例如馬路上偶遇的沙子就不是一個系統。你可以增加或帶走一些沙子,對於馬路沒有任何影響。但是如果在足球比賽缺少一個球員、或是消化系統中某個器官失能,對於原本的系統就會產生重大衝擊,就不是原本那個系統了。
  3. 並非一群事物的總和就是一個系統。其必須能夠展現可調適性 (adaptive)、動態性 (dynamic)、追尋目標 (goal-seeking)、自我保護 (self-preserving),並且有時候還會有演化的行為 (evolutionary behavior)
  4. 系統組成的元素,包含有形的與無形的。以大學為例,教室、學生、教授、行政人員、圖書館、課科書、電腦等,都是有形的元素;校譽、學術專業能力等,對於大學來說,也是非常重要的無形元素。一旦你開始列舉系統的組成元素時,這會是個看不到終點的過程,因為元素 (elements) 可以再往下細分為 sub-elementsub-sub-elements,你會發現你會很快地失焦,這就是所謂的見樹不見林 (you can’t see the forest for the trees)

2019/04/05

[Spring boot] How To Do @Async in Spring

Setup Asynchronous configuration:
package com.example.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

@Configuration
// enable asynchronous processing with Java configuration
@EnableAsync
public class AsyncConfig {

    @Bean("githubUserLookupExecutor")
    public ThreadPoolTaskExecutor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(20);
        executor.setMaxPoolSize(1000);
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setThreadNamePrefix("Async-");
        return executor;
    }

}



Create a GitHub Lookup Service:
package com.example.service;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.concurrent.CompletableFuture;

/**
 * GitHub Lookup Service
 */
@Slf4j
@Service
public class GitHubLookupService {

    @Value("${http.proxy.host}")
    private String host;

    @Value("${http.proxy.port}")
    private Integer port;

    /**
     * The method needs to be public so that it can be proxied.
     * And self-invocation doesn’t work because it bypasses the proxy and
     * calls the underlying method directly
     *
     * @param name user name
     * @return
     */
    @Async("githubUserLookupExecutor")
    public CompletableFuture<User> findUser(String name) {
        log.debug("looking up {}", name);

        String url = String.format("https://api.github.com/users/%s", name);
        User user = new RestTemplate(setupProxy()).getForObject(url, User.class);

        return CompletableFuture.completedFuture(user);
    }

    private SimpleClientHttpRequestFactory setupProxy() {
        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();

        Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, port));
        requestFactory.setProxy(proxy);
        return requestFactory;
    }


    /**
     * Representation of a GitHub User (JSON to Object)
     */
    @Data
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class User {
        private String login;
        private String name;
        private String blog;
        private String location;
    }

}



Test code:
package com.example.test;

import com.example.service.GitHubLookupService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;

import java.util.concurrent.CompletableFuture;

@SpringBootApplication
@ComponentScan(basePackages = "com.example")
@Slf4j
public class TestApplication {

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

    @Bean
    CommandLineRunner run(GitHubLookupService service) {
        return args -> {
            // Kick off multiple asynchronous lookups
            CompletableFuture<GitHubLookupService.User> junyuo = service.findUser("junyuo");
            CompletableFuture<GitHubLookupService.User> springProjects = service.findUser("Spring-Projects");
            CompletableFuture<GitHubLookupService.User> tensorflow = service.findUser("tensorflow");
            CompletableFuture<GitHubLookupService.User> dotnet = service.findUser("dotnet");
            CompletableFuture<GitHubLookupService.User> google = service.findUser("google");

            // Wait until they are all done
            CompletableFuture.allOf(junyuo, springProjects, tensorflow, dotnet, google).join();

            log.debug("user = {}", junyuo.get());
            log.debug("user = {}", dotnet.get());
            log.debug("user = {}", springProjects.get());
            log.debug("user = {}", google.get());
            log.debug("user = {}", tensorflow.get());
        };
    }

}


Console log:
2018-12-06 11:01:52.358  INFO 11440 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2018-12-06 11:01:52.361  INFO 11440 --- [           main] com.example.test.TestApplication         : Started TestApplication in 2.522 seconds (JVM running for 3.465)
2018-12-06 11:01:52.370 DEBUG 11440 --- [        Async-3] com.example.service.GitHubLookupService  : looking up tensorflow
2018-12-06 11:01:52.370 DEBUG 11440 --- [        Async-4] com.example.service.GitHubLookupService  : looking up dotnet
2018-12-06 11:01:52.370 DEBUG 11440 --- [        Async-5] com.example.service.GitHubLookupService  : looking up google
2018-12-06 11:01:52.370 DEBUG 11440 --- [        Async-2] com.example.service.GitHubLookupService  : looking up Spring-Projects
2018-12-06 11:01:52.370 DEBUG 11440 --- [        Async-1] com.example.service.GitHubLookupService  : looking up junyuo
2018-12-06 11:01:53.759 DEBUG 11440 --- [           main] com.example.test.TestApplication         : user = GitHubLookupService.User(login=junyuo, name=Albert Kuo, blog=http://albert-kuo.blogspot.com/, location=Taipei)
2018-12-06 11:01:53.759 DEBUG 11440 --- [           main] com.example.test.TestApplication         : user = GitHubLookupService.User(login=dotnet, name=.NET Foundation, blog=http://www.dotnetfoundation.org, location=null)
2018-12-06 11:01:53.759 DEBUG 11440 --- [           main] com.example.test.TestApplication         : user = GitHubLookupService.User(login=spring-projects, name=Spring, blog=http://spring.io/projects, location=null)
2018-12-06 11:01:53.759 DEBUG 11440 --- [           main] com.example.test.TestApplication         : user = GitHubLookupService.User(login=google, name=Google, blog=https://opensource.google.com/, location=null)
2018-12-06 11:01:53.759 DEBUG 11440 --- [           main] com.example.test.TestApplication         : user = GitHubLookupService.User(login=tensorflow, name=null, blog=http://www.tensorflow.org, location=null)