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

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

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

    paulwong

    #

    配置SPRING BATCH中的JUNIT TEST

    關(guān)鍵是JobLauncherTestUtils的配置:

        @Configuration
        public class BatchTestConfiguration {
            
            
            @Bean
            public JobLauncherTestUtils stoppedReportJobLauncherTestUtils(
                    JobLauncher stoppedReportJobLauncher
            ) {
                return new JobLauncherTestUtils() {
                    
                    @Autowired
                    public void setJobLauncher(JobLauncher stoppedReportJobLauncher) {
                        super.setJobLauncher(stoppedReportJobLauncher);
                    }

                    @Autowired
                    public void setJob(Job stoppedReportJob) {
                        super.setJob(stoppedReportJob);
                    }
                    
                };
            }
        }


    posted @ 2020-02-03 16:47 paulwong 閱讀(794) | 評(píng)論 (0)編輯 收藏

    Transform RemoteChunk to remote with json format in Spring Batch

    Spring Batch Remote Chunk模式下,遠(yuǎn)程執(zhí)行JOB時(shí),傳輸?shù)膶?duì)象是ChunkRequest/ChunkResponse,無(wú)法轉(zhuǎn)成JSON格式傳輸。

    注意此處使用的是SPRING JACKSON,而不是JACKSON。一般是在SPRING INTEGRATIONA框架下轉(zhuǎn)的。

    需要自定義Transformer:

    JsonToChunkRequestTransformer.java
    package com.frandorado.springbatchawsintegrationslave.transformer;

    import java.io.IOException;
    import java.util.Collection;
    import java.util.Map;
    import java.util.stream.IntStream;

    import org.springframework.batch.core.ExitStatus;
    import org.springframework.batch.core.StepContribution;
    import org.springframework.batch.core.StepExecution;
    import org.springframework.batch.integration.chunk.ChunkRequest;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.integration.aws.support.AwsHeaders;
    import org.springframework.integration.json.JsonToObjectTransformer;
    import org.springframework.messaging.Message;
    import org.springframework.stereotype.Component;

    import com.amazonaws.services.sqs.AmazonSQSAsync;
    import com.fasterxml.jackson.databind.ObjectMapper;

    @Component
    public class JsonToChunkRequestTransformer extends JsonToObjectTransformer {
        
        private static final String MESSAGE_GROUP_ID_HEADER = "message-group-id";
        
        @Autowired
        AmazonSQSAsync amazonSQSAsync;
        
        @Override
        protected Object doTransform(Message<?> message) throws Exception {
            // ACK
            ack(message);
            
            return this.getMessageBuilderFactory().withPayload(buildChunkRequest(message)).setHeader(MESSAGE_GROUP_ID_HEADER, "unique").build();
        }
        
        private ChunkRequest buildChunkRequest(Message<?> message) throws IOException {
            Map map = new ObjectMapper().readValue(message.getPayload().toString(), Map.class);
            Map stepContributionMap = (Map) map.get("stepContribution");
            Map exitStatusMap = (Map) stepContributionMap.get("exitStatus");
            
            StepContribution stepContribution = new StepContribution(new StepExecution("null", null));
            ExitStatus exitStatus = new ExitStatus((String) exitStatusMap.get("exitCode"), (String) exitStatusMap.get("exitDescription"));
            
            IntStream.range(0, (Integer) stepContributionMap.get("readCount")).forEach(e -> stepContribution.incrementReadCount());
            stepContribution.incrementWriteCount((Integer) stepContributionMap.get("writeCount"));
            stepContribution.incrementFilterCount((Integer) stepContributionMap.get("filterCount"));
            stepContribution.incrementReadSkipCount((Integer) stepContributionMap.get("readSkipCount"));
            IntStream.range(0, (Integer) stepContributionMap.get("writeSkipCount")).forEach(e -> stepContribution.incrementWriteSkipCount());
            IntStream.range(0, (Integer) stepContributionMap.get("processSkipCount"))
                    .forEach(e -> stepContribution.incrementProcessSkipCount());
            stepContribution.setExitStatus(exitStatus);
            
            return new ChunkRequest((Integer) map.get("sequence"), (Collection) map.get("items"), (Integer) map.get("jobId"), stepContribution);
        }
        
        private void ack(Message<?> message) {
            String receiptHandle = message.getHeaders().get(AwsHeaders.RECEIPT_HANDLE, String.class);
            String queue = message.getHeaders().get(AwsHeaders.QUEUE, String.class);
            String queueUrl = amazonSQSAsync.getQueueUrl(queue).getQueueUrl();
            
            amazonSQSAsync.deleteMessage(queueUrl, receiptHandle);
        }
    }


    JsonToChunkResponseTransformer.java
    package com.frandorado.springbatchawsintegrationmaster.transformer;

    import java.io.IOException;
    import java.util.Map;

    import org.springframework.batch.core.StepContribution;
    import org.springframework.batch.core.StepExecution;
    import org.springframework.batch.integration.chunk.ChunkResponse;
    import org.springframework.integration.json.JsonToObjectTransformer;
    import org.springframework.messaging.Message;
    import org.springframework.stereotype.Component;

    import com.fasterxml.jackson.databind.ObjectMapper;

    @Component
    public class JsonToChunkResponseTransformer extends JsonToObjectTransformer {
        
        @Override
        protected Object doTransform(Message<?> message) throws Exception {
            return buildChunkResponse(message);
        }
        
        private ChunkResponse buildChunkResponse(Message<?> message) throws IOException {
            Map map = new ObjectMapper().readValue(message.getPayload().toString(), Map.class);
            
            Integer jobId = (Integer) map.get("jobId");
            Integer sequence = (Integer) map.get("sequence");
            String messageContent = (String) map.get("message");
            Boolean status = (Boolean) map.get("successful");
            
            StepContribution stepContribution = new StepContribution(new StepExecution("-", null));
            
            return new ChunkResponse(status, sequence, Long.valueOf(jobId), stepContribution, messageContent);
        }
    }


    還有一種方式,就是如果第三類不支持轉(zhuǎn)JSON,即代碼里沒有JACKSON的注解,可以采用MIXIN的方式:

    StepExecutionJacksonMixIn.java
    package org.springframework.cloud.dataflow.rest.client.support;

    import com.fasterxml.jackson.annotation.JsonCreator;
    import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
    import com.fasterxml.jackson.annotation.JsonProperty;

    import org.springframework.batch.core.StepExecution;

    /**
     * Jackson MixIn for {
    @link StepExecution} de-serialization.
     *
     * 
    @author Gunnar Hillert
     * 
    @since 1.0
     
    */
    @JsonIgnoreProperties({ "jobExecution", "jobParameters", "jobExecutionId", "skipCount", "summary" })
    public abstract class StepExecutionJacksonMixIn {

        @JsonCreator
        StepExecutionJacksonMixIn(@JsonProperty("stepName") String stepName) {
        }

    }

    在配置文件中注冊(cè)才能使用:
    JacksonConfiguration.java
    import java.util.Locale;
    import java.util.TimeZone;

    import org.springframework.batch.core.ExitStatus;
    import org.springframework.batch.core.JobExecution;
    import org.springframework.batch.core.JobInstance;
    import org.springframework.batch.core.JobParameter;
    import org.springframework.batch.core.JobParameters;
    import org.springframework.batch.core.StepExecution;
    import org.springframework.batch.item.ExecutionContext;
    import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.integration.support.json.Jackson2JsonObjectMapper;

    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
    import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
    import com.novacredit.bmb.batchmonitor.springbatch.common.batch.jackson.ISO8601DateFormatWithMilliSeconds;
    import com.novacredit.bmb.batchmonitor.springbatch.common.batch.jackson.mixin.ExecutionContextJacksonMixIn;
    import com.novacredit.bmb.batchmonitor.springbatch.common.batch.jackson.mixin.ExitStatusJacksonMixIn;
    import com.novacredit.bmb.batchmonitor.springbatch.common.batch.jackson.mixin.JobExecutionJacksonMixIn;
    import com.novacredit.bmb.batchmonitor.springbatch.common.batch.jackson.mixin.JobInstanceJacksonMixIn;
    import com.novacredit.bmb.batchmonitor.springbatch.common.batch.jackson.mixin.JobParameterJacksonMixIn;
    import com.novacredit.bmb.batchmonitor.springbatch.common.batch.jackson.mixin.JobParametersJacksonMixIn;
    import com.novacredit.bmb.batchmonitor.springbatch.common.batch.jackson.mixin.StepExecutionJacksonMixIn;

    @Configuration
    public class JacksonConfiguration {

        @Bean
        public Jackson2JsonObjectMapper jackson2JsonObjectMapper(ObjectMapper objectMapper) {
            return new Jackson2JsonObjectMapper(objectMapper);
        }
        
        @Bean
        public Jackson2ObjectMapperBuilderCustomizer dataflowObjectMapperBuilderCustomizer() {
            return (builder) -> {
                builder.dateFormat(new ISO8601DateFormatWithMilliSeconds(TimeZone.getDefault(), Locale.getDefault(), true));
                // apply SCDF Batch Mixins to
                
    // ignore the JobExecution in StepExecution to prevent infinite loop.
                
    // https://github.com/spring-projects/spring-hateoas/issues/333
                builder.mixIn(StepExecution.class, StepExecutionJacksonMixIn.class);
                builder.mixIn(ExecutionContext.class, ExecutionContextJacksonMixIn.class);
                builder.mixIn(JobExecution.class, JobExecutionJacksonMixIn.class);
                builder.mixIn(JobParameters.class, JobParametersJacksonMixIn.class);
                builder.mixIn(JobParameter.class, JobParameterJacksonMixIn.class);
                builder.mixIn(JobInstance.class, JobInstanceJacksonMixIn.class);
    //            builder.mixIn(StepExecutionHistory.class, StepExecutionHistoryJacksonMixIn.class);
                builder.mixIn(ExecutionContext.class, ExecutionContextJacksonMixIn.class);
                builder.mixIn(ExitStatus.class, ExitStatusJacksonMixIn.class);
    //            objectMapper.setDateFormat(new ISO8601DateFormatWithMilliSeconds());
                builder.modules(new JavaTimeModule(), new Jdk8Module());
            };
        }
    }

        @Bean
        public IntegrationFlow flow4Contribution(
                ConnectionFactory connectionFactory, 
                JobProperties jobProperties,
                Jackson2JsonObjectMapper jackson2JsonObjectMapper
        ) {
            return IntegrationFlows
                        .from(request4ContributionMaster())
                        .enrichHeaders(headerEnricherConfigurer())
                        .transform(Transformers.toJson(jackson2JsonObjectMapper))
                        .handle(jmsOutboundGateway4Contribution(connectionFactory, jobProperties))
                        .transform(Transformers.fromJson(StepExecution.class, jackson2JsonObjectMapper))
                        .channel(replies4ContributionMaster(null))
                        .get();
        }


    https://github.com/spring-cloud/spring-cloud-dataflow/tree/master/spring-cloud-dataflow-rest-client/src/main/java/org/springframework/cloud/dataflow/rest/client/support

    https://frandorado.github.io/spring/2019/07/29/spring-batch-aws-series-introduction.html

    https://github.com/frandorado/spring-projects/tree/master/spring-batch-aws-integration/spring-batch-aws-integration-master/src/main/java/com/frandorado/springbatchawsintegrationmaster/transformer


    https://github.com/frandorado/spring-projects/tree/master/spring-batch-aws-integration/spring-batch-aws-integration-slave/src/main/java/com/frandorado/springbatchawsintegrationslave/transformer

    posted @ 2020-01-21 16:44 paulwong 閱讀(583) | 評(píng)論 (0)編輯 收藏

    如何加CRON JOB到LINUX


    https://linuxtools-rst.readthedocs.io/zh_CN/latest/tool/crontab.html

    posted @ 2020-01-21 15:50 paulwong 閱讀(307) | 評(píng)論 (0)編輯 收藏

    Linux and Unix du command tutorial with examples

    https://shapeshed.com/unix-du/

    查詢>100M的文件,倒序排列,文件大小以K/M/G等顯示:
    -h: 以可讀方式顯示,-t 排除小于100m的文件,sort排序,less: 分頁(yè)
    du -ah -t 100m / | sort -n -r | less

    posted @ 2020-01-15 17:17 paulwong 閱讀(299) | 評(píng)論 (0)編輯 收藏

    SPRING INTEGRATION ERROR HANDLING

    https://github.com/zakyalvan/spring-integration-java-dsl-learn

    package com.jwebs.learn.errorhandling;

    import java.util.Random;

    import javax.jms.ConnectionFactory;

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.builder.SpringApplicationBuilder;
    import org.springframework.context.ConfigurableApplicationContext;
    import org.springframework.context.annotation.Bean;
    import org.springframework.integration.annotation.IntegrationComponentScan;
    import org.springframework.integration.channel.PublishSubscribeChannel;
    import org.springframework.integration.core.MessageSource;
    import org.springframework.integration.dsl.IntegrationFlow;
    import org.springframework.integration.dsl.IntegrationFlows;
    import org.springframework.integration.dsl.core.Pollers;
    import org.springframework.integration.dsl.jms.Jms;
    import org.springframework.integration.support.MessageBuilder;
    import org.springframework.messaging.MessagingException;

    /**
     * Show how to handle error in spring integration flow.
     * Please note, errorChannel in spring integration only applicable to
     * error thrown in asynch component.
     * 
     * 
    @author zakyalvan
     
    */
    @SpringBootApplication
    @IntegrationComponentScan
    public class ErrorHandlingApplication {
        public static void main(String[] args) throws Exception {
            ConfigurableApplicationContext applicationContext = new SpringApplicationBuilder(ErrorHandlingApplication.class)
                    .web(false)
                    .run(args);
            
            Runtime.getRuntime().addShutdownHook(new Thread(() -> applicationContext.close()));
            
            System.out.println("Pres enter key to exit");
            System.in.read();
            System.exit(0);
        }

        @Autowired
        private ConnectionFactory connectionFactory;
        
        @Bean
        public MessageSource<Integer> randomIntegerMessageSource() {
            return () -> MessageBuilder.withPayload(new Random().nextInt()).build();
        }
        
        @Bean
        public IntegrationFlow withErrorFlow() {
            return IntegrationFlows.from(randomIntegerMessageSource(), spec -> spec.poller(Pollers.fixedDelay(1000)))
                        .handle(Jms.outboundGateway(connectionFactory)
                        .requestDestination("processor.input")
                        .replyContainer(spec -> spec.sessionTransacted(true)))
                        .get();
        }
        
        @Autowired
        @Qualifier("errorChannel")
        private PublishSubscribeChannel errorChannel;
        
        @Bean
        public IntegrationFlow errorHandlingFlow() {
            return IntegrationFlows.from(errorChannel)
                    .handle(message -> System.out.println("@@@@@@@@@@@@@@@@@@@@@" + ((MessagingException) message.getPayload()).getFailedMessage().getPayload()))
                    .get();
        }
    }

    posted @ 2020-01-10 15:32 paulwong 閱讀(355) | 評(píng)論 (0)編輯 收藏

    APM資源

    Spring Boot 2 實(shí)戰(zhàn):使用 Spring Boot Admin 監(jiān)控你的應(yīng)用
    https://my.oschina.net/10000000000/blog/3119697

    監(jiān)控管理之Spring Boot Admin使用
    https://my.oschina.net/xiedeshou/blog/2051625


    https://my.oschina.net/janlle/blog/3040749

    posted @ 2019-12-30 16:50 paulwong 閱讀(321) | 評(píng)論 (0)編輯 收藏

    微服務(wù)-網(wǎng)關(guān)

    微服務(wù)開源最強(qiáng)網(wǎng)關(guān)Kong
    https://felord.cn/kong-api-gateway.html

    云原生網(wǎng)關(guān) Kong 和Kong 管理UI Konga的完全安裝攻略
    https://felord.cn/kong-and-konga-install.html




    posted @ 2019-12-30 16:44 paulwong 閱讀(298) | 評(píng)論 (0)編輯 收藏

    2020 年軟件開發(fā)趨勢(shì)預(yù)測(cè)有哪些?

    基礎(chǔ)設(shè)施:條條道路通云端

    對(duì)于云廠商來(lái)說(shuō),2019 年是碩果累累的一年。不僅初創(chuàng)公司在使用云計(jì)算,那些很注重安全的“保守派”公司(如政府機(jī)構(gòu)、醫(yī)療保健機(jī)構(gòu)、銀行、保險(xiǎn)公司,甚至是美國(guó)五角大樓)也在遷移到云端。這種趨勢(shì)在 2020 年將會(huì)繼續(xù),大大小小的公司都將(或者至少有計(jì)劃)遷移到云端。Gartner 公司最近發(fā)布了一個(gè)數(shù)字:

    image.png

    如果你是一個(gè)還在考慮要不要遷移到云端的決策者,不妨重新審視一下你的策略。如果你是一個(gè)獨(dú)立開發(fā)者,并且還沒使用過云基礎(chǔ)設(shè)施,那么完全可以在 2020 年嘗試一下。很多大型的云廠商(如亞馬遜、微軟、谷歌)都提供了免費(fèi)的體驗(yàn)機(jī)會(huì)。谷歌在這方面做得特別大方,它提供了價(jià)值 300 美元的一年免費(fèi)服務(wù)。

    image.png

    策劃注:阿里、騰訊、華為等國(guó)內(nèi)云廠商同樣有免費(fèi)云服務(wù)試用產(chǎn)品。

    云平臺(tái):亞馬遜領(lǐng)頭,其他跟上

    作為第一大云廠商,亞馬遜在 2019 年可謂風(fēng)生水起。憑借其豐富的產(chǎn)品組合,亞馬遜將把它的優(yōu)勢(shì)延續(xù)到 2020 年。Canalys 發(fā)布的 2019 年第三季度報(bào)告指出,大型云廠商(AWS、Azure、GCP)占據(jù) 56% 的市場(chǎng)份額,其中 AWS 獨(dú)享 32.6%。

    image.png

    其他云廠商也在努力縮短與 AWS 之間的差距。微軟把主要目標(biāo)轉(zhuǎn)向了大型企業(yè)。最近,微軟打敗了亞馬遜,從美國(guó)五角大樓拿到了一個(gè) 100 億美元的大單子。這個(gè)單子將提升 Azure 的聲譽(yù),同時(shí)削弱 AWS 的士氣。

    image.png

    谷歌一直在推動(dòng) CNCF,實(shí)現(xiàn)云計(jì)算運(yùn)維的標(biāo)準(zhǔn)化。谷歌的長(zhǎng)期目標(biāo)是讓云遷移變得更容易,方便企業(yè)從 AWS 遷移到 GCP。IBM 之前斥資 360 億美元收購(gòu)了 RedHat,也想要在云計(jì)算市場(chǎng)占有一席之地。

    image.png

    在亞太地區(qū),阿里云市場(chǎng)規(guī)模超過了 AWS、Azure 的總和,全球排名第三。中國(guó)國(guó)內(nèi)騰訊云等企業(yè)的增長(zhǎng)勢(shì)頭也十分迅猛。

    2020 年將出現(xiàn)更多的并購(gòu)。當(dāng)然,很多初創(chuàng)公司將會(huì)帶來(lái)新的想法和創(chuàng)新,例如多云服務(wù)。因?yàn)楦?jìng)爭(zhēng)激烈,這些公司只能從降價(jià)和推出更多的創(chuàng)新產(chǎn)品來(lái)獲取利潤(rùn)。

    容器化:Kubernetes 將會(huì)更酷

    在容器編排領(lǐng)域,雖然一度出現(xiàn)了“三足鼎立”(Kubernetes、Docker Swarm 和 Mesos),但 Kubernetes 最終脫穎而出,成為絕對(duì)的贏家。云是一個(gè)分布式系統(tǒng),而 Kubernetes 是它的 OS(分布式的 Linux)。2019 年北美 KubeCon+CloudNativeCon 大會(huì)的參會(huì)者達(dá)到了 12000 名,比 2018 年增長(zhǎng)了 50%。以下是過去 4 年參會(huì)人數(shù)的增長(zhǎng)情況。

    image.png

    在 2020 年,Kubernetes 不僅不會(huì)后退,只會(huì)變得越來(lái)越強(qiáng),你完全可以把賭注壓在 Kubernetes 身上。另外值得一提的是,Migrantis 最近收購(gòu)了 Docker Enterprise,不過收購(gòu)數(shù)額不詳。

    image.png

    幾年前,人們張口閉口說(shuō)的都是 Docker,而現(xiàn)在換成了 Kubernetes。Docker 在它的全盛時(shí)期未能盈利,反而在優(yōu)勢(shì)漸退幾年之后才嘗試變現(xiàn)。這再次說(shuō)明,在現(xiàn)代技術(shù)世界,時(shí)機(jī)就是一切。

    軟件架構(gòu):微服務(wù)將成為主流

    谷歌趨勢(shì)表明,微服務(wù)架構(gòu)范式在 2019 年持續(xù)增長(zhǎng)了一整年。

    image.png

    隨著軟件行業(yè)整體逐步遷移到云端,微服務(wù)也將成為占主導(dǎo)地位的架構(gòu)范式。微服務(wù)架構(gòu)崛起的一個(gè)主要原因是它與云原生完美契合,可以實(shí)現(xiàn)快速的軟件開發(fā)。我在之前的一篇博文中解釋了微服務(wù)架構(gòu)的基本原則及其優(yōu)勢(shì)和劣勢(shì)。

    https://towardsdatascience.com/microservice-architecture-a-brief-overview-and-why-you-should-use-it-in-your-next-project-a17b6e19adfd

    我假設(shè)現(xiàn)在也存在一種回歸到單體架構(gòu)的趨勢(shì),因?yàn)樵诤芏嗲闆r下,微服務(wù)架構(gòu)有點(diǎn)過頭了,而且做好微服務(wù)架構(gòu)設(shè)計(jì)其實(shí)很難。微服務(wù)架構(gòu)有哪些好的實(shí)踐?在之前的另一篇博文中,我也給出了一些大概,希望對(duì)讀者有用。

    https://towardsdatascience.com/effective-microservices-10-best-practices-c6e4ba0c6ee2

    編程語(yǔ)言(整體):Python 將吞噬世界

    機(jī)器學(xué)習(xí)、數(shù)據(jù)分析、數(shù)據(jù)處理、Web 開發(fā)、企業(yè)軟件開發(fā),甚至是拼接黑洞照片,Python 的影子無(wú)處不在。

    在著名的編程語(yǔ)言排行榜網(wǎng)站 TIOBE 上,Python 位居最流行編程語(yǔ)言第三位,僅次于 Java 和 C 語(yǔ)言。

    image.png

    更有意思的是,在 2019 年,Python 的流行度翻了一番(從 5% 到 10%)。

    Python 的崛起將在 2020 年延續(xù),并縮短與 Java 和 C 語(yǔ)言之間的差距。另一門無(wú)所不在的編程語(yǔ)言 JavaScript 正面臨下行的風(fēng)險(xiǎn)。為什么 Python 的勢(shì)頭會(huì)如此強(qiáng)勁?因?yàn)樗娜胧珠T檻低,有一個(gè)優(yōu)秀的社區(qū)在支持,并受到數(shù)據(jù)科學(xué)家和新生代開發(fā)者的喜愛。

    編程語(yǔ)言(企業(yè)方面):Java 將占主導(dǎo)

    之前的 TIOBE 網(wǎng)站截圖顯示,Java 仍然是一門占主導(dǎo)地位的編程語(yǔ)言,并將在 2020 年繼續(xù)保持這種地位。JVM 是 Java 的基石,其他編程語(yǔ)言(如 Kotlin、Scala、Clojure、Groovy)也將 JVM 作為運(yùn)行時(shí)。最近,Oracle 修改了 JVM 的許可協(xié)議。

    image.png

    新的許可協(xié)議意味著使用 Java、Kotlin、Scala 或其他 JVM 編程語(yǔ)言的公司需要向 Oracle 支付大額費(fèi)用。所幸的是,OpenJDK 讓 JVM 繼續(xù)免費(fèi)。另外,還有其他一些公司為 JVM 提供企業(yè)支持。

    image.png

    因?yàn)轶w積和速度方面的問題,基于 JVM 的編程語(yǔ)言并不適合用在今天的無(wú)服務(wù)器環(huán)境中。Oracle 正在推動(dòng) GraalVM 計(jì)劃,旨在讓 Java 變得更加敏捷和快速,讓它更適合用在無(wú)服務(wù)器環(huán)境中。因?yàn)槌?Java,沒有其他編程語(yǔ)言可以提供企業(yè)級(jí)的穩(wěn)定性和可靠性,所以 Java 將在 2020 年繼續(xù)占主導(dǎo)地位。

    企業(yè)版 Java:Spring 繼續(xù)發(fā)力

    曾幾何時(shí),在企業(yè)開發(fā)領(lǐng)域,Spring 和 JavaEE 之間存在著白熱化的競(jìng)爭(zhēng)。但因?yàn)?Oracle 在 JavaEE 方面沒有作為,在競(jìng)爭(zhēng)中慘敗,這導(dǎo)致了“MicroProfile”計(jì)劃的形成,并最終促成了 JakartaEE。

    雖然所有的政策和活動(dòng)都是圍繞 JavaEE 展開,但 Spring 事實(shí)上已經(jīng)贏得了這場(chǎng)企業(yè) JVM 之爭(zhēng)。2020 年,Spring 將成為 JVM 生態(tài)系統(tǒng)的頭牌。

    有兩個(gè)正在進(jìn)展中的項(xiàng)目,它們旨在減小 Java 的體積,讓它更適合用在無(wú)服務(wù)器環(huán)境中。

    其中一個(gè)是 Micronaut(https://micronaut.io/)。

    image.png

    另一個(gè)是 Quarkus(https://quarkus.io/)。

    image.png

    這兩個(gè)項(xiàng)目都使用了 GraalVM,它們?cè)?2020 年將會(huì)得到 Java 社區(qū)更多的關(guān)注。

    編程語(yǔ)言:后起之秀的突破

    2000 年代,編程語(yǔ)言的發(fā)展出現(xiàn)了停滯。大多數(shù)人認(rèn)為沒有必要再去開發(fā)新的編程語(yǔ)言,Java、C 語(yǔ)言、C++、JavaScript 和 Python 已經(jīng)可以滿足所有的需求。但是,谷歌的 Go 語(yǔ)言為新編程語(yǔ)言大門打開了一扇大門。在過去十年出現(xiàn)了很多有趣的編程語(yǔ)言,比如 Rust、Swift、Kotlin、TypeScript。導(dǎo)致這種情況的一個(gè)主要原因是已有的編程語(yǔ)言無(wú)法充分利用硬件優(yōu)勢(shì)(例如多核、更快的網(wǎng)絡(luò)、云)。另一個(gè)原因是現(xiàn)代編程語(yǔ)言更加關(guān)注開發(fā)者經(jīng)濟(jì),即實(shí)現(xiàn)更快速更容易的開發(fā)。在 Stackoverflow 提供的一份開發(fā)者報(bào)告中,排名靠前的現(xiàn)代編程語(yǔ)言如下所示(Rust 連續(xù) 4 年名列第一)。

    image.png

    在之前的一篇博文中,我深入探討了現(xiàn)代編程語(yǔ)言,對(duì)比 Rust 和 Go 語(yǔ)言,并說(shuō)明了為什么現(xiàn)在是采用這些語(yǔ)言的好時(shí)機(jī)。

    https://towardsdatascience.com/back-to-the-metal-top-3-programming-language-to-develop-big-data-frameworks-in-2019-69a44a36a842

    最近,微軟宣布他們?cè)谔剿魇褂?Rust 來(lái)開發(fā)更安全的軟件。

    image.png

    亞馬遜最近也宣布要贊助 Rust。

    image.png

    谷歌宣布將 Kotlin 作為 Android 官方開發(fā)語(yǔ)言,所以,在 JVM 領(lǐng)域,Kotlin 成了 Java 的主要競(jìng)爭(zhēng)對(duì)手。

    image.png

    Angular 使用 TypeScript 代替 JavaScript,將其作為主要的編程語(yǔ)言,其他 JavaScript 框架(如 React 和 Vue)也開始為 TypeScript 提供更多的支持。

    這種趨勢(shì)將在 2020 年延續(xù)下去,很多巨頭公司將會(huì)深入了解新一代編程語(yǔ)言(如 Rust、Swift、TypeScript、Kotlin),它們會(huì)站出來(lái)公開表示支持。

    Web:JavaScript 繼續(xù)占主導(dǎo)地位

    曾幾何時(shí),JavaScript 并不被認(rèn)為是一門強(qiáng)大的編程語(yǔ)言。在當(dāng)時(shí),前端內(nèi)容主要通過后端框架在服務(wù)器端進(jìn)行渲染。2014 年,AngularJS 的出現(xiàn)改變了這種局面。從那個(gè)時(shí)候開始,更多的 JavaScript 框架開始涌現(xiàn)(Angular 2+、React、Vue、Meteor),JavaScript 已然成為主流的 Web 開發(fā)語(yǔ)言。隨著 JavaScript 框架不斷創(chuàng)新以及微服務(wù)架構(gòu)的崛起,JavaScript 框架在 2020 年將繼續(xù)主導(dǎo)前端開發(fā)。

    JavaScript 框架:React 閃耀

    雖然 React 是在 AngularJS 之后出現(xiàn)的,但在過去十年對(duì) Web 開發(fā)產(chǎn)生了巨大的影響,這也讓 Facebook 在與 Google+ 的競(jìng)爭(zhēng)中打了一場(chǎng)勝戰(zhàn)。React 為前端開發(fā)帶來(lái)了一些新的想法,比如事件溯源、虛擬 DOM、單向數(shù)據(jù)綁定、基于組件的開發(fā),等等。它對(duì)開發(fā)者社區(qū)產(chǎn)生了重大影響,以至于谷歌放棄了 AngularJS,并借鑒 React 的想法推出了徹底重寫的 Angular 2+。React 是目前為止最為流行的 JavaScript 框架,下圖顯示了相關(guān)的 NPM 下載統(tǒng)計(jì)信息。

    image.png

    為了獲得更好的并發(fā)和用戶體驗(yàn),F(xiàn)acebook 宣布完全重寫 React 的核心算法,推出了 React-Fiber 項(xiàng)目。

    image.png

    2020 年,React 仍然是你開發(fā)新項(xiàng)目的首選 Web 框架。其他框架(如 Angular/Angular 2+ 或 Vue)呢?Angular 仍然是一個(gè)不錯(cuò)的 Web 開發(fā)框架,特別適合企業(yè)開發(fā)。我敢肯定谷歌在未來(lái)幾年會(huì)在 Angular 上加大投入。Vue 是另一個(gè)非常流行的 Web 框架,由中國(guó)的巨頭公司阿里巴巴提供支持。如果你已經(jīng)在使用 Angular 或 Vue,就沒必要再遷移到 React 了。

    App 開發(fā):原生應(yīng)用

    在移動(dòng) App 開發(fā)方面,有關(guān)混合應(yīng)用開發(fā)的炒作有所消停。混合開發(fā)提供了更快的開發(fā)速度,因?yàn)橹恍枰粋€(gè)開發(fā)團(tuán)隊(duì),而不是多個(gè)。但原生應(yīng)用提供了更好的用戶體驗(yàn)和性能。另外,混合應(yīng)用需要經(jīng)過調(diào)整才能使用一些高級(jí)特性。對(duì)于企業(yè)來(lái)說(shuō),原生應(yīng)用仍然是首選的解決方案,這種趨勢(shì)將在 2020 年延續(xù)。Airbnb 在一篇博文中非常詳細(xì)地說(shuō)明了為什么他們要放棄混合應(yīng)用開發(fā)平臺(tái) React Native。

    https://medium.com/airbnb-engineering/sunsetting-react-native-1868ba28e30a

    盡管 Facebook 嘗試改進(jìn) React Native,谷歌也非常努力地推動(dòng)混合 App 開發(fā)平臺(tái) Flutter,但它們?nèi)匀恢贿m合用于原型、POC、MVP 或輕量級(jí)應(yīng)用的開發(fā)。所以,原生應(yīng)用在 2020 年仍將繼續(xù)占主導(dǎo)地位。

    在原生應(yīng)用開發(fā)方面,谷歌和蘋果分別將 Kotlin 和 Swift 作為各自平臺(tái)主要的編程語(yǔ)言。谷歌最近再次重申了對(duì) Kotlin 的支持,這對(duì)于 Kotlin 用戶來(lái)說(shuō)無(wú)疑是個(gè)好消息。

    image.png

    混合應(yīng)用開發(fā):React Native

    在很多情況下,混合應(yīng)用是個(gè)不錯(cuò)的選擇。在這方面也有很多選擇:Xamarin、Inoic、React Native 和 Flutter。Facebook 基于成熟的 React 框架推出了 React Native。就像 React 在 Web 框架領(lǐng)域占據(jù)主導(dǎo)地位一樣,React Native 在混合應(yīng)用領(lǐng)域也占據(jù)著主導(dǎo)地位,如下圖所示。

    image.png

    React Native 和 React 有共同的基因,都提供了高度的代碼重用性以及“一次開發(fā),到處運(yùn)行”的能力。React Native 的另一個(gè)優(yōu)勢(shì)是 Facebook 本身也用它來(lái)開發(fā)移動(dòng)應(yīng)用。谷歌在這個(gè)領(lǐng)域起步較晚,但在去年,谷歌的混合應(yīng)用開發(fā)框架 Flutter 獲得了不少關(guān)注。Flutter 提供了更好的性能,但需要使用另一門不是那么流行的編程語(yǔ)言 Dart。React Native 在 2020 年將繼續(xù)占主導(dǎo)地位。

    API:REST 將占主導(dǎo)地位

    REST 是 API 領(lǐng)域事實(shí)上的標(biāo)準(zhǔn),被廣泛用在基于 API 的服務(wù)間通信上。當(dāng)然,除了 REST,我們還有其他選擇,比如來(lái)自谷歌的 gRPC 和來(lái)自 Facebook 的 GraphQL。

    它們提供了不同的能力。谷歌開發(fā)的 gRPC 作為遠(yuǎn)程過程調(diào)用(如 SOAP)的化身,使用 Protobuf 代替 JSON 作為消息格式。Facebook 開發(fā)的 GraphQL 作為一個(gè)集成層,避免頻繁的 REST 調(diào)用。gRPC 和 GraphQL 都在各自的領(lǐng)域取得了成功。2020 年,REST 仍然是占主導(dǎo)地位的 API 技術(shù),而 GraphQL 和 gRPC 將作為補(bǔ)充技術(shù)。

    人工智能:Tensorflow 2.0 將占主導(dǎo)地位

    谷歌和 Facebook 也是深度學(xué)習(xí) / 神經(jīng)網(wǎng)絡(luò)領(lǐng)域的主要玩家。谷歌基于深度學(xué)習(xí)框架 Theano 推出了 TensorFlow,它很快就成為深度學(xué)習(xí) / 神經(jīng)網(wǎng)絡(luò)的主要開發(fā)庫(kù)。谷歌還推出了特別設(shè)計(jì)的 GPU(TPU)來(lái)加速 TensorFlow 的計(jì)算。

    Facebook 在深度學(xué)習(xí)領(lǐng)域也不甘落后,他們擁有世界上最大的圖像和視頻數(shù)據(jù)集合。Facebook 基于另一個(gè)深度學(xué)習(xí)庫(kù) Torch 推出了深度學(xué)習(xí)庫(kù) PyTorch。TensorFlow 和 PyTorch 之間有一些區(qū)別,前者使用的是靜態(tài)圖進(jìn)行計(jì)算,而 PyTorch 使用的是動(dòng)態(tài)圖。使用動(dòng)態(tài)圖的好處是可以在運(yùn)行時(shí)糾正自己。另外,PyTorch 對(duì) Python 支持更好,而 Python 是數(shù)據(jù)科學(xué)領(lǐng)域的一門主要編程語(yǔ)言。

    隨著 PyTorch 變得越來(lái)越流行,谷歌也趕緊在 2019 年 10 月推出了 TensorFlow 2.0,也使用了動(dòng)態(tài)圖,對(duì) Python 的支持也更好。

    image.png

    2020 年,TensorFlow 2.0 和 PyTorch 將齊頭并進(jìn)。考慮到 TensorFlow 擁有更大的社區(qū),我估計(jì) TensorFlow 2.0 將成為占主導(dǎo)地位的深度學(xué)習(xí)庫(kù)。

    數(shù)據(jù)庫(kù):SQL是王者,分布式SQL是王后

    在炒作 NoSQL 的日子里,人們嘲笑 SQL,還指出了 SQL 的種種不足。有很多文章說(shuō) NoSQL 有多么的好,并將要取代 SQL。但等到炒作的潮水褪去,人們很快就意識(shí)到,我們的世界不能沒有 SQL。以下是最流行的數(shù)據(jù)庫(kù)的排名。

    image.png

    可以看到,SQL 數(shù)據(jù)庫(kù)占據(jù)了前四名。SQL 之所以占主導(dǎo)地位,是因?yàn)樗峁┝?ACID 事務(wù)保證,而 ACID 是業(yè)務(wù)系統(tǒng)最潛在的需求。NoSQL 數(shù)據(jù)庫(kù)提供了橫向伸縮能力,但代價(jià)是不提供 ACID 保證。

    互聯(lián)網(wǎng)公司一直在尋找“大師級(jí)數(shù)據(jù)庫(kù)”,也就是既能提供 ACID 保證又能像 NoSQL 那樣可橫向伸縮的數(shù)據(jù)庫(kù)。目前有兩個(gè)解決方案可以部分滿足對(duì)“大師級(jí)數(shù)據(jù)庫(kù)”的要求,一個(gè)是亞馬遜的 Aurora,一個(gè)是谷歌的 Spanner。Aurora 提供了幾乎所有的 SQL 功能,但不支持橫向?qū)懮炜s,而 Spanner 提供了橫向?qū)懮炜s能力,但對(duì) SQL 支持得不好。

    2020 年,但愿這兩個(gè)數(shù)據(jù)庫(kù)能夠越走越近,或者有人會(huì)帶來(lái)一個(gè)“分布式 SQL”數(shù)據(jù)庫(kù)。如果真有人做到了,那一定要給他頒發(fā)圖靈獎(jiǎng)。

    數(shù)據(jù)湖:MinIO 將要崛起

    現(xiàn)代數(shù)據(jù)平臺(tái)非常的復(fù)雜。企業(yè)一般都會(huì)有支持 ACID 事務(wù)的 OLTP 數(shù)據(jù)庫(kù)(SQL),也會(huì)有用于數(shù)據(jù)分析的 OLAP 數(shù)據(jù)庫(kù)(NoSQL)。除此之外,它們還有其他各種數(shù)據(jù)存儲(chǔ)系統(tǒng),比如用于搜索的 Solr、ElasticSearch,用于計(jì)算的 Spark。企業(yè)基于數(shù)據(jù)庫(kù)構(gòu)建自己的數(shù)據(jù)平臺(tái),將 OLTP 數(shù)據(jù)庫(kù)的數(shù)據(jù)拷貝到數(shù)據(jù)湖中。各種類型的數(shù)據(jù)應(yīng)用程序(比如 OLAP、搜索)將數(shù)據(jù)湖作為它們的事實(shí)來(lái)源。

    HDFS 原本是事實(shí)上的數(shù)據(jù)湖,直到亞馬遜推出了對(duì)象存儲(chǔ) S3。S3 可伸縮,價(jià)格便宜,很快就成為很多公司事實(shí)上的數(shù)據(jù)湖。使用 S3 唯一的問題是數(shù)據(jù)平臺(tái)被緊緊地綁定在亞馬遜的 AWS 云平臺(tái)上。雖然微軟 Azure 推出了 Blob Storage,谷歌也有類似的對(duì)象存儲(chǔ),但都不是 S3 的對(duì)手。

    對(duì)于很多公司來(lái)說(shuō),MinIO 或許是它們的救星。MinIO 是一個(gè)開源的對(duì)象存儲(chǔ),與 S3 兼容,提供了企業(yè)級(jí)的支持,并專門為云原生環(huán)境而構(gòu)建,提供了與云無(wú)關(guān)的數(shù)據(jù)湖。

    image.png

    微軟在 Azure Marketplace 是這么描述 MinIO 的:“為 Azure Blog Storage 服務(wù)提供與亞馬遜 S3 API 兼容的數(shù)據(jù)訪問”。如果谷歌 GCP 和其他云廠商也提供 MinIO,那么我們將會(huì)向多云邁出一大步。

    大數(shù)據(jù)批處理:Spark 將繼續(xù)閃耀

    現(xiàn)如今,企業(yè)通常需要基于大規(guī)模數(shù)據(jù)執(zhí)行計(jì)算,所以需要分布式的批處理作業(yè)。Hadoop 的 Map-Reduce 是第一個(gè)分布式批處理平臺(tái),后來(lái) Spark 取代了 Hadoop 的地位,成為真正的批處理之王。Spark 是怎樣提供了比 Hadoop 更好的性能的?我之前寫了另一篇文章,對(duì)現(xiàn)代數(shù)據(jù)平臺(tái)進(jìn)行了深入分析。

    https://towardsdatascience.com/programming-language-that-rules-the-data-intensive-big-data-fast-data-frameworks-6cd7d5f754b0

    Spark 解決了 Hadoop Map-Reduce 的痛點(diǎn),它將所有東西放在內(nèi)存中,而不是在完成每一個(gè)昂貴的操作之后把數(shù)據(jù)保存在存儲(chǔ)系統(tǒng)中。盡管 Spark 重度使用 CPU 和 JVM 來(lái)執(zhí)行批處理作業(yè),但這并不妨礙它成為 2020 年批處理框架之王。我希望有人能夠使用 Rust 開發(fā)出一個(gè)更加高效的批處理框架,取代 Spark,并為企業(yè)省下大量的云資源費(fèi)用。

    大數(shù)據(jù)流式處理:Flink 是未來(lái)

    幾年前,實(shí)現(xiàn)實(shí)時(shí)的流式處理幾乎是不可能的事情。一些微批次處理框架(比如 Spark Streaming)可以提供“幾近”實(shí)時(shí)的流式處理能力。不過,F(xiàn)link 改變了這一狀況,它提供了實(shí)時(shí)的流式處理能力。

    2019 年之前,F(xiàn)link 未能得到足夠的關(guān)注,因?yàn)樗鼰o(wú)法撼動(dòng) Spark。直到 2019 年 1 月份,中國(guó)巨頭公司阿里巴巴收購(gòu)了 Data Artisan(Flink 背后的公司)。

    image.png

    在 2020 年,企業(yè)如果想要進(jìn)行實(shí)時(shí)流式處理,F(xiàn)link 應(yīng)該是不二之選。不過,跟 Spark 一樣,F(xiàn)link 同樣重度依賴 CPU 和 JVM,并且需要使用大量的云資源。

    字節(jié)碼:WebAssembly將被廣泛采用

    我從 JavaScript 作者 Brandon Eich 的一次訪談中知道了 WebAssembly 這個(gè)東西。現(xiàn)代 JavaScript(ES5 之后的版本)是一門優(yōu)秀的編程語(yǔ)言,但與其他編程語(yǔ)言一樣,都有自己的局限性。最大的局限性是 JavaScript 引擎在執(zhí)行 JavaScript 時(shí)需要讀取、解析和處理“抽象語(yǔ)法樹”。另一個(gè)問題是 JavaScript 的單線程模型無(wú)法充分利用現(xiàn)代硬件(如多核 CPU 或 GPU)。正因?yàn)檫@些原因,很多計(jì)算密集型的應(yīng)用程序(如游戲、3D 圖像)無(wú)法運(yùn)行在瀏覽器中。

    一些公司(由 Mozilla 帶領(lǐng))開發(fā)了 WebAssembly,一種底層字節(jié)碼格式,讓任何一門編程語(yǔ)言都可以在瀏覽器中運(yùn)行。目前發(fā)布的 WebAssembly 版本可以支持 C++、Rust 等。

    image.png

    WebAssembly 讓計(jì)算密集型應(yīng)用程序(比如游戲和 AutoCAD)可以在瀏覽器中運(yùn)行。不過,WebAssembly 的目標(biāo)不僅限于此,它還要讓應(yīng)用程序可以在瀏覽器之外運(yùn)行。WebAssembly 可以被用在以下這些“瀏覽器外”的場(chǎng)景中。

    • 移動(dòng)設(shè)備上的混合原生應(yīng)用。
    • 沒有冷啟動(dòng)問題的無(wú)服務(wù)器計(jì)算。
    • 在服務(wù)器端執(zhí)行不受信任的代碼。
      我預(yù)測(cè),2020 年將是 WebAssembly 取得突破的一年,很多巨頭公司(包括云廠商)和社區(qū)將會(huì)擁抱 WebAssembly。

    代碼:低代碼 / 無(wú)代碼將更進(jìn)一步

    快速的數(shù)字化和工業(yè) 4.0 革命意味著軟件開發(fā)者的供需缺口巨大。由于缺乏開發(fā)人員,很多企業(yè)無(wú)法實(shí)現(xiàn)它們的想法。為了降低進(jìn)入軟件開發(fā)的門檻,可以嘗試無(wú)代碼(No Code)或低代碼(Low Code)軟件開發(fā),也就是所謂的 LCNC(Low-Code No-Code)。它已經(jīng)在 2019 年取得了一些成功。

    image.png

    LCNC 的目標(biāo)是讓沒有編程經(jīng)驗(yàn)的人也能開發(fā)軟件,只要他們想要實(shí)現(xiàn)自己的想法。

    雖然我對(duì)在正式環(huán)境中使用 LCNC 框架仍然心存疑慮,但它為其他公司奠定了良好的基礎(chǔ),像亞馬遜和谷歌這樣的公司可以基于這個(gè)基礎(chǔ)構(gòu)建出有用的產(chǎn)品,就像 AWS Lambda 的蓬勃發(fā)展是以谷歌 App Engine 為基礎(chǔ)。

    2020 年,LCNC 將會(huì)獲得更多關(guān)注。

    posted @ 2019-12-30 09:09 paulwong 閱讀(354) | 評(píng)論 (0)編輯 收藏

    How to provide a Spring Boot "fat JAR" with external dependencies

    發(fā)現(xiàn)loader.path放在properties文件中時(shí),不起作用,要以-Dloader.path=lib/的方式才行。

    http://www.codevomit.xyz/bootlog/blog/how-to-provide-spring-boot-fat-jar


    https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-executable-jar-format.html

    posted @ 2019-12-27 15:47 paulwong 閱讀(305) | 評(píng)論 (0)編輯 收藏

    解決“/bin/bash^M: bad interpreter: No such file or directory”

    在執(zhí)行shell腳本時(shí)提示這樣的錯(cuò)誤主要是由于shell腳本文件是dos格式,即每一行結(jié)尾以\r\n來(lái)標(biāo)識(shí),而unix格式的文件行尾則以\n來(lái)標(biāo)識(shí)。
    查看腳本文件是dos格式還是unix格式的幾種辦法。
    (1)cat -A filename 從顯示結(jié)果可以判斷,dos格式的文件行尾為^M$,unix格式的文件行尾為$。
    (2)od -t x1 filename 如果看到輸出內(nèi)容中存在0d 0a的字符,那么文件是dos格式,如果只有0a,則是unix格式。
    (3)vi filename打開文件,執(zhí)行 : set ff,如果文件為dos格式在顯示為fileformat=dos,如果是unxi則顯示為fileformat=unix。

    解決方法:
    (1)使用linux命令dos2unix filename,直接把文件轉(zhuǎn)換為unix格式
    (2)使用sed命令sed -i -e 's/\r$//' filename 或者 sed -i "s/^M//" filename直接替換結(jié)尾符為unix格式
    (3)vi filename打開文件,執(zhí)行 : set ff=unix 設(shè)置文件為unix,然后執(zhí)行:wq,保存成unix格式。

    posted @ 2019-12-11 13:42 paulwong 閱讀(304) | 評(píng)論 (0)編輯 收藏

    僅列出標(biāo)題
    共115頁(yè): First 上一頁(yè) 20 21 22 23 24 25 26 27 28 下一頁(yè) Last 
    主站蜘蛛池模板: 国产男女猛烈无遮挡免费视频| 69免费视频大片| www成人免费观看网站| 视频一区二区三区免费观看| 九九免费观看全部免费视频| 亚洲免费网站观看视频| 日本免费一二区在线电影| 久久久久亚洲av成人无码电影| 亚洲精品无码精品mV在线观看| 亚洲av永久无码精品表情包| 亚洲最新黄色网址| 成人亚洲国产va天堂| 最新亚洲人成网站在线观看| 久久不见久久见免费影院www日本| 免费无码H肉动漫在线观看麻豆| 中文字幕在线免费观看| 黄a大片av永久免费| 亚洲国产日韩在线观频| 国产AV无码专区亚洲Av| 亚洲人妖女同在线播放| 免费人成动漫在线播放r18| 午夜精品射精入后重之免费观看| 在线观看av永久免费| 亚洲色图在线观看| 亚洲国产精品无码久久98| 中文字幕乱码系列免费| 野花高清在线观看免费3中文| 久久亚洲日韩精品一区二区三区| 猫咪www免费人成网站| 免费看AV毛片一区二区三区| 国产成人精品日本亚洲专一区| selaoban在线视频免费精品| 性xxxxx免费视频播放| 亚洲国产人成精品| 色www免费视频| 又黄又大又爽免费视频| 亚洲国产精品成人精品小说| 中文字幕无码免费久久| 亚洲乳大丰满中文字幕| 亚洲AV无码男人的天堂| 6080午夜一级毛片免费看|