Fork me on GitHub

品Spring:bean定义上梁山

原文链接 品Spring:bean定义上梁山

技术不枯燥,先来点闲聊

先说点好事高兴一下。前段时间看新闻说,我国正式的空间站建设已在进行当中。下半年,长征五号B运载火箭将在海南文昌航天发射场择机将空间站核心舱发射升空。预计用2到3年将空间站建好。

虽然到时你们不让我上去,不过我也为这件事出不了什么力,算扯平了。哈哈,但是我还是会衷心的祝福你。

长征五号火箭首次采用5米大直径的箭体结构,总加注量达到780吨,起飞时共有10台发动机产生1078吨的推力,具备近地轨道25吨、地球同步转移轨道14吨的运载能力。

不要误会,本文不是讲火箭的,关键我也讲不了呀。但是我们可以分析下火箭的特点。自身体积和重量非常大,内部结构与实现极其复杂。能够运送的物品与自身比起来微乎其微,关键这玩意老贵老贵了。

因此SpaceX推出的猎鹰可回收火箭,从一开始就受到了全世界的关注。回收之后可以被重新利用,不但缩短了火箭发射的周期,平均下来每次发射的成本也少了很多。享受同样的服务,花更少的钱,不是所有人的最爱嘛。

回到程序,其实现在大部分程序员,包括我自己在内都应该属于2.0或3.0版本的程序员,因为我们的职业生涯都是从Spring开始的。在Spring之前Java企业级应用开发标准其实是EJB(企业级JavaBean)。

EJB只是一个标准或规范,由各大服务提供商来实现。EJB非常笨重而且用起来也痛苦,关键还很贵。其实和火箭的性质一样,自身的负担太重。这个问题必须要解决。

因此,Elon Musk认识到了这点,就开始着手研制可回收火箭。在当时,Rod Johnson也认识到了EJB特点并深受其害,于是发明了Spring,轻量级、免费开源,慢慢就流行起来了。

看到了吧,在工作或生活中,凡是遇到苦逼的地方,就说明这也是一个极有可能产生大成功的地方。这个秘密我可是告诉诸位了,能不能成功就看你们的了。哈哈。

其实Spring现在也已经变得足够复杂了。

要想渡人,必先渡己

易中天老师曾说过,能够制造工具标志着人类的诞生。目前人类建造的文明,哪一个是通过双手刨出来的,不都是通过工具建造出来的嘛。

比如我们盖高楼用的建材,不都是通过塔吊一点点吊上去的,随着建材的堆砌,楼越来越高。那么我们来思考一个问题,塔吊本身是如何上去的?

塔吊本身就是一个工具了,所以(一般情况下)不可能再有其它工具来帮它了。所以塔吊只能实现自我爬升,实际也是这样的,相信大多人都见过,速度很慢的。

我们都在用Windows操作系统,点点鼠标,敲敲键盘,用着很爽。但是在开发Windows系统本身时却是很苦逼的一件事。

我主要想表达两方面的意思:

如果有一天,我们能从工具的使用者变成设计者或制造者,那就厉害多了。

还有就是,一个工具在对外提供服务前,一定要解决好自身的搭建或构建问题。

Spring其实就是个工具,开发人员把业务代码写好后,把类作为bean注册到工具上,后续的运行时全部交由Spring这个工具接管,简直不要太爽。

阅读更多...

品Spring:帝国的基石

来源:公众号【编程新说】

生活是一杯酒,有时需要麻醉自己,才能够暂时忘却痛苦与不快。
生活是一杯茶,有时需要细细品味,才发现苦涩背后也会有甘甜。

Spring是一杯酒,一眼望不到边的官方文档,着实让人难以下咽。
Spring是一杯茶,在无边的源码中畅游之后,发现色相味道俱全。

高考状元是六月份的网红,Spring帝国是Java界的明星。
状元有自己的“武功秘籍”,Spring有自己的“帝国基石”。

