干货分享:ASP.NET CORE(C#)与Spring Boot MVC(JAVA)异曲同工的编程方式总结

我 ( 梦在旅途,http://zuowj.cnblogs.com; http://www.zuowenjun.cn) 最近发表的一篇文章《.NET CORE 与 Spring Boot 编写控制台程序应有的优雅姿势》看到都上 48 小时阅读排行榜(当然之前发表的文章也有哦!),说明关注.NET CORE 及 Spring Boot 的人很多,也是目前的主流方向,于是我便决定系统性的总结一下 C# 与 JAVA 、ASP.NET CORE 与 Spring Boot MVC,让更多的人了解它们,消除之前可能存在的对.NET 或 JAVA 的误解。

本文目的是通过全面简述 C# 与 JAVA 在基础语法以及 ASP.NET CORE 与 Spring Boot MVC 的在框架规范、部署、运行的异曲同工的实现方式,让大家更多的了解 C# 与 JAVA,本文不会刻意说哪门语言好,我认为这是没有意义的,更多的是了解每种语言的特点、优点以及不同语言的共性,掌握编程内功(如:面向对象、DI、AOP、设计模式、算法),这样才能让自己更能适应社会及未来的变化。

本文主要以示例代码为主,辅以简单文字说明,不会细讲每个语法点,只会体现不同的实现方式而矣,全文无废话,全是干货,慢慢欣赏吧。

(注:本文内容是使用 Markdown 编辑器进行编辑完成!)

目录

C# VS JAVA 基础语法类比篇:

一、匿名类

C#(直接 new{},在 {} 中直接定义只读公开属性或委托方法,无需预先定义任何接口或类)
            #region 1. 匿名类
            var helloWord = new
            {
                CodeBy = "C# 匿名类",
                Output = new Action<string, string>((name, codeBy) =>
                {
                    System.Console.WriteLine($"Welcome:{name},Hello Word!  by {codeBy}");
                })
            };
        helloWord.Output(<span class="hljs-string">"梦在旅途"</span>, helloWord.CodeBy);
        <span class="hljs-meta">#endregion</span>

JAVA(需要先定义接口或类,然后 new 接口或类的构造函数 {},{} 内实现接口方法或重写父类接口)
        //1. 匿名类
        IHelloWord helloWord=new IHelloWord() {
            @Override
            public void output(String name) {
                System.out.printf("Welcome:%s,Hello Word!  by %s\n",name,getCodeBy());
            }
        <span class="hljs-meta">@Override</span>
        <span class="hljs-keyword">public</span> String <span class="hljs-title function_">getCodeBy</span><span class="hljs-params">()</span> {
            <span class="hljs-keyword">return</span> <span class="hljs-string">"JAVA匿名类"</span>;
        }
    };

    helloWord.output(<span class="hljs-string">"梦在旅途"</span>);

public interface IHelloWord {
void output(String name);
String getCodeBy();
}

二、类型初始化

C#(IList 类型(Dictionary、List)直接在 new 类型 {},在{} 内直接使用 {key,value} 或{value}方式添加集合元素,其实是隐式调用了 add 方法)
            #region 2. 类型初始化
        Dictionary&lt;<span class="hljs-built_in">string</span>, <span class="hljs-built_in">string</span>&gt; <span class="hljs-built_in">map</span> = new Dictionary&lt;<span class="hljs-built_in">string</span>, <span class="hljs-built_in">string</span>&gt;
        {
          { <span class="hljs-string">"key1"</span>,<span class="hljs-string">"value1"</span> },<span class="hljs-comment">//(隐式自动调用add方法)</span>
          { <span class="hljs-string">"key2"</span>, <span class="hljs-string">"value2"</span> },
          { <span class="hljs-string">"key3"</span>, <span class="hljs-string">"value3"</span> }
        };

        foreach (var item in <span class="hljs-built_in">map</span>)
        {
            System.Console.WriteLine($<span class="hljs-string">"key:{item.Key},value:{item.Value}"</span>);
        }

        List&lt;<span class="hljs-built_in">string</span>&gt; <span class="hljs-built_in">list</span> = new List&lt;<span class="hljs-built_in">string</span>&gt;
        {
            <span class="hljs-string">"list-item1"</span>,<span class="hljs-comment">//(隐式自动调用add方法)</span>
            <span class="hljs-string">"list-item2"</span>,
            <span class="hljs-string">"list-item3"</span>
        };

        foreach (<span class="hljs-built_in">string</span> item in <span class="hljs-built_in">list</span>)
        {
            System.Console.WriteLine(item);
        }

        String[] strArr = { <span class="hljs-string">"arr1"</span>, <span class="hljs-string">"arr2"</span>, <span class="hljs-string">"arr3"</span> };
        foreach (<span class="hljs-built_in">string</span> item in strArr)
        {
            System.Console.WriteLine(item);
        }


        Person person = new Person
        {
            Name = <span class="hljs-string">"梦在旅途"</span>,
            Age = <span class="hljs-number">23</span>,
            Sex = <span class="hljs-string">"男"</span>
        };


        <span class="hljs-built_in">string</span> json = JsonConvert.SerializeObject(person);
        System.Console.WriteLine(<span class="hljs-string">"Person json:"</span> + json);

        <span class="hljs-meta">#endregion</span>

JAVA(new 集合类型 {},并在{} 内再次使用 {},即{{赋值}},在双大括号内进行赋值操作,省略类名,这个特点有点类似 VB 及 VB.NET 的 with 语句,大家有兴趣可以了解一下,数组的初始化与 C# 相同,都可以直接在定义数组的时候在{} 中给定元素)
        //2. 类型初始化
        Map<String,String> map=new HashMap(){
            {
                put("key1","value1");
                put("key2","value2");
                put("key3","value3");
            }
        };
    <span class="hljs-keyword">for</span> (Map.Entry&lt;String, String&gt; item:map.entrySet()) {
        System.out.printf(<span class="hljs-string">"key:%1$s,value:%2$s\n"</span>,item.getKey(),item.getValue());
    }

    List&lt;String&gt; list=<span class="hljs-keyword">new</span> <span class="hljs-title class_">ArrayList</span>(){
        {
            add(<span class="hljs-string">"list-item1"</span>);
            add(<span class="hljs-string">"list-item2"</span>);
            add(<span class="hljs-string">"list-item3"</span>);
        }
    };

    <span class="hljs-keyword">for</span> (String item :list) {
        System.out.printf(<span class="hljs-string">"%s\n"</span>,item);
    }



    String[] strArr={<span class="hljs-string">"arr1"</span>,<span class="hljs-string">"arr2"</span>,<span class="hljs-string">"arr3"</span>};

    <span class="hljs-keyword">for</span> (String item :strArr) {
        System.out.printf(<span class="hljs-string">"%s\n"</span>,item);
    }


    Person person=<span class="hljs-keyword">new</span> <span class="hljs-title class_">Person</span>(){
        {
            setName(<span class="hljs-string">"zwj"</span>);
            setAge(<span class="hljs-number">32</span>);
            setSex(<span class="hljs-string">"男"</span>);
        }
    };

    ObjectMapper jsonMapper=<span class="hljs-keyword">new</span> <span class="hljs-title class_">ObjectMapper</span>();
    String json= jsonMapper.writeValueAsString(person);
    System.out.println(<span class="hljs-string">"Person json:"</span> + json);

三、委托(方法引用)

C#(委托定义使用 delegate 关键字,后面就跟方法答名定义【不含方法体】,可委托普通方法,静态方法,有很多的现成的预定义委托类型,如:Action<T0...T16>,Func<T0...T16,TOut> 各有 16 个重载)
            #region 3. 委托
            delegate void HelloDelegate(string name);// 定义委托类型 (重点是方法签名)
        <span class="hljs-comment">//常规普通自定义委托类型及委托相应的方法</span>
        HelloWord helloWordObj = new HelloWord();

        HelloDelegate helloDelegate = helloWordObj.Output; <span class="hljs-comment">//委托实例方法</span>
        helloDelegate.Invoke(<span class="hljs-string">"梦在旅途"</span>);<span class="hljs-comment">// OR helloDelegate("梦在旅途");</span>

        HelloDelegate helloDelegate2 = HelloWord.OutputForStatic; <span class="hljs-comment">//委托类的静态方法</span>
        helloDelegate2.Invoke(<span class="hljs-string">"zuowenjun"</span>); <span class="hljs-comment">// OR helloDelegate2("zuowenjun");</span>

        <span class="hljs-comment">//使用通用的已封装好的委托类型(如:Func、Action)并实例化</span>
        Func&lt;<span class="hljs-type">int</span>, <span class="hljs-type">int</span>, <span class="hljs-type">int</span>&gt; multiplyFunc = new Func&lt;<span class="hljs-type">int</span>, <span class="hljs-type">int</span>, <span class="hljs-type">int</span>&gt;(delegate (<span class="hljs-type">int</span> a, <span class="hljs-type">int</span> b)
        {
            <span class="hljs-keyword">return</span> a * b;
        });

        <span class="hljs-type">int</span> x = <span class="hljs-number">12</span>, y = <span class="hljs-number">25</span>;
        <span class="hljs-type">int</span> multiplyResult = multiplyFunc.Invoke(x, y); <span class="hljs-comment">//OR multiplyFunc(x,y);</span>
        System.Console.WriteLine($<span class="hljs-string">"{x}乘以{y}等于:{multiplyResult}"</span>);

        Action&lt;<span class="hljs-built_in">string</span>&gt; helloAction = new Action&lt;<span class="hljs-built_in">string</span>&gt;(delegate (<span class="hljs-built_in">string</span> name)
        {
            System.Console.WriteLine($<span class="hljs-string">"hello,{name},how are you!"</span>);
            System.Console.WriteLine(<span class="hljs-string">"learning keep moving!"</span>);
        });
        helloAction.Invoke(<span class="hljs-string">"www.zuowenjun.cn"</span>);

        <span class="hljs-meta">#endregion</span>

JAVA(定义委托需要先定义委托类型【即:函数式接口,规则:接口 +@FunctionalInterface+ 一个方法定义】,然后就可以普通方法,静态方法,有很多的现成的预定义委托类型【即:函数式接口】,如:BiFunction,Consumer 等)
        //3. 委托
	<span class="hljs-type">HelloWord</span> <span class="hljs-variable">helloWordObj</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">HelloWord</span>();

    <span class="hljs-type">HelloWordDelegate</span> <span class="hljs-variable">helloWordDelegate</span> <span class="hljs-operator">=</span> helloWordObj::output;
    helloWordDelegate.invoke(<span class="hljs-string">"梦在旅途"</span>);

    <span class="hljs-type">HelloWordDelegate</span> <span class="hljs-variable">helloWordDelegate2</span> <span class="hljs-operator">=</span> HelloWord::outputForStatic;
    helloWordDelegate2.invoke(<span class="hljs-string">"zuowenjun"</span>);


    <span class="hljs-comment">//使用已封装好的委托方法(JAVA这边称:函数式接口,有很多详见:https://www.runoob.com/java/java8-functional-interfaces.html)</span>
    BiFunction&lt;Integer, Integer, Integer&gt; multiplyFunc = <span class="hljs-keyword">new</span> <span class="hljs-title class_">BiFunction</span>&lt;Integer, Integer, Integer&gt;() {
        <span class="hljs-meta">@Override</span>
        <span class="hljs-keyword">public</span> Integer <span class="hljs-title function_">apply</span><span class="hljs-params">(Integer i, Integer i2)</span> {
            <span class="hljs-keyword">return</span> i * i2;
        }
    };

    <span class="hljs-type">int</span> <span class="hljs-variable">x</span> <span class="hljs-operator">=</span> <span class="hljs-number">12</span>, y = <span class="hljs-number">25</span>;
    <span class="hljs-type">int</span> <span class="hljs-variable">multiplyResult</span> <span class="hljs-operator">=</span> multiplyFunc.apply(x, y);
    System.out.printf(<span class="hljs-string">"%d乘以%d等于:%d%n"</span>, x, y, multiplyResult);


    Consumer&lt;String&gt; helloAction=<span class="hljs-keyword">new</span> <span class="hljs-title class_">Consumer</span>&lt;String&gt;() {
        <span class="hljs-meta">@Override</span>
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">accept</span><span class="hljs-params">(String s)</span> {
            System.out.printf(<span class="hljs-string">"hello,%s,how are you!%n"</span>,s);
            System.out.printf(<span class="hljs-string">"learning keep moving!%n"</span>);
        }
    };
    helloAction.accept(<span class="hljs-string">"www.zuowenjun.cn"</span>);

@FunctionalInterface
public interface HelloWordDelegate {
void invoke(String name);
}

public class HelloWord implements IHelloWord {

<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">output</span><span class="hljs-params">(String name)</span> {
    System.out.printf(<span class="hljs-string">"Welcome:%s,Hello Word!  by %s\n"</span>,name,getCodeBy());
}

<span class="hljs-keyword">public</span>  <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">outputForStatic</span><span class="hljs-params">(String name)</span>{
    System.out.printf(<span class="hljs-string">"Welcome:%s,Hello Word!  by JAVA static\n"</span>,name);
}

<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> String <span class="hljs-title function_">getCodeBy</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-string">"JAVA"</span>;
}

}

