一.什么是AutoMapper与为什么用它。 它是一种对象与对象之间的映射器,让AutoMapper有意思的就是在于它提供了一些将类型A映射到类型B这种无聊的实例,只要B遵循AutoMapper已经建立的惯例,那么大多数情况下就可以进行相互映射了。 二.如何使用? 直接nuget install-package automapper 简单到不能再简单了。 三.入门 定义了连个简单的Model:
|
1 2 3 4 5 6 7 8 9 10 11 12 |
public class Destination { public string name { get; set; } public string InfoUrl { get; set; } } public class Source { public string name { get; set; } public string InfoUrl { get; set; } public string aa { get; set; } } |
|
1 2 3 4 5 6 7 8 9 10 11 |
static void Main(string[] args) { Destination des = new Destination() { InfoUrl = "www.cnblogs.com/zaranet", name = "张子浩" }; Mapper.Initialize(x => x.CreateMap<Destination, Source>()); Source source = AutoMapper.Mapper.Map<Source>(des); Console.WriteLine(source.InfoUrl); } |
Initialize方法是Mapper的初始化,里面可以写上CreateMap表达式,具体是谁和谁进行匹配。在之后就可以直接进行一个获取值的过程了,非常的简单。 四.映射前后操作 偶尔有的时候你可能需要在映射的过程中,你需要执行一些逻辑,这是非常常见的事情,所以AutoMapper给我们提供了BeforeMap和AfterMap两个函数。
|
1 2 3 |
Mapper.Initialize(x => x.CreateMap<Destination, Source>().BeforeMap( (src,dest)=>src.InfoUrl ="https://"+src.InfoUrl).AfterMap( (src,dest)=>src.name="真棒"+src.name)); |
其中呢,src是Destination对象,dest是Source,你呢就可以用这两个对象去获取里面的值,说白了这就是循环去找里面的值了。 五.条件映射
|
1 |
Mapper.Initialize(x => x.CreateMap<Destination, Source>().ForMember(dest => dest.InfoUrl,opt => opt.Condition(dest => dest.InfoUrl == "www.cnblogs.com/zaranet1")).ForMember(...(.ForMember(...)))); |
在条件映射中,通过ForMember函数,参数是一个委托类型Fun<>,其里面呢也是可以进行嵌套的,但一般来说一个就够用了。 六.AutoMapper配置 初始化配置是非常受欢迎的,每个领域都应该配置一次。
|
1 2 3 4 5 |
//初始化配置文件 Mapper.Initialize(cfg => { cfg.CreateMap<Aliens, Person>(); }); |
但是像这种情况呢,如果是多个映射,那么我们只能用Profile来配置,组织你的映射配置,并将配置放置到构造函数中(这种情况是5.x以上的版本),一个是以下的版本,已经被淘汰了。 5.0及以上版本:
|
1 2 3 4 5 6 7 |
public class AliensPersonProfile : Profile { public AliensPersonProfile() { CreateMap<Destination, Source>(); } } |
5.0以下版本(在早期版本中,使用配置方法而不是构造函数。 从版本5开始,Configure()已经过时。 它将在6.0中被删除。)
|
1 2 3 4 5 6 7 |
public class OrganizationProfile : Profile { protected override void Configure() { CreateMap<Foo, FooDto>(); } } |
然后在程序启动的时候初始化即可。
|
1 |
Mapper.Initialize(x=>x.AddProfile<AliensPersonProfile>()); |
七.AutoMapper的最佳实践 上文中已经说到了AutoMapper的简单映射,但是在实际项目中,我们应该有很多类进行映射,这么多的映射应该怎么组织,这是一个活生生的问题,这成为主映射器。 在主映射器中,组织了多个小映射器,Configuration为我们的静态配置入口类;Profiles文件夹为我们所有Profile类的文件夹。如果是MVC,我们需要在Global中调用,那我的这个是控制台的。
|
1 2 3 4 5 6 7 8 |
public static void Configure() { Mapper.Initialize(cfg => { cfg.AddProfile<DestinationSourceProfile>(); cfg.AddProfile(new StudentSourceProfile()); }); } |
其中添加子映射,可以用以上两种方式。
|
1 2 3 4 |
public void Configuration(IAppBuilder app) { AutoMapperConfiguration.Configure(); } |
八.指定映射字段 在实际业务环境中,你不可能说两个类的字段是一 一 对应的,这个时候我们就要对应它们的映射关系。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public class CalendarEvent { public DateTime Date { get; set; } public string Title { get; set; } } public class CalendarEventForm { public DateTime EventDate { get; set; } public int EventHour { get; set; } public int EventMinute { get; set; } public string DisplayTitle { get; set; } } |
在这两个类中,CalendarEvent的Date将被拆分为CalendarEventForm的日期、时、分三个字段,Title也将对应DisplayTitle字段,那么相应的Profile定义如下:
|
1 2 3 4 5 6 7 8 9 10 11 |
public class CalendarEventProfile : Profile { public CalendarEventProfile() { CreateMap<CalendarEvent, CalendarEventForm>() .ForMember(dest => dest.EventDate, opt => opt.MapFrom(src => src.Date.Date)) .ForMember(dest => dest.EventHour, opt => opt.MapFrom(src => src.Date.Hour)) .ForMember(dest => dest.EventMinute, opt => opt.MapFrom(src => src.Date.Minute)) .ForMember(dest => dest.DisplayTitle, opt => opt.MapFrom(src => src.Title)); } } |
main方法通过依赖注入,开始映射过程,下图是代码和图。
|
1 2 3 4 5 6 7 8 9 10 11 |
static void Main(string[] args) { CalendarEvent calendar = new CalendarEvent() { Date = DateTime.Now, Title = "Demo Event" }; AutoMapperConfiguration.Configure(); CalendarEventForm calendarEventForm = Mapper.Map<CalendarEventForm>(calendar); Console.WriteLine(calendarEventForm); } |
那么最后呢,如果是反向的映射,一定回缺少属性,那么就你就可以obj.属性进行赋值。 附AutoHelper封装类
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
/// <summary> /// AutoMapper扩展帮助类 /// </summary> public static class AutoMapperHelper { /// <summary> /// 类型映射 /// </summary> public static T MapTo<T>(this object obj) { if (obj == null) return default(T); Mapper.CreateMap(obj.GetType(), typeof(T)); return Mapper.Map<T>(obj); } /// <summary> /// 集合列表类型映射 /// </summary> public static List<TDestination> MapToList<TDestination>(this IEnumerable source) { foreach (var first in source) { var type = first.GetType(); Mapper.CreateMap(type, typeof(TDestination)); break; } return Mapper.Map<List<TDestination>>(source); } /// <summary> /// 集合列表类型映射 /// </summary> public static List<TDestination> MapToList<TSource, TDestination>(this IEnumerable<TSource> source) { //IEnumerable<T> 类型需要创建元素的映射 Mapper.CreateMap<TSource, TDestination>(); return Mapper.Map<List<TDestination>>(source); } /// <summary> /// 类型映射 /// </summary> public static TDestination MapTo<TSource, TDestination>(this TSource source, TDestination destination) where TSource : class where TDestination : class { if (source == null) return destination; Mapper.CreateMap<TSource, TDestination>(); return Mapper.Map(source, destination); } /// <summary> /// DataReader映射 /// </summary> public static IEnumerable<T> DataReaderMapTo<T>(this IDataReader reader) { Mapper.Reset(); Mapper.CreateMap<IDataReader, IEnumerable<T>>(); return Mapper.Map<IDataReader, IEnumerable<T>>(reader); } } |
from:https://www.cnblogs.com/ZaraNet/p/10000311.html
View Details下载地址: 主程序官网下载链接:https://download.jetbrains.com/resharper/ReSharperUltimate.2018.3.3/JetBrains.ReSharperUltimate.2018.3.3.exe 2018.3.x破解补丁:https://files.cnblogs.com/files/simadi/Resharper2018.2Crack.7z 安装破解方法 1.先安装好Resharper; 2.下载完补丁后解压,以管理员身份运行Patch.cmd,如下图所示,即破解成功: 3.打开VS,打开ReSharper的注册窗口:ReSharper->Help->License Information… 4.剩余99999天,够你用200多年了吧! from:https://www.cnblogs.com/simadi/p/10412702.html
View Detailsis_uploaded_file ile总是返回false,根据以下方法进行检查,全部检查通过。
|
1 2 3 4 5 6 |
1,是否通过http协议上传。 2,form中是否有 enctype="multipart/form-data"。 3,上传文件是否超出了规定的大小。 4,存放上传文件的文件夹是否存在,上传的文件夹是否具有写权限。 5,上传文件应该是使用move<span class="hljs-emphasis">_uploaded_</span>file()这个函数吧! 6,请确保$_FILES[<span class="hljs-string">"upload"</span>][<span class="hljs-symbol">'error'</span>] = 0; |
最后,找到一篇帖子, 将文件名用realpath函数过滤一下即可。
|
1 |
<span class="hljs-meta">is_uploaded_file(realpath($</span><span class="bash">file[<span class="hljs-string">'tmp_name'</span>]))</span> |
原文链接:http://www.xiumu.org/other/under-the-iis-is_uploaded_file-always-returns-false.shtml from:https://my.oschina.net/qii/blog/400692?p=1
View Detailsbytes[] 到数字类型的转换是个经常用到的代码,解决方式也不止一种,最近需要将bytes[]转为long,有机会深入了解了一下,此文做个总结。 java代码实现 如果不想借助任何已经有的类,完全可以自己实现这段代码,如下:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/** * 将字节数组转为long<br> * 如果input为null,或offset指定的剩余数组长度不足8字节则抛出异常 * @param input * @param offset 起始偏移量 * @param littleEndian 输入数组是否小端模式 * @return */ public static long longFrom8Bytes(byte[] input, int offset, boolean littleEndian){ long value=0; // 循环读取每个字节通过移位运算完成long的8个字节拼装 for(int count=0;count<8;++count){ int shift=(littleEndian?count:(7-count))<<3; value |=((long)0xff<< shift) & ((long)input[offset+count] << shift); } return value; } |
借助java.nio.ByteBuffer实现 java.nio.ByteBuffer 本身就有getLong,getInt,getFloat….方法,只要将byte[]转换为ByteBuffer就可以实现所有primitive类型的数据读取,参见javadoc。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/** * 利用 {@link java.nio.ByteBuffer}实现byte[]转long * @param input * @param offset * @param littleEndian 输入数组是否小端模式 * @return */ public static long bytesToLong(byte[] input, int offset, boolean littleEndian) { // 将byte[] 封装为 ByteBuffer ByteBuffer buffer = ByteBuffer.wrap(input,offset,8); if(littleEndian){ // ByteBuffer.order(ByteOrder) 方法指定字节序,即大小端模式(BIG_ENDIAN/LITTLE_ENDIAN) // ByteBuffer 默认为大端(BIG_ENDIAN)模式 buffer.order(ByteOrder.LITTLE_ENDIAN); } return buffer.getLong(); } |
借助java.io.DataInputStream实现 java.io.DataInputStream 同样提供了readLong,readLong,readLong….方法,只要将byte[]转换为DataInputStream就可以实现所有primitive类型的数据读取,参见javadoc。 完整测试代码 下面的Junit 测试代码计算String 的MD5校验码(16 bytes),然后使用上述方式分别将16 bytes转换为2个long(大端模式)然后以16进制模式输出结果,以验证三种方式一致性。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
package net.gdface.facelog; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import org.junit.Test; public class TestSerialVersionUID { /** * 生成MD5校验码 * * @param source * @return */ static public byte[] getMD5(byte[] source) { if (null==source) return null; try { MessageDigest md = MessageDigest.getInstance("MD5"); return md.digest(source); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return null; } /** * 将16位byte[] 转换为32位的HEX格式的字符串String * * @param buffer * @return */ static public String toHex(byte buffer[]) { if (null==buffer) return null; StringBuffer sb = new StringBuffer(buffer.length * 2); for (int i = 0; i < buffer.length; i++) { sb.append(Character.forDigit((buffer[i] & 240) >> 4, 16)); sb.append(Character.forDigit(buffer[i] & 15, 16)); } return sb.toString(); } /** * 将字节数组转为long<br> * 如果input为null,或offset指定的剩余数组长度不足8字节则抛出异常 * @param input * @param offset 起始偏移量 * @param littleEndian 输入数组是否小端模式 * @return */ public static long longFrom8Bytes(byte[] input, int offset, boolean littleEndian){ if(offset <0 || offset+8>input.length) throw new IllegalArgumentException(String.format("less than 8 bytes from index %d is insufficient for long",offset)); long value=0; for(int count=0;count<8;++count){ int shift=(littleEndian?count:(7-count))<<3; value |=((long)0xff<< shift) & ((long)input[offset+count] << shift); } return value; } /** * 利用 {@link java.nio.ByteBuffer}实现byte[]转long * @param input * @param offset * @param littleEndian 输入数组是否小端模式 * @return */ public static long bytesToLong(byte[] input, int offset, boolean littleEndian) { if(offset <0 || offset+8>input.length) throw new IllegalArgumentException(String.format("less than 8 bytes from index %d is insufficient for long",offset)); ByteBuffer buffer = ByteBuffer.wrap(input,offset,8); if(littleEndian){ // ByteBuffer.order(ByteOrder) 方法指定字节序,即大小端模式(BIG_ENDIAN/LITTLE_ENDIAN) // ByteBuffer 默认为大端(BIG_ENDIAN)模式 buffer.order(ByteOrder.LITTLE_ENDIAN); } return buffer.getLong(); } @Test public void test() throws IOException { String input="net.gdface.facelog.dborm.person.FlPersonBeanBase"; byte[] md5 = getMD5(input.getBytes()); System.out.printf("md5 [%s]\n",toHex(md5)); // 三种方式运算结果对比验证 DataInputStream dataInput = new DataInputStream(new ByteArrayInputStream(md5)); long l1 = dataInput.readLong(); long l2 = dataInput.readLong(); System.out.printf("l1=0x%x l2=0x%x,DataInputStream\n", l1,l2); long ln1 = bytesToLong(md5,0, false); long ln2 = bytesToLong(md5,8, false); System.out.printf("ln1=0x%x ln2=0x%x,ByteBuffer\n", ln1,ln2); long ll1 = longFrom8Bytes(md5,0, false); long ll2 = longFrom8Bytes(md5,8, false); System.out.printf("ll1=0x%x ll2=0x%x\n", ll1,ll2); } } |
输出结果 md5 [39627933ceeebf2740e1f822921f5837] l1=0x39627933ceeebf27 l2=0x40e1f822921f5837,DataInputStream ln1=0x39627933ceeebf27 ln2=0x40e1f822921f5837,,ByteBuffer ll1=0x39627933ceeebf27 ll2=0x40e1f822921f5837 参考资料 《Java 中 byte、byte 数组和 int、long 之间的转换》 from:https://blog.csdn.net/10km/article/details/77435659
View Details第一种:饿汉模式(线程安全)
|
1 2 3 4 5 6 7 8 9 10 11 12 |
public class Single2 { private static Single2 instance = new Single2(); private Single2(){ System.out.println("Single2: " + System.nanoTime()); } public static Single2 getInstance(){ return instance; } } |
第二种:懒汉模式 (如果方法没有synchronized,则线程不安全)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public class Single3 { private static Single3 instance = null; private Single3(){ System.out.println("Single3: " + System.nanoTime()); } public static synchronized Single3 getInstance(){ if(instance == null){ instance = new Single3(); } return instance; } } |
第三种:懒汉模式改良版(线程安全,使用了double-check,即check-加锁-check,目的是为了减少同步的开销)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public class Single4 { private volatile static Single4 instance = null; private Single4(){ System.out.println("Single4: " + System.nanoTime()); } public static Single4 getInstance(){ if(instance == null){ synchronized (Single4.class) { if(instance == null){ instance = new Single4(); } } } return instance; } } |
第四种:利用私有的内部工厂类(线程安全,内部类也可以换成内部接口,不过工厂类变量的作用域要改为public了。)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public class Singleton { private Singleton(){ System.out.println("Singleton: " + System.nanoTime()); } public static Singleton getInstance(){ return SingletonFactory.singletonInstance; } private static class SingletonFactory{ private static Singleton singletonInstance = new Singleton(); } } |
from:https://my.oschina.net/yangchunlian/blog/1607947
View Details在同步块中调用 wait() 和 notify()方法,如果阻塞,通过循环来测试等待条件。请参考答案中的示例代码。 【生产者】
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; public class Producer implements Runnable { private final Vector sharedQueue; private final int SIZE; public Producer(Vector sharedQueue, int size) { this.sharedQueue = sharedQueue; this.SIZE = size; } @Override public void run() { // 生产数据 for (int i = 0; i < 7; i++) { System.out.println("Produced:" + i); try { produce(i); } catch (InterruptedException ex) { Logger.getLogger(Producer.class.getName()).log(Level.SEVERE, null, ex); } } } private void produce(int i) throws InterruptedException { // wait if queue is full while (sharedQueue.size() == SIZE) { synchronized (sharedQueue) { System.out.println("Queue is full " + Thread.currentThread().getName() + " is waiting , size: " + sharedQueue.size()); sharedQueue.wait(); } } // producing element and notify consumers synchronized (sharedQueue) { sharedQueue.add(i); sharedQueue.notifyAll(); } } } |
【消费者】
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; public class Consumer implements Runnable { private final Vector sharedQueue; private final int SIZE; public Consumer(Vector sharedQueue, int size) { this.sharedQueue = sharedQueue; this.SIZE = size; } @Override public void run() { // 消费数据 while (true) { try { System.out.println("Consumer: " + consume()); Thread.sleep(50); } catch (InterruptedException ex) { Logger.getLogger(Consumer.class.getName()).log(Level.SEVERE, null, ex); } } } private int consume() throws InterruptedException { // wait if queue is empty while (sharedQueue.isEmpty()) { synchronized (sharedQueue) { System.out.println("Queue is empty " + Thread.currentThread().getName() + " is waiting , size: " + sharedQueue.size()); sharedQueue.wait(); } } //otherwise consume element and notify waiting producer synchronized (sharedQueue) { sharedQueue.notifyAll(); return (Integer) sharedQueue.remove(0); } } } |
【测试函数】
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import java.util.Vector; public class ProducerConsumerSolution { public static void main(String[] args) { Vector sharedQueue = new Vector(); int size = 4; Thread prodThread = new Thread(new Producer(sharedQueue, size), "Producer"); Thread consThread = new Thread(new Consumer(sharedQueue, size), "Consumer"); prodThread.start(); consThread.start(); } } |
运行结果:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
Produced:0 Queue is empty Consumer is waiting , size: 0 Produced:1 Consumer: 0 Produced:2 Produced:3 Produced:4 Produced:5 Queue is full Producer is waiting , size: 4 Consumer: 1 Produced:6 Queue is full Producer is waiting , size: 4 Consumer: 2 Consumer: 3 Consumer: 4 Consumer: 5 Consumer: 6 Queue is empty Consumer is waiting , size: 0 |
from:https://www.cnblogs.com/xbq8080/p/10371214.html
View Details事故现场: 解决办法: 一是命令行,
|
1 |
mvn clean package -Dmaven.test.skip=true |
二是写入pom文件
|
1 2 3 4 5 6 7 8 |
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.4.2</version> <configuration> <skipTests>true</skipTests> </configuration> </plugin> |
from:https://www.cnblogs.com/lxcy/p/8279899.html
View Details1.git 项目到仓库中。 2.运行maven 导入JAR包 3.配置项目project structure(CTRL+ALT+SHIFT+S) project settings 第一项 Project compiler output 路径 : D:\git\CMS\target\shishuocms-2.0.1\WEB-INF\classes 第二项 Modules: Paths 选择第一个 Inherit project compile output path 复制 applicationContext.xml 、 log4j.properties、 shishuocms.properties 到 target/shishuocms-2.0.1/WEB-INF/classes下面。 别忘了修改shishuocms.properties的数据库连接配置。 ———————————————— 版权声明:本文为CSDN博主「matt0614」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/matt0614/article/details/44972539
View DetailsFAQ 什么是持续交付(CD)? CD是一种软件工程方法,团队在短周期内生成软件,确保软件可以随时可靠地发布。微服务、云原生架构的兴起引发了持续交付实践的必然结果。这与CI/CD有关,其中包括持续集成(CI) – 将所有开发者工作副本一天多次合并到共享主线的做法。 宣布了什么? CDF(Continuous Delivery Foundation,持续交付基金会)是一个新的、中立的组织,将发展和维持一个开放的持续交付生态系统。它将提供统一的治理和与供应商中立的管理,以及对资金和运营的监督。CD基金会的第一批项目是Jenkins、Jenkins X、Spinnaker和Tekton。 为什么CD社区组成基金会。为什么需要? 整个行业都迫切需要围绕管道、工作流程和其他CI/CD领域合作定义行业规范,并为CI/CD工具提供基础支持。例如,Jenkins社区正在寻求一个“全方位服务”的基金会来托管Jenkins(最受欢迎的CI/CD项目之一),并构建一个增强协作的平台。还需要一个全行业的中立DevOps/CD会议。 这是否代表了云原生态系统的转变? 是的,市场已转向容器化和云原生技术,因此CI/CD系统、DevOps和相关工具的生态系统发生了根本性的变化。CNCF云原生互动景观展示了CI/CD领域的多样性,以及在该领域中活跃的众多项目和供应商。 通过建立供应商中立的持续交付基金会,业界顶级开发者、最终用户和供应商可以将CI/CD作为方法,定义/记录最佳实践以及创建培训材料,以使全球任何软件开发团队能够交付代码更改更快、更可靠、无论它们是否为云原生。 开发者为何要关心? CI/CD项目目前面临的挑战,包括工具复杂性和管道和其他CI/CD工具缺乏行业标准化,正在抑制增长和创新。由于缺乏中立的法律实体和强有力的治理,项目很难吸引新开发者和组织的宝贵支持。项目维护者和开发者花费大量时间和金钱处理安全程序和监督等方面的变通方法。这使人们不再关注新的发展和创新。拥有广泛行业支持的基金会将能够更快地定义行业规范,并为跨项目协作创造更多机会,以改善开发者的工具。 谁用CD? CD广泛应用于云计算、企业IT,并且正在迅速扩展到其他顶级行业垂直领域。例如,在网络运营商与供应商并肩工作,开发CI/CD工具,使开发者能够直接与上游项目的分支合作 – 大幅缩短实施新功能的时间,并解决数月到数天的错误。使用云原生技术(如Kubernetes)时,设置CI/CD管道将加快发布生命周期。这使开发者每天可以多次发布;让团队灵活到足以快速迭代。 CDF如何与渐进式交付相关? 渐进式交付(Progressive delivery)是现代持续交付技术的一种形式,例如灰度发布、功能标记、A/B测试、经过验证的部署组等。渐进式交付技术和技术与持续交付密切相关。有关渐进式交付的更多信息,请阅读James Governor关于此主题的Redmonk博客:https://redmonk.com/jgovernor… 这将如何影响开源软件的开发? 持续交付可提高软件开发团队的速度、生产力和可持续性。CDF促进行业顶级开发者、最终用户和供应商之间的合作,以确保CD方法的软件工程充分发挥其潜力,推进开源软件开发。 哪些项目将包含在CDF中? CDF正在推出四个项目:Jenkins、Jenkins X、Spinnaker和Tekton,还有更多感兴趣的项目正在筹备中。我们邀请人们关注CDF技术监督委员会(“TOC”),该委员会将在未来做出项目决策:https://github.com/cdfoundati…。 我是否必须是成员才可以贡献到CDF项目? 绝对不是,CDF中的开源项目或任何Linux基金会计划的技术贡献都不需要成员资格。组织作为成员加入CDF,因为它们希望在持续交付模型和最佳实践的增长和发展中扮演积极的角色,而不只是支持CDF中的开放源码项目。如果你有兴趣加入,请参阅https://cd.foundation/members…。 什么是Jenkins? Jenkins是领先的开源自动化服务器,由大量不断增长的开发者、测试者、设计者和其他对持续集成、持续交付和现代软件交付实践感兴趣的人提供支持。它基于Java虚拟机(JVM),提供超过1,500个插件,可将Jenkins扩展为几乎所有技术软件交付团队使用的自动化服务器。2019年,Jenkins有超过了200,000个已知安装,使其成为部署最广泛的自动化服务器。 什么是Jenkins X? Jenkins X是Kubernetes上现代云应用程序的开源CI/CD解决方案。Jenkins X提供管道自动化、内置GitOps和预览环境,以帮助团队协作并加速他们的软件交付。Jenkins X使用最好的OSS工具自动化Kubernetes的CI + CD,如Jenkins、Tekton、Prow、SkaffoldKaniko和Helm。 为什么Jenkins和Jenkins X成为CDF的一员? Jenkins和Jenkins X将成为与技术兴趣相关的中立社区的一部分,并在构建开发者社区和项目治理方面获得帮助。CD基金会还将协助Jenkins和Jenkins X的营销和文档工作。 这对现有Jenkins用户有何影响? 将Jenkins和Jenkins X捐赠给CD基金会将促进行业内开发者、最终用户和供应商之间的更多合作。有关详细信息,请参阅此电子邮件和与Jenkins社区的对话:https://groups.google.com/for… 什么是Tekton? Tekton是一组用于构建CI/CD系统的共享开源组件。它使持续交付控制平面现代化,并将软件部署的大脑转移到Kubernetes。Tekton的目标是通过供应商中立的开源基金会为CI/CD管道、工作流程和其他构建模块提供行业规范。Tekton的代码在https://github.com/tektoncd/p…。 为什么Tekton成为CDF的一员?为什么Google会捐赠代码? 作为CDF的创始成员,谷歌正在捐赠Tekton。正如Kubernetes通过提供一组标准的API在云中进行交互而彻底改变了应用程序开发,Google的目标是通过CD基金会为DevOps从业者提供相同的优势。CDF将提供行业规范、安全、实用和可扩展的持续交付构建块,可用于在任何地方部署代码。 Tekton对knative build的影响是什么? 从第1天开始,可插拔性一直是knative的核心功能。将Build与Serving分离的目标是强化这种可插拔性概念。已经对构建系统感到满意的用户可以将其与Knative Serving一起使用。Tekton将继续支持Knative生态系统作为一流的目标环境。Tekton管道将部署到Knative环境。 在可预见的未来,Knative Build将继续作为Knative的一部分,专注于无服务器环境的源到容器工作流程。这两个项目将在标准和界面上保持紧密联系。 什么是Spinnaker? Spinnaker是云端优先的持续交付平台,最初由Netflix创建,目前由Netflix和Google共同领导。它支持所有主要的云平台和Kubernetes,并得到各个供应商的贡献。Spinnaker通常用于大规模组织,DevOps团队通过提供“黄金路径”(golden path)应用程序部署管道来支持许多开发者。 为什么Google/Netflix将Spinnaker捐赠给CDF? 随着Spinnaker最近将其治理正式化,将其转移到基金会是社区自然的下一步。Spinnaker设计为持续交付平台,通常与Jenkins结合使用,因此CDF真的是项目的理想之家。 Spinnaker也是一个多组件系统,在概念上与Tekton分享了许多想法 – 看到两个项目在一个基金会上聚集在一起,是将持续交付向前推进的巨大机会。 这对Spinnaker用户有何影响? Spinnaker作为CDF的一员,社区将有更多机会创建更简单、更强大的端到端体验,并就CI/CD的一套通用标准进行协作。Spinnaker用户在持续交付领域拥有丰富的经验,加入CDF提供了一个与更广泛的社区分享专业知识的绝佳机会。 Spinnaker用户还将受益于CDF社区中广泛的CI/CD知识,他们使用的各种工具之间的一致性,当然还有不断改进的生态系统! 未来的CI/CD项目进入CDF的过程是怎样? 其他项目预计将通过其即将成立的技术监督委员会(TOC)加入CDF:https://github.com/cdfoundati…,重点是将CD生态系统整合在一起,围绕可移植性和互操作性构建规范和项目。 CDF的下一步是什么? 接下来的步骤是启动治理结构。将成立一个理事会、技术和外联/营销委员会。我们计划在未来几个月内实现这一目标,并邀请新成员加入我们的社区。如果你有兴趣加入社区推进CD,请到https://cd.foundation/members…。 CNCF的参与程度,为什么需要一个单独的基金会? 首先要注意的是,CD适用于整个软件行业,而不仅仅适用于现代云原生应用程序。CNCF(Cloud Native Computing Foundation,云计算本地计算基金会)是CDF的姐妹基金会,拥有自己的治理结构和使命。每个基金会都有不同的使命,由其创始成员和技术专家定义。CNCF认为大多数与CD相关的工具超出了他们专注的云原生定义的范围,后者主要关注容器化、微服务、服务网格和编排。CDF超越云和容器,包括传统基础设施、移动、物联网、裸机等。CNCF和CDF都属于较大的Linux基金会旗下,计划在许多领域进行合作,包括同场会议。例如,CDF将于5月20日在西班牙巴塞罗那的KubeCon + CloudNativeCon Europe 2019举办持续交付峰会(CDS)活动。 CDF如何支持或与DevOps领域的其他玩家合作? CDF的使命是为开发者、最终用户和供应商提供一个中立的家庭,以便在CI/CD方法上进行协作。在这方面,CDF将通过发布关注可移植性的最佳实践、培训材料和行业指南来支持DevOps从业者。 有兴趣成为这个新基金会成员并制定治理方案的组织应到CDF加入的页面。开发者可以在此处注册CD基金会邮件列表:info@lists.cd.foundation。任何有兴趣加入CDF的项目都可以联系技术监督委员会(TOC):https://github.com/cdfoundati…。 KubeCon […]
View DetailsVS工程导入protobuf-net(https://github.com/mgravell/protobuf-net) 源码,报错。 解决方法:项目右键属性 —> 生成 —> 找到最下面的高级按钮,点击高级按钮 —> 常规 —> 语言版本 —> 选择 C#最新次要版本,或者比当前版本更高的版本即可,点击确定,然后保存即可。 from:https://blog.csdn.net/iningwei/article/details/86490259
View Details