portaldacalheta.pt
  • หลัก
  • ทีมแบบกระจาย
  • เคล็ดลับและเครื่องมือ
  • ชีวิตนักออกแบบ
  • นวัตกรรม
เทคโนโลยี

Microservice Communication: บทช่วยสอนเกี่ยวกับ Spring Integration กับ Redis



สถาปัตยกรรม Microservice เป็นแนวทางที่ได้รับความนิยมอย่างมากในการออกแบบและใช้งานเว็บแอปพลิเคชันที่ปรับขนาดได้สูง การสื่อสารภายในแอปพลิเคชันเสาหินระหว่างส่วนประกอบมักจะขึ้นอยู่กับการเรียกใช้วิธีการหรือฟังก์ชันภายในกระบวนการเดียวกัน ในทางกลับกันแอปพลิเคชันที่ใช้ไมโครเซอร์วิสเป็นระบบกระจายที่ทำงานบนเครื่องหลายเครื่อง

การสื่อสารระหว่างไมโครเซอร์วิสเหล่านี้มีความสำคัญเพื่อให้ระบบมีเสถียรภาพและปรับขนาดได้ มีหลายวิธีในการดำเนินการนี้ การสื่อสารด้วยข้อความเป็นวิธีหนึ่งในการดำเนินการนี้อย่างน่าเชื่อถือ



ตัวอย่างโหนด js ส่วนที่เหลือไคลเอ็นต์

เมื่อใช้การรับส่งข้อความส่วนประกอบจะโต้ตอบกันโดยการแลกเปลี่ยนข้อความแบบอะซิงโครนัส มีการแลกเปลี่ยนข้อความผ่านช่องทาง



การแสดงภาพกราฟิกของระบบการส่งข้อความที่อำนวยความสะดวกในการสื่อสารระหว่างบริการ A และบริการ B



เมื่อบริการ A ต้องการสื่อสารกับบริการ B แทนที่จะส่งโดยตรง A จะส่งไปยังช่องเฉพาะ เมื่อ Service B ต้องการอ่านข้อความจะรับข้อความจากช่องข้อความเฉพาะ

ในบทช่วยสอน Spring Integration นี้คุณจะได้เรียนรู้วิธีใช้การส่งข้อความในแอปพลิเคชัน Spring โดยใช้ Redis คุณจะเดินผ่านแอปพลิเคชันตัวอย่างที่บริการหนึ่งกำลังผลักดันเหตุการณ์ในคิวและอีกบริการหนึ่งกำลังประมวลผลเหตุการณ์เหล่านี้ทีละรายการ



การรวมสปริง

โครงการ Spring Integration ขยายกรอบ Spring เพื่อให้การสนับสนุนการส่งข้อความระหว่างหรือภายในแอปพลิเคชันที่ใช้ Spring ส่วนประกอบต่างๆเชื่อมต่อกันผ่านกระบวนทัศน์การส่งข้อความ ส่วนประกอบส่วนบุคคลอาจไม่ทราบถึงส่วนประกอบอื่น ๆ ในแอปพลิเคชัน

Spring Integration มีกลไกมากมายในการสื่อสารกับระบบภายนอก อะแด็ปเตอร์ช่องสัญญาณเป็นกลไกหนึ่งที่ใช้สำหรับการรวมทางเดียว (ส่งหรือรับ) และเกตเวย์ใช้สำหรับสถานการณ์การร้องขอ / ตอบกลับ (ขาเข้าหรือขาออก)



Apache Camel เป็นอีกทางเลือกหนึ่งที่ใช้กันอย่างแพร่หลาย โดยปกติแล้วการรวมสปริงเป็นที่ต้องการในบริการที่ใช้สปริงที่มีอยู่เนื่องจากเป็นส่วนหนึ่งของระบบนิเวศของสปริง

Redis

Redis เป็นที่เก็บข้อมูลในหน่วยความจำที่รวดเร็วมาก สามารถเลือกที่จะคงอยู่ในดิสก์ได้เช่นกัน สนับสนุนโครงสร้างข้อมูลที่แตกต่างกันเช่นคู่คีย์ - ค่าอย่างง่ายชุดคิว ฯลฯ



