一个C#开发者重温Java的心路历程

摘自:https://www.cnblogs.com/kiba/p/12052925.html

一个C#开发者重温Java的心路历程

 

前言

我们都知道软件开发是工科,不是理科;本质上和电工、钳工是一样的。

也就是说,软件技术成长也与电工、钳工的技术成长是一样的,靠的是练,而不是学。

所以,很多时候,我们称应届大学生是一张白纸,啥也不会。

不论他在学校学的多好,都没用,因为他没练过,不能干活;同理,不论他在学校学的多差,进入工作岗位后,只要肯练,工作也不成问题。

即,刚毕业的学生,只要你做的是工科的软件开发,不是科学类的理科研发;那么,本质上,大家是不存在优秀与普通的差别的。

为什么要学习Java?

在Web端,Java是毫无疑问的领头羊;所以,从事Web开发的Net开发者学习一下Java,其实还是很有益处的,取长补短嘛。 

而且,在工作中我们难免是要遇到和Java接口对接的情况的;如果你足够了解Java,那么,对方是否假配合你很快就能发觉了;如果被人搞到离职了,还跟人称兄道弟的,就有点Low了。

下面,我以IDEA(Java的VisualStudio),创建一个Spring项目,重温一下Java。

Java重温

首先打开IDEA,点击File-New-Project(我手上只有英文版IDEA);如下图:

 

在NewProject界面里,选择Spring Intinalizr,然后勾选Default,点击Next;

然后我们会经历一个【等待界面】,该界面是用来下载Spring模板的;这是因为Spring的模板不在IDEA中集成,所以创建时,需要在网上下载。

由于VisualStudio集成了大量模板,所以,我们几乎不用自己去找模板下载;如果情况特殊,我们需要找模板的话,那也是到网站上下载,然后手动安装。比如MVC2的时代,你想用MVC3的模板。

所以,对于Net开发而言,这种IDE提供下载模板渠道的模式,我们还是比较陌生的。不过IDEA也提供手动安装模板的功能,勾选Custom就可以使用手动安装模式了。

【等待界面】结束后,进入下图界面:

 

这个界面里有两个参数需要设置,一个是Group,一个是Artifact。那么这两个参数的作用是什么呢?

从字面上我是理解不了的,于是我百度了一下。。。然后,呃。。。我还是很混乱。。。

调查后,我大概得出一个结果,就是Group和Artifact是这个项目的唯一标识,Group是组织唯一标识,Artifact是项目唯一标识。

呃。。。我想,对于对于Net开发而言,这应该是很难理解的。项目唯一标识?这是什么鬼?唯一标识这个词怎么听起来像主键呢。。。项目怎么还需要唯一标识呢。。。

那到底要如何解释他们呢?

我想,应该是这样的,Java创建者的初始目的可能是想创建一个地球村共荣圈。。。所以,每一个Java项目都被期待着被共享,如果项目被共享,那么项目就需要唯一标识Artifact。如果一个公司共享了多个项目,那要证明这些项目都从属于该公司,那就需要组织(公司)唯一标识Group。

换成Net的描述就是,你创建的每一个Net项目都被微软期待着,共享到Nuget上,所以你创建项目之前,要先创建这个项目在Nuget上的唯一标识。(很显然微软没有这个期待)

这样,似乎就很好理解Group和Artifact了。

但是,因为现实中,不论Java还是Net都不可能每个项目都共享,所以,当我们做一个非开源项目时,这两个属性设置,就有点鸡肋了。

----------------------------------------------------------------------------------------------------

下面看一下,我认为这个界面中第三个重要的属性配置—Package。

可以在图中看到,系统默认把Package赋值成了Group+Artifact的值了—kibagroup.kibaarifact。

这里的Package大约等于C#里的命名空间。呃。。。然后,这个默认赋值我就觉得很奇葩了。。。

比如,你做了唯一标识,Group等于公司名kibacompany,Artifact等于项目kibatest;然后,你项目的默认命名空间就是kibacompany.kibatest。。。

很显然,这件事,对我而言很难理解,还好,IDEA支持我们去修改默认Package。

----------------------------------------------------------------------------------------------------

这里我们修改Package为KibaJavaStart。

修改完Package后,我们点击Next继续,如下图:

 

 选择图中的Web项目和其子选项中的Spring Web,然后点击下一步。

 

如上图所示,我们创建项目已经到了最后一步了,因为右下角不在是Next,而是Finish了。

在最后的这个界面里,系统提示我们设置ProjectName(项目名称)。

