JAVAEE项目结构以及并发随想
长久以来统领javaee领域的脚手架以spring struts2 mybatis/hibernate引领;
Spring:
Spring is not just for Java services。spring作为cgi标准的实现,并不仅仅是作为Java领域的框架,C#平台依旧可以获益;spring提供了抽象化等各种方便的注解配置方式或者bootde 一体化方案,极大简化了Javaee的项目基础;
在spring的使用过程中,两面分化,一部分,轻量注解,一部分倾向于全注解。
首先注解的前提是必然要经历代理的,动态,静态,cglib代理。对于轻量注解,角度站在静态或者说是一次性注解,
比如controller注解,这些一次性的注解或者是编译期的注解,在项目上下文初始化作为一个隐射一次性扫描,相关的有service等类似注解,提供了单例的轻量级对象实例。视为首选。这样减少了运行期的代理,反射,这些动辄大动干戈的消耗,也为运行期的堆栈节约了更好的资源。
另一类比如responsebody,这类属于动态注解或者运行期的注解,每次请求,都会执行该注解的反射。运行期的注解,想当然是要占用资源的。
总的来讲,不是必须的注解完全可以不注解,基于servlet基础的request,response方式没有解决不了的mvc,取参,传参,返回等,完全不需要运行期的注解,运行期的注解看似是减少了代码量,为了补住这过程的各种缺,会运行一个圆环的动态注解来执行一个被你用在方法内部的注解。对于写在方法里面的param注解,相比于自己用request get 究竟少了哪些代码?不过是让原本一步到位的处理,加入了一层代码拦截。
如何知道一个注解是否是运行期或者编译期的注解,很简单,Ctrl+鼠标点击,会看见:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
Retention 这个枚举类型完整清晰的说明了你使用的注解的作用期。
用spring 大家都喜欢用单例,这是极好的方式,单例与并发本身毫无关系,除了你非要让它产生资源标识竞争,
如果说你的项目中必须要出现许多prototype的对象,那说明你滥用或者用错了对象,mvc基本都是入参,返回,每一个请求都是一个线程,一个单独的request response 有他们进出的东西,完全是隔离的。由此说到mybatis,许多人用mybatis一个配置里面各种resmapper,每次都是各种bean来回走,一个请求下来,作为参数以及结果的bean必须有一次,mybatis表面上面清晰了sql维护,是以极大程度拉低jdbc的效率为代价的,然后并没有很多人在意,bean对他们来讲,没有什么,不了解也不关心gc,出来问题就加内存,内存加到顶,解决的只是时间问题,以空间换取时间。同样的参数与结果映射,那么自己new 一个bean 使用jdk的map,哪个好,自然是jdk自身的map,
个人从来固执的认为,new一个jdk自身的对象,其消耗远小于自己定义一个bean。为什么,Sorry,i do not know either。所以我从来都是map来,map走。使用mybatis,一定要紧密检测,你的事物代理到你的类上面了吗,方法很简单,在项目的log里面,打开debug,看你的日志是不是每次都是 create a new sqlsession,要是这样的话 就要注意了 你的mybatis的session没有池化,没有被事物代理,一个方法里面如果出现了竞争性的sql,sorry 没有任何错误,只是发现数据库没有执行你的sql。很快,会发现连接池用的很快,频繁的会创建新的connection。当然如果可以不用mybatis,别犹豫,不用是对的。
为什么一定要尽量使用静态注解呢,很简单,spring的类基本都是singleton,项目够大,bean实例也就够多,这些单例的东西,占用了什么呢。对象实例在堆空间,引用在栈里面。那么gc什么时候会回收这些单例的对象呢?你认为呢?所以,在基于注解的时候,尽量减少动态代理的使用。留更多的资源给需要用的地方用。
以前我们会说无堆不可无栈,现在要变了jdk1.7的string常量池已经到堆里面了。
编译型与解释性哪个更好,当然是解析式的,编译型的类似于中介模型。因此构建一门优秀的编译型语言,难度远大于解释性语言。
web的结构很清晰,首先依旧是上下文,然后是按照顺序的一系列组件,我们最关键的是servlet组件,这个是javaee的标准,其余的web组件是协议标准,谁都必要有。那么会看见许多项目的servlet的mapping是/,这个是糟糕的方式,因为很简单,js或者css从来没有必要通过servlet来处理,因此mapping主要考虑到与web容器的服务端组件交互,一般给两种标识,比如.do and .action .do需要权限认证之类,action属于直接放行。js等不需要进入servlet,由web上下文根据url直接去返回,然后就没有在mvc里面加一个mvc的拦截与放行,多此一举,制造问题,解决问题,不是好方式。这样不管有没有nginx的介入,你的静态资源对于web容器来说就是静态走的,没有跟servlet产生关系。servlet只关系你需要其处理的东西。
js写在哪里好?
很多人习惯把js写在jsp里面或者html里面,这样说糟糕的。
我们构建项目,必须希望我们的js与css是一定能够被浏览器缓存的。
那么写在页面的script标签里面js,就是个标签而已,跟div或者input没有区别,不会被缓存,我查阅很多资料,看见的缓存,明显的写着,缓存的单位是文件。而不是标签。所以把你的css js写在文件里面,引入文件进来,这样文件会被缓存,这一点,我并不完全确定,因为没有直接肯定的答案,是我的猜想。
jsp实际上servlet,因此是动态的页面,每次都是需要加载class去动态翻译,然后class里面的write方法将页面写到http给浏览器,浏览器渲染,如果是html,那么是静态的。动态灵活,这个是毋庸置疑的,既然是servlet,那么就是java对象,各种Java的标签与方法称为可能。静态需要你自己去处理,静态页面使用类似宏语言,不如直接用jsp。
页面上面,一次加载多少数据好?
如果你的页面展示的东西按照类别,按照列表,数据量很少,几百条,类型现在外卖点餐app的展示方式,那么,一次给出所有的分类跟数据,所以的处理在客户端处理,整个过程中的类别切换,预览,全部在页面去处理,包括搜索,我们客户端的js, A的手机或者电脑里面执行的js不会跟B的手机或者电脑产生竞争吧,如果每次切换一个类型就去刷一个ajax,都是同一个web容器群,这样才有竞争。操作越频繁,竞争越大。这点要紧密关系到实际的场景。
一次查询返回的数据的量的多少与性能并无很多关系,几千几万条数据不过几十KB级别。
查询的次数,也就是交互到服务端的次数是影响整体性能的直接原因。
一次查询的数据量多少与被查询的表的大小是正比例,不会因为一次返回10条加快查询,一次返回1W条,拖慢查询,数据库操作本质上就是集合应用,并没有创建什么。
调优的前提是给多少最合适,不是给的越多越合适,jdk或者tomcat在不同位数不同的os上面能够消耗的内存都是有上限的。
使用nginx;
必要的时候使用缓存;
根据是否需要选择消息中间件或者其他中间件;
数据库的分离或者主从等,一定是当前数据库实在不能支撑业务量了。
单例是好的方式。
多线程是利刃,不区分具体哪种语言。
maven管理是好的方式,但是你的项目主体应该是webmvc,建立web的项目,嵌入maven作为组件使用,而不是建立一个maven工程,再去转成web项目,除非是闲的。
使用spring,目前是最好的脚手架。
尽可能使用jdbc,能够做到的话。
能够在客户端完成的事情,就不要去交互到服务端,客户端的资源是广袤的,服务端的资源的有限的。
尽量少发请求,少发请求的代码是好代码,除非是你是即时的应用。
每个代码里面的工具都是工具,API是你最需要理解的,哪个好,哪个不好,没有准确答案。
一切皆对象,对于Java来讲是纯粹的,代理是对象,反射是对象,对象是对象,基本数据类型不是对象。
除了基本类型之外的东西,都是通过对象来完成,不管多复杂的流程,都是通过对应的对象的方法结合方法的参数去完成的。一个class怎么序列化,怎么反序列化,说白了就是文件的io与传输,然后加载到jvm,构造成对象。
rpc之所以rpc,调用的不是一个线程里面的东西,调用的东西,被代理了,代理把你的需求转成参数作为数据流发出去了,服务端,把你的请求流再转成对象,再流化发回去,你再构造对象,通过对象来处理。
NIO是好的方式,netty是不错的选择,多线程的socket有超越netty的吗?
zookeeper是好的分布式注册等一系列方案的优秀工具。
这些东西都是原理加对象,用就要去使劲看。
以上是个人理解,欢迎指正。