四、Lambda 表达式

C#(使用 (入参)=>{方法处理体},与要传入或要实例化的委托方法签名相同即可)
            #region 4.Lambda
        Func&lt;<span class="hljs-type">int</span>, <span class="hljs-type">int</span>, <span class="hljs-type">int</span>&gt; multiplyFunc2 = new Func&lt;<span class="hljs-type">int</span>, <span class="hljs-type">int</span>, <span class="hljs-type">int</span>&gt;((a, b) =&gt; a * b);

        <span class="hljs-type">int</span> x2 = <span class="hljs-number">12</span>, y2 = <span class="hljs-number">25</span>;
        <span class="hljs-type">int</span> multiplyResult2 = multiplyFunc2.Invoke(x2, y2); <span class="hljs-comment">//OR multiplyFunc(x,y);</span>
        System.Console.WriteLine($<span class="hljs-string">"{x2}乘以{y2}等于:{multiplyResult2}"</span>);

        Action&lt;<span class="hljs-built_in">string</span>&gt; helloAction2 = new Action&lt;<span class="hljs-built_in">string</span>&gt;(name =&gt;
        {
            System.Console.WriteLine($<span class="hljs-string">"hello,{name},how are you!"</span>);
            System.Console.WriteLine(<span class="hljs-string">"learning keep moving!"</span>);
        });

        helloAction2.Invoke(<span class="hljs-string">"www.zuowenjun.cn"</span>);

        <span class="hljs-type">int</span>[] intArr = { <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">6</span>, <span class="hljs-number">7</span>, <span class="hljs-number">8</span>, <span class="hljs-number">9</span> };
        intArr = intArr.Where(i =&gt; i &gt;= <span class="hljs-number">5</span>).ToArray();
        foreach (<span class="hljs-type">int</span> i in intArr)
        {
            System.Console.WriteLine($<span class="hljs-string">"int-{i}"</span>);
        }

        <span class="hljs-built_in">string</span> msg = <span class="hljs-string">"测试外部变量被Lambda引用"</span>;
        Action testMsgAction = () =&gt;
        {
            msg += <span class="hljs-string">"--改变内容"</span>;
            System.Console.WriteLine(<span class="hljs-string">"Lambda方法体中的值:"</span> + msg);
        };
        testMsgAction();
        System.Console.WriteLine(<span class="hljs-string">"原始值:"</span> + msg);

        <span class="hljs-meta">#endregion</span>

JAVA(使用 (入参)->{方法处理体},与要传入或要实例化的方法签名相同,且传入或实例化的类型必需是函数式接口【可以理解为自定义的委托类型】,注意与 C# 不同,Lambda 方法体内不能引用外部非 final 的变量,与 C# Lambda 有本质不同
        //4.Lambda
    BiFunction&lt;Integer, Integer, Integer&gt; multiplyFunc = (i1, i2) -&gt; i1 * i2;

    <span class="hljs-type">int</span> <span class="hljs-variable">x</span> <span class="hljs-operator">=</span> <span class="hljs-number">12</span>, y = <span class="hljs-number">25</span>;
    <span class="hljs-type">int</span> <span class="hljs-variable">multiplyResult</span> <span class="hljs-operator">=</span> multiplyFunc.apply(x, y);
    System.out.printf(<span class="hljs-string">"%d乘以%d等于:%d%n"</span>, x, y, multiplyResult);


    Consumer&lt;String&gt; helloAction= s -&gt; {
        System.out.printf(<span class="hljs-string">"hello,%s,how are you!%n"</span>,s);
        System.out.printf(<span class="hljs-string">"learning keep moving!%n"</span>);
    };
    helloAction.accept(<span class="hljs-string">"www.zuowenjun.cn"</span>);

    <span class="hljs-type">int</span>[] intArr = { <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">6</span>, <span class="hljs-number">7</span>, <span class="hljs-number">8</span>, <span class="hljs-number">9</span> };
    intArr= Arrays.stream(intArr).filter(value -&gt; value&gt;=<span class="hljs-number">5</span>).toArray();
    <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> n : intArr) {
        System.out.printf(<span class="hljs-string">"int-%d%n"</span>,n);
    }

五、泛型

C#(真泛型,不同的泛型类型参数视为不同的类型,有泛型接口,泛型类,泛型方法,泛型委托,泛型约束:in 表示逆变【泛型参数父类型转子类型,属于消费者,一般用于入参】,out 表示协变【泛型参数子类型转父类型】,只有委托、接口才支持可变性)
            #region 5. 泛型
        <span class="hljs-comment">//常用泛型集合类型</span>
        List&lt;<span class="hljs-type">int</span>&gt; intList = new List&lt;<span class="hljs-type">int</span>&gt; { <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">6</span>, <span class="hljs-number">7</span>, <span class="hljs-number">8</span>, <span class="hljs-number">9</span> };

        List&lt;<span class="hljs-type">long</span>&gt; longList = new List&lt;<span class="hljs-type">long</span>&gt; { <span class="hljs-number">1L</span>, <span class="hljs-number">2L</span>, <span class="hljs-number">3L</span>, <span class="hljs-number">4L</span>, <span class="hljs-number">5L</span>, <span class="hljs-number">6L</span>, <span class="hljs-number">7L</span>, <span class="hljs-number">8L</span>, <span class="hljs-number">9L</span> };

        Dictionary&lt;<span class="hljs-built_in">string</span>, <span class="hljs-built_in">string</span>&gt; dic = new Dictionary&lt;<span class="hljs-built_in">string</span>, <span class="hljs-built_in">string</span>&gt; {
            { <span class="hljs-string">"k1"</span>,<span class="hljs-string">"v1"</span>},{ <span class="hljs-string">"k2"</span>,<span class="hljs-string">"v2"</span>},{ <span class="hljs-string">"k3"</span>,<span class="hljs-string">"v3"</span>}
        };

        <span class="hljs-comment">//泛型方法</span>
        var demo = new DemoGenericClass();
        <span class="hljs-comment">//demo.DisplayResult("学习永无止境"); 错误,因为约束是值类型</span>
        demo.DisplayResult(ConsoleColor.DarkGreen);

        List&lt;YellowPerson&gt; yellowPersonList = new List&lt;YellowPerson&gt; {
            new YellowPerson(){ Name=<span class="hljs-string">"zzz"</span>,Age=<span class="hljs-number">11</span>,Sex=<span class="hljs-string">"G"</span>},
            new YellowPerson(){ Name=<span class="hljs-string">"xxx"</span>,Age=<span class="hljs-number">22</span>,Sex=<span class="hljs-string">"B"</span>}
        };

        <span class="hljs-comment">//协变(泛型参数子类转父类)</span>
        <span class="hljs-comment">//public interface IEnumerable&lt;out T&gt;</span>
        IEnumerable&lt;YellowPerson&gt; yellowPersons = yellowPersonList;
        IEnumerable&lt;Person&gt; persons = yellowPersons;<span class="hljs-comment">//协变(子类到父类的转变) ,泛型参数 out标记,一般用于出参,这个正确的</span>

        <span class="hljs-comment">// List&lt;Person&gt; personList = yellowPersonList; 因为List是类,而且泛型参数并没有标记out,不适用协变,故这样转换是错误的</span>

        foreach (var p in persons)
        {
            System.Console.WriteLine($<span class="hljs-string">"item :【Name={p.Name},Age={p.Age},Sex={p.Sex},Color={p.Color}】"</span>);
        }

        <span class="hljs-comment">//逆变(泛型参数父类转子类)</span>
        Action&lt;object, object&gt; showPlusResultAction = (d1, d2) =&gt; Console.WriteLine($<span class="hljs-string">"{d1}+{d2}={d1.ToString() + d2.ToString()}"</span>);

        Action&lt;<span class="hljs-built_in">string</span>, <span class="hljs-built_in">string</span>&gt; showStrPlusResultAction = showPlusResultAction;<span class="hljs-comment">//逆变(父类到子类的转变),泛型参数 in标记,一般用于入参</span>

        showPlusResultAction(<span class="hljs-number">55</span>, <span class="hljs-number">66</span>);
        showStrPlusResultAction(<span class="hljs-string">"你好"</span>, <span class="hljs-string">"中国"</span>);

        ShowMsg&lt;Person&gt; showMsg = new ShowMsg&lt;Person&gt;((p) =&gt;
        {
            System.Console.WriteLine($<span class="hljs-string">"ShowMsg :【Name={p.Name},Age={p.Age},Sex={p.Sex},Color={p.Color}】"</span>);
        });
        <span class="hljs-comment">//ShowMsg&lt;HelloWord&gt; showMsg2 = new ShowMsg&lt;HelloWord&gt;(...); 这样是不行的,因为泛型约束为需继承自Person</span>

        showMsg.Invoke(new Person() { Name = <span class="hljs-string">"zuowenjun"</span>, Age = <span class="hljs-number">33</span>, Sex = <span class="hljs-string">"B"</span> });
        showMsg.Invoke(new YellowPerson() { Name = <span class="hljs-string">"zuowenjun2"</span>, Age = <span class="hljs-number">33</span>, Sex = <span class="hljs-string">"B"</span> });

        <span class="hljs-comment">//综合演示:入参逆变,出参协变</span>
        Func&lt;Person, Person, <span class="hljs-built_in">string</span>&gt; getDataFunc = (x, y) =&gt; x.Name + y.Name;
        Func&lt;YellowPerson, YellowPerson, object&gt; getDataFunc2 = getDataFunc;
        object dataResult = getDataFunc2(new YellowPerson() { Name = <span class="hljs-string">"张三"</span>, Age = <span class="hljs-number">33</span>, Sex = <span class="hljs-string">"G"</span> }, new YellowPerson() { Name = <span class="hljs-string">"赵六"</span>, Age = <span class="hljs-number">33</span>, Sex = <span class="hljs-string">"B"</span> });
        System.Console.WriteLine($<span class="hljs-string">"getDataFunc2:{dataResult}"</span>);

        List&lt;<span class="hljs-type">int</span>&gt; a = new List&lt;<span class="hljs-type">int</span>&gt;();
        List&lt;String&gt; b = new List&lt;<span class="hljs-built_in">string</span>&gt;();
        <span class="hljs-type">bool</span> isEqual = (a.GetType() == b.GetType());
        System.Console.WriteLine($<span class="hljs-string">"List&lt;int&gt; 与 List&lt;String&gt; {(isEqual ? "</span>is<span class="hljs-string">" : "</span>not<span class="hljs-string">")} Equal "</span>);<span class="hljs-comment">//结果是不相等</span>


        <span class="hljs-meta">#endregion</span>

// 以上示例需要用到的类

public class BaseClass
{

/// <summary>
/// 必需是用 virtual 标记的方法(即:虚方法)或 abstract 标记的方法(即:抽象方法)子类才能使用 override 进行重写
/// </summary>
/// <param name="name"></param>
public virtual void SayHello(string name)
{
System.Console.WriteLine($"{nameof(BaseClass)} Say:{name},hello!");
}

}

        
public <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DemoGenericClass</span> :</span> BaseClass, IDisposable
{
    public <span class="hljs-type">void</span> DisplayResult&lt;T&gt;(T arg) where T : <span class="hljs-class"><span class="hljs-keyword">struct</span>
    {</span>
        System.Console.WriteLine($<span class="hljs-string">"DemoGenericClass.DisplayResult:{arg}"</span>);
    }

    public <span class="hljs-type">void</span> <span class="hljs-title function_">Dispose</span><span class="hljs-params">()</span>
    {
        System.Console.WriteLine(<span class="hljs-string">"DemoGenericClass Disposed"</span>);
    }

    public override <span class="hljs-type">void</span> <span class="hljs-title function_">SayHello</span><span class="hljs-params">(<span class="hljs-built_in">string</span> name)</span>
    {
        base.SayHello(name);
        System.Console.WriteLine($<span class="hljs-string">"{nameof(DemoGenericClass)} Say:{name},hello again!"</span>);
    }
}


public <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span>
{</span>
    public virtual Color Color { get; }
    public <span class="hljs-built_in">string</span> Name { get; <span class="hljs-built_in">set</span>; }

    public <span class="hljs-type">int</span> Age { get; <span class="hljs-built_in">set</span>; }

    public <span class="hljs-built_in">string</span> Sex { get; <span class="hljs-built_in">set</span>; }

}

public <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BlackPerson</span> :</span> Person
{
    public override Color Color =&gt; Color.Black;
}

public <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">YellowPerson</span> :</span> Person
{
    public override Color Color =&gt; Color.Yellow;
}

public <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WhitePerson</span> :</span> Person
{
    public override Color Color =&gt; Color.White;
}

JAVA(伪泛型,编译后类型参数擦除,同一个泛型类型不同的泛型参数类型相同,有泛型接口,泛型类,泛型方法,泛型约束:super 限定下边界,逆变,用于入参, 属于消费者,extends 限定上边界,协变,用于出参, 属于生产者,还有?通匹符)
      // 常用泛型集合
        List<Integer> intList = new ArrayList(){
            {
                add(1);
                add(2);
                add(3);
                add(4);
                add(5);
            }
        };
    Map&lt;String,String&gt; map=<span class="hljs-keyword">new</span> <span class="hljs-title class_">HashMap</span>(){
        {
            put(<span class="hljs-string">"k1"</span>,<span class="hljs-string">"v1"</span>);
            put(<span class="hljs-string">"k2"</span>,<span class="hljs-string">"v2"</span>);
            put(<span class="hljs-string">"k3"</span>,<span class="hljs-string">"v3"</span>);
        }
    };

    <span class="hljs-comment">//泛型方法</span>
    DemoGenericClass demo=<span class="hljs-keyword">new</span> <span class="hljs-title class_">DemoGenericClass</span>();
    demo.displayResult(<span class="hljs-keyword">new</span> <span class="hljs-title class_">YellowPerson</span>(){{
        setName(<span class="hljs-string">"zwj"</span>);setSex(<span class="hljs-string">"B"</span>);setAge(<span class="hljs-number">33</span>);
    }});

    List&lt;Integer&gt; a=<span class="hljs-keyword">new</span> <span class="hljs-title class_">ArrayList</span>&lt;&gt;();
    List&lt;String&gt; b=<span class="hljs-keyword">new</span> <span class="hljs-title class_">ArrayList</span>&lt;&gt;();
    <span class="hljs-type">boolean</span> <span class="hljs-variable">isEqual</span> <span class="hljs-operator">=</span>(a.getClass()==b.getClass());
    System.out.printf(<span class="hljs-string">"List&lt;Integer&gt;与List&lt;String&gt; %s Equal %n"</span>,isEqual?<span class="hljs-string">"is"</span>:<span class="hljs-string">"not"</span>); <span class="hljs-comment">//结果是相等,都是同一个List类型,不能使用instanceof判断泛型类型实例</span>

    <span class="hljs-comment">//协变、逆变(详见说明:https://www.jianshu.com/p/2bf15c5265c5 ,意义与C#相同)</span>
    List&lt;? <span class="hljs-built_in">super</span> Person&gt; persons=<span class="hljs-keyword">new</span> <span class="hljs-title class_">ArrayList</span>&lt;&gt;(); <span class="hljs-comment">//super:限定下边界,逆变,用于入参</span>
    persons.add(<span class="hljs-keyword">new</span> <span class="hljs-title class_">Person</span>(){
        {
            setName(<span class="hljs-string">"张三"</span>);
            setAge(<span class="hljs-number">25</span>);
            setSex(<span class="hljs-string">"B"</span>);
        }
    });

    persons.add(<span class="hljs-keyword">new</span> <span class="hljs-title class_">YellowPerson</span>(){
        {
            setName(<span class="hljs-string">"赵六"</span>);
            setAge(<span class="hljs-number">18</span>);
            setSex(<span class="hljs-string">"G"</span>);
        }
    });

   List&lt;? <span class="hljs-keyword">extends</span> <span class="hljs-title class_">Person</span>&gt; result= (List&lt;? <span class="hljs-keyword">extends</span> <span class="hljs-title class_">Person</span>&gt;) persons;<span class="hljs-comment">//extends:限定上边界,协变,用于出参</span>
   <span class="hljs-keyword">for</span> (Person p:result){
       System.out.printf(<span class="hljs-string">"Person list item:%s %n"</span>,p.toString());
   }

// 以上示例需要用到的类
public class DemoGenericClass implements AutoCloseable
{
@Override
public void close() throws Exception {
System.out.println("DemoGenericClass closed");
}

    <span class="hljs-keyword">public</span> &lt;T <span class="hljs-keyword">extends</span> <span class="hljs-title class_">Person</span>&gt; <span class="hljs-keyword">void</span> <span class="hljs-title function_">displayResult</span><span class="hljs-params">(T arg)</span> <span class="hljs-comment">//泛型约束(泛型参数上边界,协变)</span>
    {
       System.out.printf(<span class="hljs-string">"DemoGenericClass.DisplayResult:%s %n"</span>,arg.toString());
    }
}

public class Person {
private String name;
private int age;
private String sex;

<span class="hljs-keyword">public</span> String <span class="hljs-title function_">getName</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> name;
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setName</span><span class="hljs-params">(String name)</span> {
    <span class="hljs-built_in">this</span>.name = name;
}

<span class="hljs-keyword">public</span> <span class="hljs-type">int</span> <span class="hljs-title function_">getAge</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> age;
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setAge</span><span class="hljs-params">(<span class="hljs-type">int</span> age)</span> {
    <span class="hljs-built_in">this</span>.age = age;
}

<span class="hljs-keyword">public</span> String <span class="hljs-title function_">getSex</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> sex;
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setSex</span><span class="hljs-params">(String sex)</span> {
    <span class="hljs-built_in">this</span>.sex = sex;
}

<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> String <span class="hljs-title function_">toString</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> String.format(<span class="hljs-string">"Person=[Name:%s,Age:%d,Sex:%s] %n"</span>, name, age, sex);
}

}

class YellowPerson extends Person {

<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> String <span class="hljs-title function_">toString</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-string">"YellowPerson#toString-"</span>+ <span class="hljs-built_in">super</span>.toString();
}

}

六、自动释放

C#(采用 using 包裹,要实现自动释放必需实现 IDisposable 接口)
            using (var demo2 = new DemoGenericClass()) //DemoGenericClass 实现 IDisposable 接口
            {
                demo2.DisplayResult(123456);
            }
JAVA(采用 try 包裹,要实现自动释放必需实现 AutoCloseable 接口)
        try(DemoGenericClass demo=new DemoGenericClass()) {
            demo.displayResult(new YellowPerson(){
                {
                    setName("zuowenjun");
                    setAge(33);
                    setSex("B");
                }
            });
        }

七、重写(override)

C#(必需是用 virtual 标记的方法(即:虚方法)或 abstract 标记的方法(即:抽象方法)子类才能使用 override 进行重写,重写后父类的方法将被子类取代,若需在子类中执行父类被重写的方法,应使用 base 关键字,若父类方法非虚方法或抽象方法但又想“重写”怎么办?则只能使用 new 覆盖方法,覆盖方法与重写方法的不同之处在于,在父类中仍可以正常执行父类的方法而不会执行子类的覆盖方法,覆盖方法的方法签名、访问修饰符均没有严格限制,即使不相同仍不会报错,但 IDE 会有提示,如需真正覆盖父类方法,则应按照重写的规范来,只是使用 new 来修饰覆盖方法,但覆盖方法与重写方法有本质不同,一般情况下更建议使用重写方法)

C# 所有类的普通方法默认是密封方法(类似 JAVA 的 final 方法),是不允许被重写,可以理解为默认是不开放的,需要开放重写的方法必需使用 virtual 标记为虚方法(虚方法至少是 protected 及以上的访问权限),若重写后不想被后续的子类再次重写,则可以标记为 sealed,即:密封方法

    public class BaseClass
    {
        /// <summary>
        /// 必需是用 virtual 标记的方法(即:虚方法)或 abstract 标记的方法(即:抽象方法)子类才能使用 override 进行重写
        /// </summary>
        /// <param name="name"></param>
        public virtual void SayHello(string name)
        {
            System.Console.WriteLine($"{nameof(BaseClass)} Say:{name},hello!");
        }
}

public <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DemoGenericClass</span> :</span> BaseClass
{
    public override <span class="hljs-type">void</span> <span class="hljs-title function_">SayHello</span><span class="hljs-params">(<span class="hljs-built_in">string</span> name)</span>
    {
        base.SayHello(name);
        System.Console.WriteLine($<span class="hljs-string">"{nameof(DemoGenericClass)} Say:{name},hello again!"</span>);
    }
}

JAVA(非 private 且非 final 修饰的普通方法默认均可在子类中进行重写,重写要求基本与 C# 相同,只是无需强制 Override 关键字,但建议仍使用 @Override 注解,以便 IDE 进行重写规范检查,重写后父类的方法将被子类取代,若需在子类中执行父类被重写的方法,应使用 super 关键字)

JAVA 所有类的普通方法默认是虚方法,都是可以被重写,可以理解为默认是开放重写的,若不想被重写则应标记为 final , 即:最终方法(C# 中称密封方法)

    public  class BaseClass{
        public  void  testOutput(String msg){
            System.out.println("output Msg:" + msg);
        }
    }
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">DemoGenericClass</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_">BaseClass</span>
{
    <span class="hljs-meta">@Override</span>
    <span class="hljs-keyword">public</span>  <span class="hljs-keyword">void</span>  <span class="hljs-title function_">testOutput</span><span class="hljs-params">(String msg)</span>{
        <span class="hljs-built_in">super</span>.testOutput(msg);
        System.out.println(<span class="hljs-string">"output again Msg:"</span> + msg);
    }
}

ASP.NET CORE VS Spring Boot 框架部署类比篇:

一、引用依赖(包)

C#(编辑 csproj 文件,可以通过 PackageReference 引用包、ProjectReference 引用同一个解决方案下的其它项目,Reference 引用本地 DLL 组件,csproj 除了引用包以外,还可以通过在 PropertyGroup 元素下配置相关的属性,比如 TargetFramework 指定 SDK 框架版本等)

.NET 项目的包是 NuGet 包,可以从 nuget.org 上查找浏览所需的包,项目中引用依赖包,除了在 csproj 文件中使用 PackageReference 添加编辑外(具体用法参见:项目文件中的包引用 (PackageReference))还可以使用 package manager 控制台使用包管理命令,如:Install-Package ExcelEasyUtil -Version 1.0.0,或者直接使用.NET CLI 命令行工具,如:dotnet add package ExcelEasyUtil --version 1.0.0

.NET 有包、元包、框架 之分,详细了解:包、元包和框架

  <!-- 包引用 -->
  <ItemGroup>
    <PackageReference Include="Autofac.Extras.DynamicProxy" Version="4.5.0" />
    <PackageReference Include="Autofac" Version="4.9.2" />
    <PackageReference Include="Microsoft.AspNetCore.App" />
    <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.1.1" />
    <PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.4.0" />
  </ItemGroup>

<!-- 同一解方案下的项目引用 -->
<ItemGroup>
<ProjectReference Include="..\StandardClassLib2019\StandardClassLib2019.csproj" />
</ItemGroup>

<!-- 本地组件直接引用 -->
<ItemGroup>
<Reference Include="KYExpress.Common">
<HintPath>xxxx\xxxx.dll</HintPath>
<Private>true</Private>
</Reference>
</ItemGroup>

JAVA(编辑 POM 文件,通过 dependencies.dependency 来声明引入多个依赖,根据 scope 可以指定依赖的有效作用范围)
    <dependencies>
        <!--maven 包依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
    <span class="hljs-comment">&lt;!--本地JAR包依赖(scope=system,systemPath=jar包存放目录)--&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>cn.zuowenjun.boot.mybatis.plugin<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>cn.zuowenjun.boot.mybatis.plugin<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.0<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">scope</span>&gt;</span>system<span class="hljs-tag">&lt;/<span class="hljs-name">scope</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">systemPath</span>&gt;</span>${basedir}/src/main/libs/xxxxx.jar<span class="hljs-tag">&lt;/<span class="hljs-name">systemPath</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>

    <span class="hljs-comment">&lt;!--同一父项目Module之间依赖,注意这个必需先创建基于POM的父项目,然后各子Moudle 的POM 的parent指向父项目--&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>cn.zuowenjun.springboot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>springboot-demo1<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.0-SNAPSHOT<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">dependencies</span>&gt;</span>

JAVA POM 依赖继承两种方式

通过 parent 继承,如下所示:(如下是非常典型的 spring boot 的 parent 继承),项目将继承 spring-boot-starter-parent POM 中的所有设置及依赖(如:properties、dependencies 等)

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
    </parent>

通过 dependencyManagement 继承,如下所示:(这是依赖管理,dependencyManagement 里只是声明依赖,并不实现引入,因此子项目可按需显式的声明所需的依赖项。如果不在子项目中声明依赖,则不会从父项目中继承依赖,只有在子项目中声明了依赖项,且没有指定具体版本,才会从父项目中继承依赖项,(写了版本号相当于覆盖),version 和 scope 都读取自父 pom)

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.SR2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

二、依赖注入 DI (IOC 容器)

C#(一般在 Startup 文件中 ConfigureServices 方法中按需注册依赖,注册依赖可以指定生命周期如:AddTransient【瞬时,即:每次都创建新实例】、AddScoped【作用域范围内】、AddSingleton【单例,仅实例化一次】,具体效果可以参见:在 ASP.NET Core 依赖注入
//1. 使用 ASP.NET CORE 默认的 DI 框架,在 Startup 文件中 ConfigureServices 方法中按需注册依赖
        public void ConfigureServices(IServiceCollection services)
        {
            // 采用 ASP.NET CORE 默认的 IOC 容器注册
            services.AddTransient<IOperationTransient, Operation>();
            services.AddScoped<IOperationScoped, Operation>();
            services.AddSingleton<IOperationSingleton, Operation>();
            services.AddSingleton<IOperationSingletonInstance>(new Operation(Guid.Empty));
        }

//2. 在 Controller 中就可以直接采用构造函数注入或指明从 IOC 容器中获得实例 [FromServices]
[ApiController]
[Route("api/[controller]")]
public class DemoController : Controller
{
private readonly OperationService operationService;

    public <span class="hljs-title function_">DemoController</span><span class="hljs-params">(OperationService operationService)</span>
    {
        this.operationService = operationService;
    }

    [Route(<span class="hljs-string">"optid"</span>)]
    public object <span class="hljs-title function_">Operation</span><span class="hljs-params">([FromServices]OperationService optSrv)</span>{
        <span class="hljs-comment">//<span class="hljs-doctag">TODO:</span>方法体中直接使用operationService 或 入参optSrv均可</span>
    }
  }

// 如上所需接口及类定义

public interface IOperation
{
    Guid OperationId { get; }
}


public interface IOperationTransient : IOperation
{
}

public interface IOperationScoped : IOperation
{
}

public interface IOperationSingleton : IOperation
{
}

public interface IOperationSingletonInstance : IOperation
{
}


public <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Operation</span> :</span> IOperationTransient,
    IOperationScoped,
    IOperationSingleton,
    IOperationSingletonInstance
{
    public <span class="hljs-title function_">Operation</span><span class="hljs-params">()</span> : <span class="hljs-title function_">this</span><span class="hljs-params">(Guid.NewGuid())</span>
    {
    }

    public <span class="hljs-title function_">Operation</span><span class="hljs-params">(Guid id)</span>
    {
        OperationId = id;
    }

    public Guid OperationId { get; private <span class="hljs-built_in">set</span>; }
}

public <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">OperationService</span>
{</span>
    public <span class="hljs-title function_">OperationService</span><span class="hljs-params">(
        IOperationTransient transientOperation,
        IOperationScoped scopedOperation,
        IOperationSingleton singletonOperation,
        IOperationSingletonInstance instanceOperation)</span>
    {
        TransientOperation = transientOperation;
        ScopedOperation = scopedOperation;
        SingletonOperation = singletonOperation;
        SingletonInstanceOperation = instanceOperation;
    }

    public IOperationTransient TransientOperation { get; }
    public IOperationScoped ScopedOperation { get; }
    public IOperationSingleton SingletonOperation { get; }
    public IOperationSingletonInstance SingletonInstanceOperation { get; }

}

C# 使用第三方 IOC 容器,如:autofac,由第三方 IOC 容器接管并实现 DI,示例如下:(autofac 支持更多、更灵活的依赖注入场景)

        public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            // 采用 ASP.NET CORE 默认的 IOC 容器注册
            services.AddTransient<IOperationTransient, Operation>();
            services.AddScoped<IOperationScoped, Operation>();
            services.AddSingleton<IOperationSingleton, Operation>();
            services.AddSingleton<IOperationSingletonInstance>(new Operation(Guid.Empty));
        services.AddTransient&lt;OperationService, OperationService&gt;();

        var containerBuilder = new ContainerBuilder();
        containerBuilder.Populate(services); <span class="hljs-comment">//交由autofac IOC容器管理</span>

        var container = containerBuilder.Build();
        <span class="hljs-keyword">return</span> new AutofacServiceProvider(container);<span class="hljs-comment">//使用utofac IOC容器</span>
    }

JAVA(可以使用 xml 来进行 Bean 的依赖注册,也可使用注解方式来进行依赖注册,目前在 DI 方面更多的是流行注解注册及注入,故这里也以注解依赖注册及注入为简要说明,更多有关注解依赖注册及注入以及 XML 的依赖注册及注入详细说明,可查阅我之前的文章:JAVA WEB 快速入门之通过一个简单的 Spring 项目了解 Spring 的核心(AOP、IOC)

注解依赖注册一般可以通过自定义一个 spring 统一注册配置类,如代码中所示 BeansConfig,这种一般对于集中注册 Bean 或 Bean 之间有先后依赖,先后顺序时比较有效果;另一种是直接在 Bean 上使用 @Component 注解(或其它专用含义的注解,如:@Repository、@Service,这些注解本身也标记了 @Component 注解)

//1. 在自定义的 spring 统一注册配置类中注册相关 Bean
@Configuration
public class BeansConfig {
<span class="hljs-meta">@Bean</span>
<span class="hljs-meta">@Scope("prototype")</span> <span class="hljs-comment">//singleton,request,session</span>
<span class="hljs-meta">@Order(1)</span> <span class="hljs-comment">//注册顺序</span>
<span class="hljs-keyword">public</span> DemoBean <span class="hljs-title function_">demoBean</span><span class="hljs-params">()</span>{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">DemoBean</span>();
}

<span class="hljs-meta">@Bean("demo")</span> <span class="hljs-comment">//定义名称</span>
<span class="hljs-meta">@Order(2)</span>
<span class="hljs-keyword">public</span>  DemoInterface <span class="hljs-title function_">demoInterface</span><span class="hljs-params">()</span>{
    <span class="hljs-keyword">return</span>  <span class="hljs-keyword">new</span> <span class="hljs-title class_">DemoImplBean</span>(demoBean()); <span class="hljs-comment">//构造函数注入</span>
}

}

//2. 在 Controller 中就可以直接通过属性注入或构造函数注入获得实例,并在 ACTION 中使用这些实例对象
@RestController
public class DemoController {

<span class="hljs-meta">@Autowired</span>
<span class="hljs-keyword">private</span>  DemoBean demoBean;

<span class="hljs-meta">@Autowired</span>
<span class="hljs-meta">@Qualifier("demo")</span><span class="hljs-comment">//指定从IOC中解析的bean注册名</span>
<span class="hljs-keyword">private</span>  DemoInterface demoInterface;

<span class="hljs-meta">@Autowired</span>
<span class="hljs-keyword">private</span>  DemoBean2 demoBean2;

<span class="hljs-meta">@RequestMapping(path = "/demo/msg",method = RequestMethod.GET,produces = "application/json;charset=utf-8")</span>
<span class="hljs-keyword">public</span> Object <span class="hljs-title function_">testMsg</span><span class="hljs-params">(<span class="hljs-meta">@RequestParam(value = "m",required = false)</span> String m)</span>{
    <span class="hljs-comment">//<span class="hljs-doctag">TODO:</span>可直接使用:demoBean、demoInterface、demoBean2这些私有字段,它们通过属性注入</span>
    <span class="hljs-keyword">return</span> <span class="hljs-string">"test msg:"</span> + m;
}

}

// 以下是如上所需的类及接口定义

public class DemoBean {

}

public interface DemoInterface {
void showMsg(String msg);
}

public class DemoImplBean implements DemoInterface {

<span class="hljs-keyword">private</span>  DemoBean demoBean;

<span class="hljs-keyword">public</span>  <span class="hljs-title function_">DemoImplBean</span><span class="hljs-params">(DemoBean demoBean)</span>{
    <span class="hljs-built_in">this</span>.demoBean=demoBean;
}

<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">showMsg</span><span class="hljs-params">(String msg)</span> {
    System.out.println(<span class="hljs-string">"show msg:"</span> + msg);
}

}

// 通过标记 Component,交由 spring IOC 自动扫描注册
@Component
public class DemoBean2 {

}

三、过滤器、拦截器 AOP

C#(在 ASP.NET CORE 中实现 AOP 常见有三种方式:第一种:添加 ACTION 过滤器(仅适用于 MVC);第二种:使用第三方的 AOP 切面拦截器(如下文的 AopInterceptor,可拦截指定的任意位置的虚方法),第三种:在请求管道中添加中间件(仅适用 MVC))
        public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            services.AddMvc(opt => opt.Filters.Add<AopFilter>() // 第一种:添加过滤器,实现 ACTION 执行前后记录耗时
                ).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        var containerBuilder = new ContainerBuilder();
        containerBuilder.Populate(services);

        containerBuilder.RegisterType&lt;AopInterceptor&gt;();
        containerBuilder.RegisterType&lt;OperationService&gt;().InterceptedBy(typeof(AopInterceptor)).EnableClassInterceptors(); <span class="hljs-comment">//第二种:启用autofac的AOP拦截</span>
        
        var container = containerBuilder.Build();
        <span class="hljs-keyword">return</span> new AutofacServiceProvider(container);
        
    }


    public <span class="hljs-type">void</span> <span class="hljs-title function_">Configure</span><span class="hljs-params">(IApplicationBuilder app, IHostingEnvironment env)</span>
    {
        <span class="hljs-keyword">if</span> (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        <span class="hljs-comment">//第三种:使用一个自定义的中间件,实现AOP的效果</span>
        app.Use(async (ctx, next) =&gt;
        {
            <span class="hljs-comment">//如果为示例逻辑</span>
            <span class="hljs-keyword">if</span> (!ctx.Request.Query.TryGetValue(<span class="hljs-string">"token"</span>, out var tokenVal) || tokenVal != <span class="hljs-string">"zuowenjun"</span>)
            {
                await ctx.Response.WriteAsync(<span class="hljs-string">"验证token失败,禁止访问!"</span>);
                <span class="hljs-keyword">return</span>;
            }

            ctx.Request.EnableBuffering();<span class="hljs-comment">//启动用buffer,以便可以重置Position</span>
            var requestReader = new StreamReader(ctx.Request.Body);

            var requestContent = requestReader.ReadToEnd();
            ctx.Request.Body.Position = <span class="hljs-number">0</span>; <span class="hljs-comment">//需要重置为流开头,否则将导致后续的Model Binding失效等各种问题</span>

            var originalResponseStream = ctx.Response.Body;<span class="hljs-comment">//记录原始请求</span>
            using (var ms = new MemoryStream())
            {
                ctx.Response.Body = ms;<span class="hljs-comment">//因原始请求为只写流,故此处用自定义的内存流来接收响应流数据</span>

                var watch = Stopwatch.StartNew();
                await next.Invoke();
                watch.Stop();

                ms.Position = <span class="hljs-number">0</span>;
                var responseReader = new StreamReader(ms);
                var responseContent = responseReader.ReadToEnd();

                <span class="hljs-built_in">string</span> logMsg = $<span class="hljs-string">"execedTime:{ watch.ElapsedMilliseconds.ToString() }ms,Request,{requestContent},Response: { responseContent}"</span>;
                Logger.LogInformation(logMsg);

                ms.Position = <span class="hljs-number">0</span>;<span class="hljs-comment">//恢复流位置为开头</span>

                await ms.CopyToAsync(originalResponseStream); <span class="hljs-comment">//将当前的流合并到原始流中</span>
                ctx.Response.Body = originalResponseStream; <span class="hljs-comment">//恢复原始响应流</span>
            };
        });

        app.UseMvc();

    }



<span class="hljs-comment">/// &lt;summary&gt;</span>
<span class="hljs-comment">/// Filter仅针对接入层(MVC)有效,底层服务若需使用AOP,则必需使用特定的AOP框架</span>
<span class="hljs-comment">/// &lt;/summary&gt;</span>
public <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AopFilter</span> :</span> IActionFilter
{
    private readonly Stopwatch stopWatch = new Stopwatch();

    public <span class="hljs-type">void</span> <span class="hljs-title function_">OnActionExecuting</span><span class="hljs-params">(ActionExecutingContext context)</span>
    {
        <span class="hljs-comment">//执行前逻辑</span>
        stopWatch.Start();
    }

    public <span class="hljs-type">void</span> <span class="hljs-title function_">OnActionExecuted</span><span class="hljs-params">(ActionExecutedContext context)</span>
    {
        <span class="hljs-comment">//执行后逻辑</span>
        stopWatch.Stop();
        var returnResult = context.Result;
        <span class="hljs-keyword">if</span> (returnResult is ObjectResult)
        {
            var objResult = (returnResult as ObjectResult);
            objResult.Value = new { Original = objResult.Value, ElapsedTime = stopWatch.ElapsedMilliseconds.ToString() + <span class="hljs-string">"ms"</span> };
        }
        <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (returnResult is JsonResult)
        {
            var jsonResult = (returnResult as JsonResult);
            jsonResult.Value = new { Original = jsonResult.Value, ElapsedTime = stopWatch.ElapsedMilliseconds.ToString() + <span class="hljs-string">"ms"</span> };
        }
    }


}

JAVA(可以通过自定义 Filter、HandlerInterceptor、MethodInterceptor 、around AOP 增强等方式实现 AOP 拦截处理)

// 最先执行,由 servlet 拦截请求(适用 WEB)
@WebFilter(filterName = "demoFilter",urlPatterns = "/*")
class  DemoFilter implements Filter {
<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">init</span><span class="hljs-params">(FilterConfig filterConfig)</span> <span class="hljs-keyword">throws</span> ServletException {
    <span class="hljs-comment">//初始化</span>
}

<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">doFilter</span><span class="hljs-params">(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)</span> <span class="hljs-keyword">throws</span> IOException, ServletException {
    <span class="hljs-comment">//过滤处理</span>
}

<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">destroy</span><span class="hljs-params">()</span> {
    <span class="hljs-comment">//销毁之前执行</span>
}

}