根据Net的习惯,项目名称通常和默认命名空间一样,所以这里我也赋值KibaJavaStart。

点击Finish,项目创建完成,界面如下:

项目简介

在上图中有三个大文件夹,和若干文件。

文件夹

其中前两个.idea和.mvn分别是IDEA开发工具和Maven管理工具的配置文件、管理文件等等(Maven类似nuget,但它还管理代码的生成和发布。。。貌似比IEDA还好用。。。这里Net开发就需要转变一下观念了,因为Java不是C#一家独大,所以他的相关工具存在的功能重复的问题,所以Java开发通常都是用组合工具在开发,不像我们一个VisualStudio走天下)

第三个src是我们项目的核心文件,java代码都在这里;src我猜就是source的意思,不知道为什么它不用全拼。。。

我们可以看到,在展开的src文件夹中,有着一层,两层,三层。。。呃。。。好多层文件夹。。。谁说的臃肿。。。

呃。。。我们可以看到其中java这个文件夹的颜色是不一样的,它代表的着,它下面的代码是核心Java代码。

与java文件夹同级的resources文件夹,顾名思义,存的是资源文件;不过他这个资源文件几乎什么都可以存储,比如图片,配置字符串,XML数据,SQL查询语句等等。(可能Net项目很少如此集中的存储资源,所以感官上可能会有些奇怪,但我觉得java的这种资源集中的做法是很科学的,非常值得Net开发借鉴学习)

----------------------------------------------------------------------------------------------------

文件

在剩下的若干文件中,我们暂时只关注Pom.xml文件;它是Java的配置文件,不过他并不类似于Net的App.config,他相对的更接近Net的.csproj工程文件,里面存储引用了那些Jar包(Net里就是dll)。

Java的Web是有类似于Net的App.config文件的文件的,他叫做web.xml,不过,很明显,我们在这里看不到,我们暂时不关注他,后文会讲到它。

Java里还有个数据配置文件,在这里配置的信息可以在Java代码里被访问;他就是java的数据配置文件在resources文件夹下的application.properties(类似App.config的AppSettings使用configSource把配置文件外放)如下图:

Web项目开发

首先,我们找到我们的默认命名空间,Java里的默认包—KibaJavaStart,如下图:

可以看到,在KibaJavaStart包下只有一个类ArtifactApplication,类里只有一个方法Main。

Main方法?不是Web项目吗?怎么还有Main方法?

如果你这么想,那一定是你Low了,嘿嘿;学一下Asp.Net Core吧,我们的Core也有Main函数了。

Asp.Net Core学习导航

学习了Asp.Net Core我们就了解了,这个承载Main函数的Application类,就是Asp.Net Core的Program类。

吐槽一下

1,现在项目创建完成后,系统在生成一个Main函数启动类时,使用了Arifact的值来做开头;这事很奇怪,Arifact是和Group在第一步一起创建的,两者是上下级关系;但现在Arifact又突然的和最后一步创建默认包名成了上下级关系,这感觉太诡异了,为什么不直接用Application命名呢,非要这样结合一下呢?

2,项目创建完成后自带的项目文件也太少了吧,就一个Main函数启动类,这让人怎么自学啊,逼着我们去看教程啊。

----------------------------------------------------------------------------------------------------

言归正传,一起看代码。。。

首先第一行代码,声明包名称。

1
package KibaJavaStart;

意义很简单,就是声明类所在的包名;不过,这里与C#不同的是,这个包名是固定的,不可修改的。

也就是说,这个类文件在文件夹KibaJavaStart下,他的包名就必须是KibaJavaStart;如果是在文件夹KibaJavaStart/Test下,他的包名就必须是KibaJavaStart.Test。

是的,这的确很不方便,不过,我们换一个角度考虑,Java文件夹的设置已经很臃肿了,刚刚创建就来了好几层,如果不强制包名称和文件夹名一致,那只怕会带来更多的不便。

我们接着看代码。

1
2
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

声明包名后,引入两个Spring包,理由很简单,因为Main函数要使用这两个包里的内容。

这里import与C#里的Using引用命名空间的用法类似。

因为创建的是Spring项目,所以一些相关的Spring的Jar依赖(类似C#的Dll)已经被默认引用进来了,可以在项目的External Libraries下找到相关引用;如下图:

我们知道在C#项目中,被引用的DLL会被复制一份到本地目录。

不过,在Java项目却不是这样的,我们打开项目的所在文件目录,会发现,目录里并没有这些Jar文件。

所以我猜想,被引用的Jar还在原来的位置,只有被编译的时候才会被调用。

----------------------------------------------------------------------------------------------------

在Java里,JDK自带的Jar包相对比Net而言,还是较少的,所以,在开发Java时,通常要引用很多很多个Jar包。

比如Spring框架就不在JDK自带的Jar包里,所以,使用Spring框架开发项目,就要先下载其相应的Jar包。

因为,我们是使用IDEA开发工具开发,而IDEA默认的下载Jar包的工具是Maven,那么下载的Jar包自然是由Maven管理;即,它们应该在Maven工具的所在目录下。

Maven管理工具好像是没有界面的,只能用命令行来操作;不过IDEA为我们提供了操作Maven的界面,现在我们打开IDEA提供的Maven操作界面。

File—Settings—Build,Execution,Deployment—BuildTools—Maven,如下图:

可以看到Maven不仅支持下载Jar包,还支持自定义保存下载Jar包的位置。

图中的Local repository就是保存已下载Jar包的位置了。

----------------------------------------------------------------------------------------------------

回到代码。

1
@SpringBootApplication

这种@开头的东西叫注解,它使用方式与C#的特性类似,要放在类,函数,属性上面;然后在注解(特性)的定义里去找到它的宿主(类or函数or属性),然后为他增加特性;当然,也可设置成只支持类或者只支持函数的模式。

不过Java里的注解实在是太多了、太强大了、太复杂了;注解不仅拥有各种各样的功能,还互相依赖,甚至注解和注解之间还有嵌套;目前Java已经发展到了不使用注解,开发就举步维艰的地步了。

有些注解在Net开发看来,真的有些奇葩,比如这个@Data注解,你都想象不到他是干什么的。 

如上图所示,我们定义了一个实体类DataTest ;类里定义两个私有字段,然后我们在类的头上加了一个Data注解,然后。。。然后。。。

然后,这个Data注解就会自动给这两个私有字段变成属性。。。

也许是因为我定义实体时总是想着他要被充血,所以我才觉得这注解很奇葩吧。。。

在上图中我们还可以看到,@Data注解是红色的,这是因为,我们还没有引入他依赖的Jar包。如何引用呢?呃。。。目前我只知道一种方法。。。

打开pom.xml,找到dependencies标签,在他的下面添加@Data依赖的Jar包 (手敲的),如下图:

图中除了@Data的依赖的lombok包,还有两个依赖,一个是spring-boot-starter,一个是spring-boot-starter-web;简单介绍下,这两个依赖是Spring框架的基础依赖,如果创建项目时未帮我们自动添加这俩依赖,则需要我们手动添加一下,不然会影响项目运行。

PS:在dependency标签中,我们会发现,他的子标签是groupId和artifactId,而spring-boot-starter包和spring-boot-starter-web包的groupId又是一样的,结合我们上文创建项目时设置Group和Artifact,可以想到,spring-boot-starter包和spring-boot-starter-web包都是由org.springframework.boot组织创建的开源项目,而我们在项目中,引用这种开源项目时,需要在dependency标签下增加groupId和artifactId两个标签,并在其中填写这个项目创建时设置的Group和Artifact属性值。

----------------------------------------------------------------------------------------------------

在Java的工程文件里添加完依赖后,我们所依赖的Jar并不会被下载,还需要手动使用Maven来下载,(这个下载依赖库的方式有点倒序的意思和Net不一样)顺序如下。

1,点击左下角快捷图标,打开Maven管理工具,如下图:

点击后,右侧会弹出Maven管理工具,如下图:

点击图中红框内的下载按钮,然后弹出浮动窗,在浮动窗内点击第一项Download Source,如下图:

 

然后IDEA下方会出现一个下载进度条,双击进度条可以最大化,里面有详细信息(如果网速很快或者Jar包很小,该进度条可能一闪而过),如下图:

 

最后我们回到实体类,将鼠标放到@Data上,点击Alt+Enter,然后在弹出的浮动窗上点击Import class,然后系统会为我们引入@Data注解所属的Jar包—import lombok.Data;。

现在@Data注解就可以正常运行了,不过,这个过程好像有点。。。

----------------------------------------------------------------------------------------------------

回到注解@SpringBootApplication。。。

注解@SpringBootApplication是一个组合注解,包含@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan。

@SpringBootConfiguration:将当前类标记为配置类。上文我提到了Java项目里有个web.xml配置文件(类似app.config),不过创建项目时并没有自动生成;其原因就是这个注解了。

Spring框架项目编译时会检测这个注解(组合注解@SpringBootApplication也会被检测),检测到后会把这个类下的函数,全部提取出来,然后在逐个处理; 怎么处理呢?我猜,是通过反射找到函数的函数名,参数,然后执行一下得到返回值;然后把这些字符串组成复合规则的Xml标签,再写进web.xml配置文件。

这样做的好处就是繁琐的XML文件配置,被转化成了代码编写,而且java项目的web.xml最终好像是会被编译进jar,所以这种动态生成web.xml的模式好想也没什么问题。

@EnableAutoConfiguration,@ComponentScan简单理解就是使其他注解生效,如@Controller等;换言之,是使其他注解状态为Enable和为其他注解提供配置信息的注解。

即该注解是其他注解的依赖。。。。。。

----------------------------------------------------------------------------------------------------

我们接着看代码,现在到了类的主体代码了,代码如下:

1
2
3
4
5
6
public class ArtifactApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(ArtifactApplication.class, args);
    }
}