การใช้ Redis เป็นคิวทำให้การแชร์ข้อมูลระหว่างส่วนประกอบและการปรับขนาดแนวนอนทำได้ง่ายขึ้นมาก ผู้ผลิตหรือผู้ผลิตหลายรายสามารถส่งข้อมูลไปยังคิวและผู้บริโภคหรือผู้บริโภคหลายรายสามารถดึงข้อมูลและประมวลผลเหตุการณ์ได้

ผู้บริโภคหลายรายไม่สามารถใช้เหตุการณ์เดียวกันได้ซึ่งจะทำให้แน่ใจได้ว่ามีการประมวลผลเหตุการณ์หนึ่งครั้ง



แผนภาพแสดงสถาปัตยกรรมของผู้ผลิต / ผู้บริโภค

ประโยชน์ของการใช้ Redis เป็นคิวข้อความ:



  • การดำเนินการแบบขนานของงานที่ไม่ต่อเนื่องในรูปแบบที่ไม่ปิดกั้น
  • ประสิทธิภาพที่ยอดเยี่ยม
  • เสถียรภาพ
  • ตรวจสอบและแก้ไขจุดบกพร่องได้ง่าย
  • ติดตั้งและใช้งานง่าย

กฎ:

  • การเพิ่มงานในคิวควรเร็วกว่าการประมวลผลงานเอง
  • การบริโภคงานควรเร็วกว่าการผลิต (และถ้าไม่มีให้เพิ่มผู้บริโภคมากขึ้น)

การรวมสปริงกับ Redis

ต่อไปนี้จะอธิบายถึงการสร้างแอปพลิเคชันตัวอย่างเพื่ออธิบายวิธีใช้ Spring Integration กับ Redis

สมมติว่าคุณมีแอปพลิเคชันที่อนุญาตให้ผู้ใช้เผยแพร่โพสต์ และคุณต้องการสร้างคุณลักษณะการติดตาม ข้อกำหนดอีกประการหนึ่งคือทุกครั้งที่มีคนเผยแพร่โพสต์ผู้ติดตามทุกคนควรได้รับแจ้งผ่านช่องทางการสื่อสารบางช่องทาง (เช่นอีเมลหรือข้อความ Push)

วิธีหนึ่งในการนำไปใช้คือการส่งอีเมลไปยังผู้ติดตามแต่ละคนเมื่อผู้ใช้เผยแพร่บางสิ่ง แต่จะเกิดอะไรขึ้นเมื่อผู้ใช้มีผู้ติดตาม 1,000 คน? และเมื่อผู้ใช้ 1,000 คนเผยแพร่บางสิ่งใน 10 วินาทีแต่ละคนมีผู้ติดตาม 1,000 คน? นอกจากนี้โพสต์ของผู้เผยแพร่จะรอจนกว่าอีเมลทั้งหมดจะถูกส่งหรือไม่

ระบบแบบกระจายช่วยแก้ไขปัญหานี้

ปัญหาเฉพาะนี้สามารถแก้ไขได้โดยใช้คิว บริการ A (ผู้ผลิต) ซึ่งรับผิดชอบในการเผยแพร่โพสต์จะดำเนินการดังกล่าว จะเผยแพร่โพสต์และพุชกิจกรรมพร้อมรายชื่อผู้ใช้ที่ต้องรับอีเมลและโพสต์นั้นเอง รายชื่อผู้ใช้สามารถดึงได้จากบริการ B แต่เพื่อความง่ายของตัวอย่างนี้เราจะส่งจากบริการ A

นี่คือการดำเนินการแบบอะซิงโครนัส ซึ่งหมายความว่าบริการที่เผยแพร่จะไม่ต้องรอส่งอีเมล

แอปสาธิตวัสดุเชิงมุม 2

บริการ B (ผู้บริโภค) จะดึงเหตุการณ์ออกจากคิวและดำเนินการ ด้วยวิธีนี้เราสามารถปรับขนาดบริการของเราได้อย่างง่ายดายและเรามี n ผู้บริโภคส่งอีเมล (ประมวลผลเหตุการณ์)