// 其次执行,由 spring MVC 拦截请求(适用 Spring MVC)
@Component
public class DemoHandlerInterceptor implements HandlerInterceptor {
// 也可继承自 HandlerInterceptorAdapter

<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> <span class="hljs-type">boolean</span> <span class="hljs-title function_">preHandle</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response, Object handler)</span> <span class="hljs-keyword">throws</span> Exception {
    <span class="hljs-comment">//执行前</span>

    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
}

<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">postHandle</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)</span> <span class="hljs-keyword">throws</span> Exception {
    <span class="hljs-comment">//执行后,生成视图之前执行</span>
}

<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">afterCompletion</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)</span> <span class="hljs-keyword">throws</span> Exception {
    <span class="hljs-comment">//在DispatcherServlet完全处理完请求之后被调用,可用于清理资源</span>
}

}

// 最后执行,拦截方法
@Component
class DemoMethodInterceptor implements MethodInterceptor{

<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> Object <span class="hljs-title function_">invoke</span><span class="hljs-params">(MethodInvocation methodInvocation)</span> <span class="hljs-keyword">throws</span> Throwable {
    <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
}

}

// 方法拦截的另一种形式
@Component
@Aspect
class AutoAspectJInterceptor {

<span class="hljs-meta">@Around("execution (*..controller.*.*(..))")</span>
<span class="hljs-keyword">public</span> Object <span class="hljs-title function_">around</span><span class="hljs-params">(ProceedingJoinPoint point)</span> <span class="hljs-keyword">throws</span> Throwable{
    <span class="hljs-comment">//执行前</span>
    <span class="hljs-type">Object</span> <span class="hljs-variable">object</span> <span class="hljs-operator">=</span> point.proceed();
    <span class="hljs-comment">//执行后</span>
    <span class="hljs-keyword">return</span> object;
}

}