请随本文一起,品Spring,寻找帝国的基石。

帝国的基石

无论是大到一个国家,或是小到一个个人,都有自己赖以存在的基石。这个基石就是核心支柱,就像经济基础支撑着上层建筑。

以BAT来说,百度的搜索,阿里的电商,腾讯的社交。可以说这是他们的立司之本,如果想在这些方面和他们PK,几乎没有胜算的可能。

Spring绝对是Java开发领域中一颗闪耀的明星,它的巨大光芒甚至一直在引领着Java的发展方向。

现在说它已经发展为一个帝国,应该不会有人站出来反对吧。嗯,站出来也没关系,本人不接受反对。哈哈。

那么有一个问题,请大家思考下,Spring帝国的基石是什么?

用过或了解Spring的人肯定都会说是IoC啦,AOP啦,声明式事务啦等等。只能说这些回答浮于表面,明显不走心啊。

好了,我来公布答案吧,这个帝国的基石,其实就是Bean。肯定会有人问,这个bean是什么东西啊,那就去看它的定义吧。对,就是Spring中的bean定义。

在Spring中,bean定义其实就是一个接口,即BeanDefinition。我在上一篇“毕业十年”的文章中说过,我们定义的类或接口其实都是对一种数据构成的描述,所以可以直接把类或接口看作是一种数据结构。

那么bean定义接口,就是一种数据结构,它记录了一个bean的全部信息,后期Spring对这个bean的所有操作都是建立在这些信息之上的。

如果对Spring不是很熟悉的朋友,听到“bean的全部信息”这句话会有点懵。不要担心,照例拿生活中我们熟悉的事物去做类比,争取让所有人都能明白。

在医疗行业,每个患者都会有一个病历,上面记录了患者家族病史,患者个人病史,都做过哪些检查以及检查结果,都做过哪些治疗以及恢复情况。还有大夫每次对患者的病情诊断与分析。

这些信息肯定是记录的越全面越好,后续的治疗方案都是依赖这些信息而制定的。Spring中bean的信息就对等于这里患者的病历信息。

在公安系统,每个嫌疑人也会有一个档案,上面记录了他的口供,作案信息或一些其它证据,同样这些信息搜集的越全面越好,后期法官的宣判与量刑也都依赖于它。

那么在这里,记录案件信息的档案,就可以对等于Spring中bean的信息。

相信通过这两个示例,你已经完全明白了这个bean信息的作用和地位。虽然到目前为止,你可能还真不知道它里面到底存储的是什么信息。但这不要紧,只要记住它非常重要就可以了。

趁着这个机会,再小小拓展一下:

这里的病历信息和档案信息里面记录的都是一些数据,所以可以认为它们对应于程序中的数据结构。

医生的治疗方案和法官的宣判,其实都是依赖这些数据做出的决定,因此可以认为它们对应于程序中的算法。

可见,数据结构决定着算法,或者说,算法是基于数据结构而设计的。

因此,可以说数据结构的重要性要大于算法。良好的数据结构能简化算法,不好的数据结构只能使算法变得更复杂。

跟着变化走,把它当朋友

在上篇文章中提到过,唯一不变的就是变化,所以随着时间的推移,只需不断往这个数据结构中补充新的bean信息,Spring再利用这些补充信息去定义新的操作,以适应发展的需要。

就是这样,Spring一步一步成长为一个浩浩荡荡的帝国。就像我在上一遍文章中说的,类或接口这样的数据结构一定要进行精心设计,这样代码写起来会简单些,而且后期改起来也会容易些。

阅读更多...

实体继承与@Builder注解共存

原文地址 https://www.cnblogs.com/lori/p/10266508.html