เริ่มต้นด้วยการนำไปใช้ในบริการของผู้ผลิต การอ้างอิงที่จำเป็น ได้แก่ :

redis.clients jedis org.springframework.data spring-data-redis org.springframework.integration spring-integration-redis

การพึ่งพา Maven ทั้งสามนี้จำเป็น:

  • Jedis เป็นลูกค้าของ Redis
  • การพึ่งพา Spring Data Redis ช่วยให้ใช้ Redis ใน Java ได้ง่ายขึ้น ให้แนวคิด Spring ที่คุ้นเคยเช่นคลาสเทมเพลตสำหรับการใช้งาน API หลักและการเข้าถึงข้อมูลสไตล์พื้นที่เก็บข้อมูลที่มีน้ำหนักเบา
  • Spring Integration Redis ให้ส่วนขยายของรูปแบบการเขียนโปรแกรม Spring เพื่อสนับสนุนสิ่งที่เป็นที่รู้จัก รูปแบบการรวมองค์กร .

ต่อไปเราต้องกำหนดค่าไคลเอนต์ Jedis:

@Configuration public class RedisConfig { @Value('${redis.host}') private String redisHost; @Value('${redis.port:6379}') private int redisPort; @Bean public JedisPoolConfig poolConfig() { JedisPoolConfig poolConfig = new JedisPoolConfig(); poolConfig.setMaxTotal(128); return poolConfig; } @Bean public RedisConnectionFactory redisConnectionFactory(JedisPoolConfig poolConfig) { final JedisConnectionFactory connectionFactory = new JedisConnectionFactory(); connectionFactory.setHostName(redisHost); connectionFactory.setPort(redisPort); connectionFactory.setPoolConfig(poolConfig); connectionFactory.setUsePool(true); return connectionFactory; } }

คำอธิบายประกอบ @Value หมายความว่า Spring จะฉีดค่าที่กำหนดไว้ในคุณสมบัติของแอปพลิเคชันลงในฟิลด์ ซึ่งหมายความว่า redis.host และ redis.port ควรกำหนดค่าในคุณสมบัติของแอปพลิเคชัน

ตอนนี้เราต้องกำหนดข้อความที่เราต้องการส่งไปยังคิว ข้อความตัวอย่างง่ายๆอาจมีลักษณะดังนี้:

@Getter @Setter @Builder public class PostPublishedEvent { private String postUrl; private String postTitle; private List emails; }