特别说明:ASP.NET CORE 中的Fitler 与 Spring MVC 中的MethodInterceptor类似,都是控制方法,而 ASP.NET CORE 中的请求管道中间件与 Spring MVC 中的Filter、HandlerInterceptor类似,都是控制请求过程。这点要搞清楚。

四、配置读取

C#(支持多种配置数据提供程序,支持多种获取配置信息的方式,详见:ASP.NET Core 中的配置
            //Configuration 为 IConfiguration 实例对象
            Configuration.GetValue("key");// 适用单个 key-value
            Configuration.Get<TConfig>();// 适用整个 config 文件映射为一个 TConfig 类型的对象
            Configuration.GetSection("key").GetChildren();// 获取子项集合
JAVA(支持多种配置数据源格式(yml,Properties),可通过 @value、@ConfigurationProperties、Environment 等常见方法来获取配置信息)
    //1. 通过 @value 方式获取配置信息
	@Value("${zuowenjun.site}")
    public String zwjSite;
<span class="hljs-comment">//2.通过创建一个映射配置信息的Bean(ConfigProperties) 方式获取配置信息</span>
<span class="hljs-meta">@Component</span>
<span class="hljs-meta">@ConfigurationProperties()</span><span class="hljs-comment">//如果有前缀,则可以设置prefix=XXX</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Zuowenjun</span> {

    <span class="hljs-keyword">private</span> String site;
    <span class="hljs-keyword">private</span> String skills;
    <span class="hljs-keyword">private</span> String motto;


    <span class="hljs-keyword">public</span> String <span class="hljs-title function_">getSite</span><span class="hljs-params">()</span> {
        <span class="hljs-keyword">return</span> site;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setSite</span><span class="hljs-params">(String site)</span> {
        <span class="hljs-built_in">this</span>.site = site;
    }

    <span class="hljs-keyword">public</span> String <span class="hljs-title function_">getSkills</span><span class="hljs-params">()</span> {
        <span class="hljs-keyword">return</span> skills;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setSkills</span><span class="hljs-params">(String skills)</span> {
        <span class="hljs-built_in">this</span>.skills = skills;
    }

    <span class="hljs-keyword">public</span> String <span class="hljs-title function_">getMotto</span><span class="hljs-params">()</span> {
        <span class="hljs-keyword">return</span> motto;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setMotto</span><span class="hljs-params">(String motto)</span> {
        <span class="hljs-built_in">this</span>.motto = motto;
    }

}

//3. 通过 Environment 来直接获取配置信息
environment.getProperty("zuowenjun.site");

五、发布、部署、运行

C#(ASP.NET CORE:除了如下使用.NET CLI 命今进行发布打包,也可以使用 VS 或 VS CODE 可视化操作进行发布操作)

dotnet publish --configuration Release

JAVA(Spring MVC:除了如下使用 MAVEN 命令进行清理打包,还可以使用 IDEA 来进行打包,具体方法可参见:Springboot 项目打包成 jar 运行 2 种方式

mvn clean package

C#(ASP.NET CORE)、JAVA(Spring MVC) 都可以:

  1. 都支持 WINDOWS 服务器、Linux 服务器等多种平台服务器 部署运行

  2. 都支持使用命令行启动运行 ASP.NET CORE 或 Spring MVC 应用,例如:

    dotnet aspnetcoreApp.dll --urls="http://*:5001"

    java -jar springmvcApp.jar --server.port=5001

  3. 都支持 Jenkins CI&CD ,Docker、k8s 虚拟化部署

  4. 都支持在 Linux 服务器中以守护进程方式运行,例如:

    nohup dotnet aspnetcoreApp.dll > aspnetcoreApp.out 2>&1 &

    nohup java -jar springmvcApp.jar > springmvcApp.out 2>&1 &

    // 或者都使用 Supervisor 来构建守护进程,还提供管理 UI,具体请参见网上相关资源

好了,总结到此结束,愿能帮助到那些处于.NET 转 JAVA 或 JAVA 转.NET 或者想多了解一门编程语言的朋友们,祝大家事业有成。今后将分享更多关于分布式、算法等方面的知识,不局限.NET 或 JAVA 语言,敬请期待,谢谢!

码字不易,若需转载及转载我之前的文章请注明出处,谢谢。