可以看到,该类是一个拥有Main函数的入口类,类里Main函数主要实现一个功能调用SpringApplication命名空间下的静态方法Run。

我猜测,该方法的主要功能和AspNetCore的 WebHost.CreateDefaultBuilder(args).UseStartup<Startup>().Build();这句话是一个意思,都是启动一个服务器进程。

服务进程启动以后,就可以把我们的Web搭建进去了,我们可以看到Run函数第一个参数就要求主类的类名,这代表服务器启动后,会通过这个入参来启动Web项目。

这里Srping和Core的区别就是Spring启动的服务器是Tomcat,而Core启动的服务器是Kestrel。

创建一个Api

现在Java项目我们已经创建完了,该了解的基础我们也了解了,那么让我们一起创建一个Api,然后运行一下看看效果吧。

首先我们创建一个ApiController的文件夹,然后添加一个HelloController文件,然后编写代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RestController
public class HelloController
{
    @RequestMapping(value = "/GetName", method = RequestMethod.GET)
    public String GetName()
    {
        return "我是Kiba518";
    }
    @RequestMapping(value = "/GetAge", method = RequestMethod.GET)
    public int GetAge()
    {
        return 518;
    }
}

可以看到,代码中在类的上面加了一个注解@RestController,该注解表示当前类是一个遵循REST风格的Api类;类似于Net里的Controller继承ApiController。

