实际工作中项目会依次部署到多套环境,例如测试、灰度和生产。一般来说每套环境的资源地址都是独立的,这意味着项目在构建时要动态决定启用哪套配置以适应当前的环境。

下面介绍在maven中实现根据环境动态处理配置的两种方式。

方式一

1.在项目POM文件中配置profile

在构建项目时添加-P [profile_ID]选项可以激活指定profile,可以写多个ID,中间用逗号分隔即可。如果不指定具体的profile则默认启用local,因为在local里面配置了activeByDefault=true。

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
<profiles>
<profile>
<id>local</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<package.environment>default,local</package.environment>
</properties>
</profile>
<profile>
<id>dev</id>
<properties>
<package.environment>default,dev</package.environment>
</properties>
</profile>
<profile>
<id>test</id>
<properties>
<package.environment>default,test</package.environment>
</properties>
</profile>
<profile>
<id>staging</id>
<properties>
<package.environment>default,staging</package.environment>
</properties>
</profile>
<profile>
<id>production</id>
<properties>
<package.environment>default,production</package.environment>
</properties>
</profile>
</profiles>
阅读全文 »

本文介绍的方法仅供学习使用,如果要正式使用请购买许可证。

StartUML是一款非常棒的UML图绘制工具,官方提供了试用版本,但它在使用时会有所限制,在每次保存时有可能弹出让你购买许可证的提示,以及在将设计图导出成图片时会自动添加上水印。

那如何屏蔽掉这些限制呢?请看下面的方法:

阅读全文 »

在实际项目开发过程中我们经常会遇到把A类的属性复制到B类中的这种场景,比如实体类DO对象从数据库查询出来,在给到调用方之前很可能需要转成DTO传输对象,那这个时候就需要将DO对象的字段值复制到DTO对象中,如果字段比较少可能你手写就行了,但如果要复制的字段比较多,超过50个,并且这种场景在项目中出现频繁,该怎么办?仍然还是去手写,然后一点一点复杂吗?如果这样做那效率必然是低下的,而且没有一点儿技术含金量,花大把时间写这种样本代码对自己成长帮助不大。接下来介绍的是一款让你更优雅的实现Bean之间属性映射的框架,并且在同类框架中性能是最好的。

介绍

MapStruct是一个代码生成器,它基于约定优于配置的方法极大地简化了Java bean类型之间映射的实现。

通过上面的介绍我们应该能够理解到这么几点,首先它是一个代码生成器,就是用来帮开发者自动生成代码的工具,只需要通过简单的代码就可以实现原来手工编写的样板代码,因为它采用约定大于配置的设计思想,所以开发者只需要掌握简单的代码编写就可以了。

也就是说人家框架帮你自动生成了原先手工编写的代码,但实际上那些手工编写的代码还是存在的,只不过你没有编写,框架帮你自动生成了而已。这其实也回到框架的本质,事情还是那些事,就看你来做,还是它来做,它如果多做,你就少做,甚至可以不做。这里提到的指的是各种框架,它的本质就是帮开发者做了一些事情。

阅读全文 »

OutOfMemoryError

java.lang.OutOfMemoryError

Java heap space

Java应用程序仅允许使用有限的内存,此限制是在应用程序启动期间指定的。Java内存被分为两个不同的区域,这些区域称为Heap(堆空间)和Permgen(永久代):

这些区域的大小是在Java虚拟机(JVM)启动期间设置的,可以通过指定JVM参数-Xmx和-XX:MaxPermSize进行自定义。如果未明确设置大小,将使用特定于平台的默认值。

应用程序尝试添加更多的数据放入堆空间区域,但没有足够的空间供它,可能会有大量的物理内存可用,但当JVM达到堆大小限制时,都会引发Java堆空间错误。

是什么原因造成的?

因为你尝试将XXL大的对象放入S大小的Java堆空间中。也就是说,该应用程序需要更多的Java堆空间才能正常运行。

  • 用量/数据量激增。该应用程序旨在处理一定数量的用户或一定数量的数据。当用户数量或数据量突然达到峰值并超过预期阈值时,在峰值之前正常运行的操作将停止运行并触发java.lang.OutOfMemoryError: Java heap space。
  • 内存泄漏。一种特殊类型的编程错误将导致你的应用程序不断消耗更多的内存。每次使用应用程序的泄漏功能时,都会将某些对象留在Java堆空间中。随着时间的流逝,泄漏的对象会消耗所有可用的Java堆空间。
    阅读全文 »

什么是垃圾回收

跟踪所有仍在使用的对象并将其余对象标记为垃圾的这一过程就叫做垃圾回收。

手动内存管理

在开始介绍现代Garbage Collection之前,快速回顾一下以前不得不手动和显式分配和释放数据存储空间的日子。如果你忘记释放它,则将无法重用它,但这块内存已经被声明了只是没有被使用,这种情况称为内存泄漏

下面是一个用C语言编写的,使用手动内存管理的简单示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int send_request() {
size_t n = read_size();
int *elements = malloc(n * sizeof(int));

if(read_elements(n, elements) < n) {
// elements未释放
// 因为代码运行到此处就返回了,elements还来不及释放
return -1;
}

// …
// 如果运行到此处才会被释放
free(elements)
return 0;
}

如你所见,忘记释放内存是很容易的。内存泄漏曾经是比今天更常见的问题,你只能通过修复代码来真正打败“它们”,那有没有更优雅的解决方案呢?答案是肯定的,更好的方法是采取自动回收未使用的内存的策略,从而完全消除人为错误的可能性。这种自动化的过程称为垃圾收集(或简称GC)。

自动内存管理

在上面的C++代码中必须明确地知道何时需要进行内存管理,把这个工作给程序员,就意味着肯定有系统性风险,即人为忽略。如果把内存管理交给程序自己处理呢?这将非常方便,因为开发人员不再需要考虑自己清理。在程序运行时将自动了解不再使用某些内存并将其释放。换句话说,它会自动** 收集垃圾**。第一个垃圾收集器是在1959年为Lisp创建的,此后技术才有所发展。

引用计数(Reference Counting)

上面用C++的共享指针示例可以适用于所有对象,并且许多语言(例如Perl,Python或PHP)都采用这种方法。下面用图片说明:

绿云(GC ROOTS)表示程序员指向的对象仍在使用中。从技术上讲,这些可能是当前正在执行的方法中的局部变量或静态变量之类的东西。

蓝色圆圈是内存中的活动对象,其中的数字表示其引用计数。灰色圆圈表示没有被哪个仍在显式使用的对象中引用。因此灰色表示的是垃圾,可以由垃圾收集器清理。

这一切看起来真的很好,不是吗?但是这个策略有一个巨大的缺点。如果原先的引用不存在了,但可能它们之间仍然有相互引用,这种循环引用的问题,会导致它们的引用计数永远不为零。下面是一个例子:

红色圆圈表示的对象实际上是应用程序不使用的垃圾,可是由于引用计数的限制,仍然会存在内存泄漏问题。

有一些方法可以解决此问题,例如使用特殊的“弱”引用或应用单独的循环收集算法。上述语言(Perl、Python和PHP)都以某种方式处理循环,不过本方主要介绍JVM采取的方法。

阅读全文 »