摘自: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我们就了解了,这个承载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