在面向对象的设计里,继承是非常必要的,我们会把共有的属性和方法抽象到父类中,由它统一去实现,而在进行lombok时代之后,更多的打法是使用@Builder来进行对象赋值,我们直接在类上加@Builder之后,我们的继承就被无情的屏蔽了,这主要是由于构造方法与父类冲突的问题导致的,事实上,我们可以把@Builder注解加到子类的全参构造方法上就可以了!

下面做一个Jpa实体的例子

一个基类

它一般有统一的id,createdOn,updatedOn等字段 ,在基类中统一去维护。

注意:父类中的属性需要子数去访问,所以需要被声明为protected,如果是private,那在赋值时将是不被允许的。

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
36
37
38
39
/**
* @MappedSuperclass是一个标识,不会生成这张数据表,子类的@Builder注解需要加在重写的构造方法上.
*/
@Getter
@ToString(callSuper = true)
@AllArgsConstructor
@NoArgsConstructor
@MappedSuperclass
public abstract class EntityBase {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
protected Long id;


@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Column(name = "created_on")
protected LocalDateTime createdOn;

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Column(name = "updated_on")
protected LocalDateTime updatedOn;

/**
* Sets createdAt before insert
*/
@PrePersist
public void setCreationDate() {
this.createdOn = LocalDateTime.now();
this.updatedOn = LocalDateTime.now();
}

/**
* Sets updatedAt before update
*/
@PreUpdate
public void setChangeDate() {
this.updatedOn = LocalDateTime.now();
}
}

一个实现类

注意,需要重写全参数的构造方法,否则父数中的属性不能被赋值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Entity
@Getter
@NoArgsConstructor
@ToString(callSuper = true)
public class TestEntityBuilder extends EntityBase {
private String title;
private String description;

@Builder(toBuilder = true)
public TestEntityBuilder(Long id, LocalDateTime createdOn, LocalDateTime updatedOn,
String title, String description) {
super(id, createdOn, updatedOn);
this.title = title;
this.description = description;
}
}

单元测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 测试:在实体使用继承时,如何使用@Builder注解.
*/
@Test
public void insertBuilderAndInherit() {
TestEntityBuilder testEntityBuilder = TestEntityBuilder.builder()
.title("lind")
.description("lind is @builder and inherit")
.build();
testBuilderEntityRepository.save(testEntityBuilder);
TestEntityBuilder entity = testBuilderEntityRepository.findById(
testEntityBuilder.getId()).orElse(null);
System.out.println("userinfo:" + entity.toString());

entity = entity.toBuilder().description("修改了").build();
testBuilderEntityRepository.save(entity);
System.out.println("userinfo:" + entity.toString());
}

Swagger java.lang.NumberFormatException:For input string:"" 解决办法

原文地址 https://doc.xiaominfo.com/guide/format-exception.html

很多朋友在升级Springfox-Swagger到2.9.2版本后会碰见NumberFormatException异常java.lang.NumberFormatException: For input string: “”

异常信息如下:

1
2
3
4
5
6
java.lang.NumberFormatException: For input string: ""
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) ~[na:1.8.0_111]
at java.lang.Long.parseLong(Long.java:601) ~[na:1.8.0_111]
at java.lang.Long.valueOf(Long.java:803) ~[na:1.8.0_111]
at
//more....

解决办法是在pom.xml中排除Springfox-Swagger的Swagger-Models的jar包,重新引入,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
<exclusions>
<exclusion>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
</exclusion>
</exclusions>
</dependency>

<!-- https://mvnrepository.com/artifact/io.swagger/swagger-models -->
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
<version>1.5.21</version>
</dependency>

七成毕业生月薪不足6000:除了工资,第一份工作还应该看重什么?

原文地址 https://mp.weixin.qq.com/s/0dn2DnEJT1T7ajr2BPYG8w

昨天关于毕业生薪酬的数据上了微博热搜,戳中了很多年轻人的痛点:七成毕业生月薪不足6000。

根据《2019年大学生求职指南》数据显示,从实际签约月薪来看,有七成应届毕业生的签约月薪在6000元以内,4000元以下占比为35.77%。