接着我们创建了两个函数GetName和GetAge;他们的头上使用@RequestMapping注解,该注解的作用是设置访问该函数的地址。

即,函数GetName和GetAge的访问地址为 http://127.0.0.1:8010/GetName和 http://127.0.0.1:8010/GetAge;访问时,我们需要注意,GetName和GetAge这个地址是区分大小写的。。。

现在Shift+F10运行下项目,测试一下我们的WebApi。

 如上图,WebApi访问成功。不过我们访问的端口是8010。

还记得上面说的Spring启动时会创建一个服务器吗,这个端口就是服务器监听的端口。

当然了,这个端口是可配置的,配置的位置就在application.properties里。

不过.properties文件编写和阅读不太方便,我们把他改为.yml,然后修改代码如下:

1
2
server:
    port: 8010

这个配置文件里的内容是可以被Java访问的,而且Spring框架项目编译时也会先读这里的内容,找到同名的配置,就会替换默认的配置。

PS:Java中控制访问地址的注解非常多,控制地址访问的模式也非常多,多到有点夸张的地步。。。

结语

从开发工具的角度来看,Java的开发工具的使用相较Net而言,是比较怪异的,因为,它有一些工具的设计和使用是倒序的。

而Java工具又比较多,因此,这种正序工具和倒序工具同时存在同时使用,感觉上就有一点怪,不过习惯了以后倒也没什么。

从开发的角度来看,Java的主流Spring和Net几乎没有什么区别,唯一的区别就是Java使用注解而Net使用继承。

----------------------------------------------------------------------------------------------------

代码已经传到Github上了,欢迎大家下载。

Github地址:https://github.com/kiba518/KibaJavaStart

----------------------------------------------------------------------------------------------------

注:此文章为原创,任何形式的转载都请联系作者获得授权并注明出处!
若您觉得这篇文章还不错,请点击下方的【推荐】,非常感谢!

https://www.cnblogs.com/kiba/p/12052925.html

 

https://www.cnblogs.com/kiba/
 
分类: Java
原文地址:https://www.cnblogs.com/xichji/p/12208601.html