หมายเหตุ: โครงการลอมบอก ( https://projectlombok.org/ ) ให้ @Getter, @Setter, @Builder และคำอธิบายประกอบอื่น ๆ อีกมากมายเพื่อหลีกเลี่ยงไม่ให้โค้ดเกะกะด้วย getters, setters และสิ่งเล็กน้อยอื่น ๆ คุณสามารถเรียนรู้เพิ่มเติมได้จาก บทความ ApeeScape นี้ .

เมื่อทำการนำเสนอที่ซับซ้อนซึ่งต่อไปนี้

ข้อความจะถูกบันทึกในรูปแบบ JSON ในคิว ทุกครั้งที่มีการเผยแพร่เหตุการณ์ไปยังคิวข้อความจะถูกจัดลำดับเป็น JSON และเมื่อใช้งานจากคิวข้อความจะถูก deserialized

ด้วยข้อความที่กำหนดเราจำเป็นต้องกำหนดคิวเอง ใน Spring Integration สามารถทำได้อย่างง่ายดายผ่านทาง .xml การกำหนดค่า ควรวางการกำหนดค่าไว้ใน resources/WEB-INF ไดเรกทอรี

MessageChannel

ในการกำหนดค่าคุณจะเห็นส่วน“ int-redis: que-outbound-channel-adapter” คุณสมบัติของมันคือ:

  • id: ชื่อถั่วของส่วนประกอบ
  • ช่อง: RedisConnectionFactory ซึ่งปลายทางนี้ได้รับข้อความ
  • การเชื่อมต่อโรงงาน: การอ้างอิงถึง #root ถั่ว.
  • คิว: ชื่อของรายการ Redis ที่ดำเนินการพุชตามคิวเพื่อส่งข้อความ Redis แอ็ตทริบิวต์นี้ใช้ร่วมกันกับคิวนิพจน์
  • คิวนิพจน์: นิพจน์ SpEL เพื่อกำหนดชื่อของรายการ Redis โดยใช้ข้อความขาเข้าขณะรันไทม์เป็น RedisSerializer ตัวแปร. แอตทริบิวต์นี้ใช้ร่วมกันกับคิว
  • Serializer: ก JdkSerializationRedisSerializer การอ้างอิงถั่ว โดยค่าเริ่มต้นจะเป็น String อย่างไรก็ตามสำหรับ StringRedisSerializer payloads, a true จะใช้หากไม่มีการอ้างอิงซีเรียลไลเซอร์
  • สารสกัด - น้ำหนักบรรทุก: ระบุว่าปลายทางนี้ควรส่งเฉพาะเพย์โหลดไปยังคิว Redis หรือข้อความทั้งหมดหรือไม่ ค่าเริ่มต้นคือ true
  • ดันซ้าย: ระบุว่าจุดสิ้นสุดนี้ควรใช้การกดซ้าย (เมื่อ false) หรือกดขวา (เมื่อ false) เพื่อเขียนข้อความไปยังรายการ Redis ถ้าเป็นจริงรายการ Redis จะทำหน้าที่เป็นคิว FIFO เมื่อใช้กับอะแด็ปเตอร์ช่องสัญญาณขาเข้าของคิว Redis เริ่มต้น ตั้งค่าเป็น true เพื่อใช้กับซอฟต์แวร์ที่อ่านจากรายการด้วยป๊อปด้านซ้ายหรือเพื่อให้ได้ลำดับข้อความแบบสแต็ก ค่าเริ่มต้นคือ .xml

ขั้นตอนต่อไปคือการกำหนดเกตเวย์ซึ่งกล่าวถึงใน RedisChannelGateway การกำหนดค่า สำหรับเกตเวย์เรากำลังใช้ org.toptal.queue คลาสจาก StringRedisSerializer แพ็คเกจ

.xml ใช้เพื่อจัดลำดับข้อความก่อนบันทึกใน Redis นอกจากนี้ใน RedisChannelGateway เรากำหนดเกตเวย์และตั้งค่า RedisChannelGateway เป็นบริการเกตเวย์ ซึ่งหมายความว่า default-request-channel ถั่วสามารถฉีดเข้าไปในถั่วอื่น ๆ ได้ เรากำหนดคุณสมบัติ @Gateway เนื่องจากยังสามารถให้การอ้างอิงแชนเนลต่อวิธีได้โดยใช้ public interface RedisChannelGateway { void enqueue(PostPublishedEvent event); } คำอธิบายประกอบ นิยามคลาส:

SpringIntegrationConfig

ในการเชื่อมต่อการกำหนดค่านี้เข้ากับแอปพลิเคชันของเราเราต้องนำเข้า สิ่งนี้ถูกนำไปใช้ใน @ImportResource('classpath:WEB-INF/event-queue-config.xml') @AutoConfigureAfter(RedisConfig.class) @Configuration public class SpringIntegrationConfig { } ชั้นเรียน

@ImportResource

.xml คำอธิบายประกอบใช้เพื่อนำเข้า Spring @Configuration ไฟล์กำหนดค่าเป็น @AutoConfigureAfter. และ enqueue คำอธิบายประกอบใช้เพื่อบอกใบ้ว่าควรใช้การกำหนดค่าอัตโนมัติหลังคลาสการกำหนดค่าอัตโนมัติอื่น ๆ ที่ระบุ

ตอนนี้เราจะสร้างบริการและใช้วิธีการที่จะ public interface QueueService { void enqueue(PostPublishedEvent event); } เหตุการณ์ไปยังคิว Redis

@Service public class RedisQueueService implements QueueService { private RedisChannelGateway channelGateway; @Autowired public RedisQueueService(RedisChannelGateway channelGateway) { this.channelGateway = channelGateway; } @Override public void enqueue(PostPublishedEvent event) { channelGateway.enqueue(event); } } enqueue

และตอนนี้คุณสามารถส่งข้อความไปยังคิวได้อย่างง่ายดายโดยใช้ QueueService วิธีการจาก LPUSH.

apache spark ทำงานอย่างไร

คิว Redis เป็นเพียงรายการของผู้ผลิตและผู้บริโภคหนึ่งรายขึ้นไป ในการเผยแพร่ข้อความไปยังคิวโปรดิวเซอร์ใช้ redis-cli monitor คำสั่ง Redis และหากคุณตรวจสอบ Redis (คำใบ้: พิมพ์ 'LPUSH' 'my-event-queue' '{'postUrl':'test','postTitle':'test','emails':['test']}' ) คุณจะเห็นว่ามีการเพิ่มข้อความลงในคิว:

PostPublishedEvent

ตอนนี้เราต้องสร้างแอปพลิเคชันสำหรับผู้บริโภคซึ่งจะดึงเหตุการณ์เหล่านี้ออกจากคิวและประมวลผล บริการผู้บริโภคต้องการการอ้างอิงเช่นเดียวกับบริการผู้ผลิต

ตอนนี้เราสามารถนำ resources/WEB-INF คลาสเพื่อยกเลิกการเชื่อมต่อข้อความ

เราจำเป็นต้องสร้างการกำหนดค่าคิวและอีกครั้งจะต้องวางไว้ใน .xml ไดเรกทอรี เนื้อหาของการกำหนดค่าคิวคือ:

int-redis:queue-inbound-channel-adapter

ใน MessageChannel การกำหนดค่า, SmartLifecycle สามารถมีคุณสมบัติดังต่อไปนี้:

  • id: ชื่อถั่วของส่วนประกอบ
  • ช่อง: true ซึ่งเราส่งข้อความจากปลายทางนี้
  • เริ่มต้นอัตโนมัติ: ก SmartLifecycle แอตทริบิวต์เพื่อระบุว่าจุดสิ้นสุดนี้ควรเริ่มต้นโดยอัตโนมัติหลังจากเริ่มบริบทของแอปพลิเคชันหรือไม่ ค่าเริ่มต้นคือ 0
  • เฟส: ก RedisConnectionFactory แอตทริบิวต์เพื่อระบุเฟสที่จะเริ่มต้นจุดสิ้นสุดนี้ ค่าเริ่มต้นคือ MessageChannel
  • การเชื่อมต่อโรงงาน: การอ้างอิงถึง ErrorMessages ถั่ว.
  • คิว: ชื่อของรายการ Redis ที่ดำเนินการป๊อปตามคิวเพื่อรับข้อความ Redis
  • ช่องข้อผิดพลาด: Exceptions ที่เราจะส่ง Endpoint ด้วย MessagePublishingErrorHandler จากงานการฟังของ errorChannel. โดยค่าเริ่มต้นพื้นฐาน RedisSerializer ใช้ค่าเริ่มต้น byte[] จากบริบทของแอปพลิเคชัน
  • Serializer: Message การอ้างอิงถั่ว อาจเป็นสตริงว่างซึ่งหมายความว่าไม่มีซีเรียลไลเซอร์ ในกรณีนี้ดิบ JdkSerializationRedisSerializer จากข้อความ Redis ขาเข้าจะถูกส่งไปยังช่องเป็น true น้ำหนักบรรทุก โดยค่าเริ่มต้นจะเป็น false
  • รับ - หมดเวลา: หมดเวลาเป็นมิลลิวินาทีสำหรับการดำเนินการป๊อปเพื่อรอข้อความ Redis จากคิว ค่าเริ่มต้นคือ 1 วินาที
  • ช่วงการกู้คืน: เวลาเป็นมิลลิวินาทีที่งาน Listener ควรเข้าสู่โหมดสลีปหลังจากมีข้อยกเว้นในการดำเนินการป๊อปก่อนที่จะเริ่มงาน Listener ใหม่
  • คาดหวังข้อความ: ระบุว่าปลายทางนี้คาดว่าข้อมูลจากคิว Redis จะมีข้อความทั้งหมดหรือไม่ หากตั้งค่าแอตทริบิวต์นี้เป็น TaskExecutor ซีเรียลไลเซอร์ต้องไม่เป็นสตริงว่างเนื่องจากข้อความต้องการรูปแบบการดีซีเรียลไลเซชันบางรูปแบบ (การทำให้อนุกรม JDK โดยค่าเริ่มต้น) ค่าเริ่มต้นคือ SimpleAsyncTaskExecutor
  • ตัวดำเนินการงาน: การอ้างอิงถึง Spring true (หรือมาตรฐาน JDK 1.5+ Executor) bean ใช้สำหรับงานการฟังพื้นฐาน โดยค่าเริ่มต้น a false ถูกนำมาใช้.
  • ขวาป๊อป: ระบุว่าจุดสิ้นสุดนี้ควรใช้ป๊อปขวา (เมื่อ true) หรือป๊อปด้านซ้าย (เมื่อ false) เพื่ออ่านข้อความจากรายการ Redis ถ้า true รายการ Redis จะทำหน้าที่เป็นคิว FIFO เมื่อใช้กับอะแด็ปเตอร์ช่องสัญญาณขาออก Redis เริ่มต้น ตั้งค่าเป็น json-to-object-transformer เพื่อใช้กับซอฟต์แวร์ที่เขียนลงในรายการด้วยการกดขวาหรือเพื่อให้ได้ลำดับข้อความแบบสแตก ค่าเริ่มต้นคือ type='com.toptal.integration.spring.model.PostPublishedEvent'

ส่วนที่สำคัญคือ 'ตัวกระตุ้นบริการ' ซึ่งกำหนดว่าควรใช้บริการและวิธีการใดในการดำเนินการกับเหตุการณ์

นอกจากนี้ SpringIntegrationConfig ต้องการแอตทริบิวต์ประเภทเพื่อเปลี่ยน JSON เป็นวัตถุตั้งค่าด้านบนเป็น public interface EventProcessingService { void process(PostPublishedEvent event); } @Service('RedisEventProcessingService') public class RedisEventProcessingService implements EventProcessingService { @Override public void process(PostPublishedEvent event) { // TODO: Send emails here, retry strategy, etc :) } }

อีกครั้งในการเชื่อมต่อการกำหนดค่านี้เราจะต้องมี 'BRPOP' 'my-event-queue' '1' ซึ่งอาจจะเหมือนกับก่อนหน้านี้ และประการสุดท้ายเราต้องการบริการที่จะดำเนินการตามเหตุการณ์

|_+_|

เมื่อคุณเรียกใช้แอปพลิเคชันคุณจะเห็นใน Redis:

|_+_|

สรุป

ด้วย Spring Integration และ Redis การสร้างแอปพลิเคชัน Spring microservices นั้นไม่น่ากลัวอย่างที่เคยเป็นมา ด้วยการกำหนดค่าเล็กน้อยและรหัสสำเร็จรูปจำนวนเล็กน้อยคุณสามารถสร้างรากฐานของสถาปัตยกรรมไมโครเซอร์วิสได้ในเวลาอันรวดเร็ว

แม้ว่าคุณจะไม่ได้วางแผนที่จะขูดโครงการ Spring ปัจจุบันของคุณทั้งหมดและเปลี่ยนไปใช้สถาปัตยกรรมใหม่ด้วยความช่วยเหลือของ Redis แต่ก็เป็นเรื่องง่ายมากที่จะได้รับการปรับปรุงประสิทธิภาพครั้งใหญ่ด้วยคิว

ทำความเข้าใจพื้นฐาน

สถาปัตยกรรมไมโครเซอร์วิสคืออะไร?

แอพพลิเคชั่นที่ใช้ไมโครเซอร์วิสคือระบบกระจายที่ทำงานบนเครื่องหลายเครื่อง แต่ละบริการในระบบสื่อสารโดยส่งข้อความไปยังผู้อื่น

สถาปัตยกรรมเสาหินในซอฟต์แวร์คืออะไร?

ในแอปพลิเคชันเสาหินส่วนประกอบทั้งหมดจะอยู่ในกระบวนการเดียวกันและโดยปกติการสื่อสารจะขึ้นอยู่กับการเรียกใช้วิธีการหรือฟังก์ชันภายในกระบวนการเดียวกัน

จาก Node.js ไปจนถึงการจ่ายภาษีอิสระของคุณ: บทสัมภาษณ์กับ Developer ที่ประสบความสำเร็จ

เทคโนโลยี

จาก Node.js ไปจนถึงการจ่ายภาษีอิสระของคุณ: บทสัมภาษณ์กับ Developer ที่ประสบความสำเร็จ
การสร้างแอป Android POS ที่ไม่สามารถปิดได้

การสร้างแอป Android POS ที่ไม่สามารถปิดได้

มือถือ

โพสต์ยอดนิยม
เอกสาร Agile: การปรับสมดุลความเร็วและการรักษาความรู้
เอกสาร Agile: การปรับสมดุลความเร็วและการรักษาความรู้
ทำลายหลักการออกแบบ (ด้วยอินโฟกราฟิก)
ทำลายหลักการออกแบบ (ด้วยอินโฟกราฟิก)
วิธีจัดโครงสร้างลำดับชั้นการพิมพ์ที่มีประสิทธิภาพ
วิธีจัดโครงสร้างลำดับชั้นการพิมพ์ที่มีประสิทธิภาพ
ฮาร์ดแวร์ที่คล่องตัวพร้อมการพัฒนาซอฟต์แวร์ในตัว
ฮาร์ดแวร์ที่คล่องตัวพร้อมการพัฒนาซอฟต์แวร์ในตัว
วิธีการรวม OAuth 2 เข้ากับ Django / DRF Back-end ของคุณโดยไม่บ้า
วิธีการรวม OAuth 2 เข้ากับ Django / DRF Back-end ของคุณโดยไม่บ้า
 
GWT Toolkit: สร้างส่วนหน้า JavaScript ที่มีประสิทธิภาพโดยใช้ Java
GWT Toolkit: สร้างส่วนหน้า JavaScript ที่มีประสิทธิภาพโดยใช้ Java
แหล่งข้อมูลสำหรับธุรกิจขนาดเล็กสำหรับ COVID-19: เงินกู้เงินช่วยเหลือและสินเชื่อ
แหล่งข้อมูลสำหรับธุรกิจขนาดเล็กสำหรับ COVID-19: เงินกู้เงินช่วยเหลือและสินเชื่อ
Libation Frontiers: เจาะลึกอุตสาหกรรมไวน์โลก
Libation Frontiers: เจาะลึกอุตสาหกรรมไวน์โลก
เรียนรู้ Markdown: เครื่องมือการเขียนสำหรับนักพัฒนาซอฟต์แวร์
เรียนรู้ Markdown: เครื่องมือการเขียนสำหรับนักพัฒนาซอฟต์แวร์
พบกับ Phoenix: กรอบงานคล้ายรางสำหรับเว็บแอปสมัยใหม่บน Elixir
พบกับ Phoenix: กรอบงานคล้ายรางสำหรับเว็บแอปสมัยใหม่บน Elixir
โพสต์ยอดนิยม
  • วิธีสร้างโทเค็น
  • c ++ โดยใช้ไฟล์ส่วนหัว
  • หลักการออกแบบตัวอย่างลวดลาย
  • อะไรที่ทำให้จังหวะโปรเกรสซีฟโดดเด่น?
  • จิราเป็นเครื่องมือบริหารจัดการโครงการ
  • บัตรเดบิต แฮกเงินฟรี
หมวดหมู่
  • ทีมแบบกระจาย
  • เคล็ดลับและเครื่องมือ
  • ชีวิตนักออกแบบ
  • นวัตกรรม
  • © 2022 | สงวนลิขสิทธิ์

    portaldacalheta.pt