毕业生薪酬不高带来的是签约难。应届生尚未签约的原因中,“薪水/待遇未达到期望值”仍是首要因素,比例达到38.23%。

毕竟是人生的第一份工作,很多毕业生都心怀期望慎之又慎,可是有时候,走走停停找来找去,却发现现实远比想象更残酷。一边是需求降低,一边是薪资减少,很多年轻人忍不住会纠结,第一份工作到底要不要在意薪酬。

年轻人到底要不要在意薪酬,其实不能一概而论,毕竟比起薪水,还有很多其他方面值得考虑。

1

首先,要考虑行业发展。

数据显示,在所有的招聘行业中,就业形势最好的行业依然是中介服务,今年该行业的企业招聘需求同比增长25%。

需求上涨的同时,在这个行业求职的大学生数量却在减少,2019届应届生投递中介服务行业的人数同比减少21%。

很多毕业生在职业选择上喜欢随大流,盲目涌向热门行业。

但是衡量一个行业,热门与否不应该是主要考量因素。有些热门行业本身并不具备长期发展,比如马云曾经举的一个例子,数据分析是热门职业,但是十年后,可能会被AI取代。

而且由于竞争激烈,人才辈出,你能谈判的资本并不多。反倒是冷门行业,由于招聘需求大,年轻人更容易谈出好条件。

宁向东曾经做过这样的比喻,选择行业其实就等于是选择投资。

当年,有一家投资机构,他们在选择是否要投资高铁行业的时候,首先问自己的就是,高铁在中国有没有前途?

选行业,其实也可以参考这个思路。选择一家公司,要看行业发展。它们做的事,是不是符合未来发展需要,只有在人们的生活息息相关的行业里,你才会找到未来事业发展的机会和希望。

2

其次,要考虑个人职业发展空间。

所谓个人职业发展空间,其实就是成长性。

阅读更多...

面试:一个Java对象到底有多大?

出处:http://u6.gg/swLPg

编写Java代码的时候,大多数情况下,我们很少关注一个Java对象究竟有多大(占据多少内存),更多的是关注业务与逻辑。但是殊不知,在我们不经意间,大量的内存被无形地浪费了。

这也是一个很基础的 java 面试考点

一个Java对象到底有多大?

想要精确计算一个Java对象占用的内存,首先要了解Java对象的结构表示。

Java对象结构

一个Java对象在Heap的表示,可以分为三部分:

  • Object Header
  • Class Pointer
  • Fields

每个普通Java对象在堆(heap)中都有一个头信息(object header),头信息是必不可少的,记录着对象的状态。

32位与64位占用空间不同,在32位中:

1
hash(25)+age(4)+lock(3)=32bit

32位与64位占用空间不同,在32位中:

1
hash(25)+age(4)+lock(3)=32bit

64位中:

1
unused(25+1)+hash(31)+age(4)+lock(3)=64bit

我们知道,在Java中,一切皆对象;每个类都有一个父类, ClassPointer就是当前对象父类的一个指针,在32位系统中,这个指针为4byte;在64位系统中,如果开启指针压缩(-XX:+UseCompressedOops)或者JVM堆的最大值小于32G,这个指针也是4byte,否则是8byte。

关于字段(Fields),这里指的是类的实例字段;也就是说不包括静态字段,因为这个字段是共享内存的,只会存在一份。

阅读更多...

深入理解JVM

视频地址 https://www.youtube.com/watch?v=wBR1w3kSBhE&list=PL9avoKyUyEuzk6yl5X20r2SYRUcXcw-zs

01 学习方法论与高效学习方式演进

向事情学习

向人学习

输出

后会无期

知道很多道理,确过不好这一生

需要持久化,需要输出。一定要吐出来

输出,输出,输出,输出!

刻意练习。

02 JVM学习曲线与疑难点剖析

1 模仿,不管底层

有节奏,有计划的去学习

03 深入理解JVM课程大纲分析与工具使用

JVM

介绍:JVM是一个令人望而却步的领域,因为它博大精深,涉及到的内容与知识点非常之多。虽然Java开发者每天都在使用JVM,但对其有所研究并且研究深入的人却少之又少。然而,JVM的重要性却又是不言而喻的。基于JVM的各种动态与静态语言生态圈已经异常繁荣了,对JVM的运行机制有一定的了解不但可以提升我们的竞争力,还可以让我们在面对问题时能够沉着应对,加速问题的解决速度;同时还能够增强我们的自信心,让我们更加游刃有余。

  • JVM介绍
  • HotSpot虚拟机讲解
  • 垃圾收集方式详解

【TED演讲】不要为了后悔而后悔

  • 教育
  • 事业
  • 爱情
  • 子女教育
  • 对自身的决定
  • 闲暇时间
  • 表现执拗

面对后悔的建议

  1. 意识到后悔的普遍性

  2. 学会自嘲

  3. 通过时间的流逝慢慢地平和面对遗憾

  4. 有时候你后悔的东西不像你原想的那样糟糕

天天用Synchronized,底层原理是个啥?

作者:liuxiaopeng

原文地址::https://www.cnblogs.com/paddix/p/5367116.html

Synchronized 的基本使用

Synchronized 的作用主要有三个:

  • 确保线程互斥的访问同步代码
  • 保证共享变量的修改能够及时可见
  • 有效解决重排序问题

从语法上讲,Synchronized 总共有三种用法:

  • 修饰普通方法
  • 修饰静态方法
  • 修饰代码块

接下来我就通过几个例子程序来说明一下这三种使用方式(为了便于比较,三段代码除了 Synchronized 的使用方式不同以外,其他基本保持一致)。

没有同步的情况

代码段 1:

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
36
37
38
39
40
41
42
43
44
package com.paddx.test.concurrent;

public class SynchronizedTest {
public void method1(){

System.out.println("Method 1 start");
try {
System.out.println("Method 1 execute");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Method 1 end");
}

public void method2(){
System.out.println("Method 2 start");
try {
System.out.println("Method 2 execute");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Method 2 end");
}

public static void main(String[] args) {
final SynchronizedTest test = new SynchronizedTest();

new Thread(new Runnable() {
@Override
public void run() {
test.method1();
}
}).start();

new Thread(new Runnable() {
@Override
public void run() {
test.method2();
}
}).start();
}
}

执行结果如下,线程 1 和线程 2 同时进入执行状态,线程 2 执行速度比线程 1 快,所以线程 2 先执行完成。推荐阅读:多线程 start 和 run 方法到底有什么区别?

这个过程中线程 1 和线程 2 是同时执行的:

1
2
3
4
5
6
Method 1 start
Method 1 execute
Method 2 start
Method 2 execute
Method 2 end
Method 1 end

对普通方法同步

代码段 2:

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
36
37
38
39
40
41
42
43
package com.paddx.test.concurrent;

public class SynchronizedTest {
public synchronized void method1(){
System.out.println("Method 1 start");
try {
System.out.println("Method 1 execute");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Method 1 end");
}

public synchronized void method2(){
System.out.println("Method 2 start");
try {
System.out.println("Method 2 execute");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Method 2 end");
}

public static void main(String[] args) {
final SynchronizedTest test = new SynchronizedTest();

new Thread(new Runnable() {
@Override
public void run() {
test.method1();
}
}).start();

new Thread(new Runnable() {
@Override
public void run() {
test.method2();
}
}).start();
}
}

执行结果如下,跟代码段 1 比较,可以很明显的看出,线程 2 需要等待线程 1 的 Method1 执行完成才能开始执行 Method2 方法。

阅读更多...
  • Copyrights © 2015-2023 高行行
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信