JavaBean 的取名
“A Java Bean is a reusable software component that can be manipulated visually in a builder tool.”,这句话出自于 Oracle 官方文档,翻译过来,含义便是:Java Bean 就是一个可复用程序组件,其在编译工具中可以可视化地操作。
bean 作为“豆子”这个含义实际上没有什么特别的比喻含义,如果有,那也便是 小东西、小部件的含义。在 Spring 框架中使用了 JavaBean,并将它们用作“POJO”。这是因为它们没有从其他类或这接口上继承或实现。beans 的set
方法是依赖注入( Dependency Injection )的基础。
规范详情
其规范(框架)可以总结为如下:
- 所有属性为 private;
- 有一个 public 默认构造器(例如无参构造器,有的人认为其必为无参构造器);
- 提供 getter 和 setter(方法加上字段名用于区分);
- 实现 serializable 接口(部分人可能认为这个不一定要实现);
发展历史
关于起源可以详见Oracle 官方文档:JavaBeans,或者像我一样引用知乎用户文朋的回答。
- 在 1996 年 Java 发布,当年12月即发布了 Java Bean1.00-A,有什么用呢?通过统一的规范可以设置对象的值(get,set 方法),这是最初的 Java Bean;
- 最初的 JavaBean 用于桌面的 GUI 设计,但是后来逐渐发展为只要符合 Java Bean 规范,即使不用于 GUI 设计(设计上 Java 的 GUI 领域表现并不好),也统称为 Java Bean;
- 在实际企业开发中,需要实现事务、安全、分布式,JavaBean 就不好用了。sun 公司就开始往上面堆功能,这里 Java Bean 就复杂为 EJB;
- EJB 功能强大,但是太重了。此时出现 DI(依赖注入),AOP(面向切面)技术,通过简单的 Java Bean 也能完成 EJB 的事情,这里的 Java Bean 简化为 POJO(但是这个发生 Spring 诞生之后,为时已晚了);
- EJB 中用起来极为繁琐和笨重, 性能也不好, 为了获得所谓的分布式,反而背上了沉重的枷锁。因为 EJB 的难以使用以及后续框架的诞生,EJB 最终被抛弃了;
- Spring 诞生了;
这里单独拎出 Java 的后端开发发展历史:参考于:老李-大连以及linix
开发模式 | 出现年代 | 评价(根据最初版本,但不局限于最初版本) |
---|---|---|
CGI | 1993 | CGI可以直接吐出一个html网页,也可以进行各种计算、逻辑处理任务。但随着各类web前后端技术的发展,以及大数据、高并发的Server使用场景越来越多。现代的CGI的用法,在发生变化。越来越多的任务从后端转移到前端,前端页面利用强大的JS承担起更多的责任。 |
Servlet | 1997 | SUN公司刚刚推出JavaEE(Java企业版)时,推出了Servlet这个东西,命名就是Service Applet,即服务小程序。Servlet可以说是Java技术中最早的Web解决方案,Servlet与普通Java类的编写非常类似。开发servlet必须精通网页前端和美工,你得非常不直观的在Servlet中写前端代码,这使得实现各种页面效果和风格非常困难。对于后端来说,所有的业务逻辑、页面跳转、央视表现全部混杂在同一个类中,并且一项业务一般只有一个Servlet类与其对应,实在是….太麻烦了。 |
Servlet JSP | 1999 | Java服务器页面(JSP)是HttpServlet的扩展。由于HttpServlet大多是用来响应HTTP请求,并返回Web页面(例如HTML、XML),所以不可避免地,在编写servlet时会涉及大量的HTML内容,这给servlet的书写效率和可读性带来很大障碍,JSP便是在这个基础上产生的。其功能是使用HTML的书写格式,在适当的地方加入Java代码片段,将程序员从复杂的HTML中解放出来,更专注于servlet本身的内容。JSP在首次被访问的时候被应用服务器转换为servlet,在以后的运行中,容器直接调用这个servlet,而不再访问JSP页面。JSP的实质仍然是servlet。虽然JSP可以实现网站的快速开发,但依然存在缺点:网站的输入输出、处理、控制全部夹杂在一起,维护不方便,即使只需要修改该页面的一个简单按钮文本,或者一段静态的文本内容,也不得不打开混杂的动态脚本的页面源文件进行修改。当网站中需要进行大量的处理代码的时候,JSP文件将很难维护,并且代码也不容易共享。 |
JSP JavaBean(Model1) | / | Java Bean 虽然早在 1996 年便已推出,但是其用于服务器开发却晚很多年。这种开发模式有一个简单的分层 JSP:表现层、控制层 JavaBean:模型层 利用我们现在熟悉的MVC模型的思想去看,虽然编写代码十分容易,但Jsp混淆了MVC模型中的视图层和控制层,高度耦合的结果是Jsp代码十分复杂,后期维护依旧困难。一般建议应用于消息的 web 项目。 |
Servlet JSP JavaBean(Model2) | / | 一般将此称为:倡导了MVC思想的 servlet 版本 servlet1.2。页面的表现由 jsp 实现,转发控制由 servlet 实现,业务逻辑写在业务逻辑层,操作数据库部分写在持久化层,分工明确,各司其职。 |
Struts | 2001 | 倡导了MVC思想的jsp javabean servlet出现,也存在问题:1)jsp页面中嵌入了很多java代码,使得结构很乱;2)对于大型项目,servlet过多,转向频繁,流程,配置等不易集中管理,因而出现了strutsstruts针对jsp推出了一套struts标签,从而使得jsp中没有了Java代码,结构清晰,功能强大。针对servlet,它提供了Action类来代替了servlet,这个Action类具有servlet的功能,并且能够进行一些请求过滤和自动转码的功能。 |
Spring | 2002 | 原本已经开起来很完美了,但是又有一个问题,就是我们在Action调用DAO、Java bean等对象的时候都需要在自身代码中构建它们的对象来使用,这样增加了程序的耦合性,这与我们:“高内聚、松耦合”的思想不符合,那么怎么解决这个问题呢?因而出现了Spring框架。Spring框架有两大功能:IOC(控制反转)和AOP(面向切面的编程),其中IOC就是说:当一个类中想要调用另外一个类的对象时,不需要再通过new 关键字来创建,而是由Spring框架来负责:创建、分配和管理,从而降低了程序中的耦合性。而AOP可以用来做一些日志的打印和输出,用于提示程序执行过程中的一些具体信息等。 |
SpringMVC | / | / |
为什么使用 JavaBean
- 可进行优秀的序列化,而 Servlet 要求 sessions 必须是可序列化的,为了满足这个要求,对象应当是可序列化的,那么进一步设置为 JavaBean 也不是很费力气(不妨这么做,多做一步还能享受其他好处!);
- 可以使用反射进行初始化;
- 可以使用反射进行方便的控制;
- 利于将真实数据封装,远离于业务代码;
- 既然已然为一个惯例,那么你使用别人的类,或者别人使用你的类,不需要高额的学习代价;
- 非常接近 POJO,这实际上意味着系统不同部分之间的互操作性更高;
- 有利于解耦,所以在应用程序中进行传输数据是一件很容易的事情;
- beans 的
set
方法是 Spring 框架中依赖注入的基础;
这个回答也是很好的:
Before we go into programming, let’s talk about real life.
Let’s say you are at home, and your kids are bored. You decide to buy a new toy for them. So, you go to the toy store, and ask them to give you a plane. They bring out a box, which you purchase. You take the box home, open it with your kids, but there’s no plane! But, there are a bunch of instructions that tell you how you can construct a plane. You get frustrated! You wanted a plane! So, you go to a restaurant, and ask them to serve you a burger. They come out and give you some wheat seeds, tomato seeds, lettuce roots, a pile of dirt, water… and a cow… Here’s your sandwich. You just need to construct it.
Does that sound silly or senseless to you? Probably it does. You can obviously construct a plane, and grow your own burger yourself, right? Why do you want to complicate things by creating things in factories and farms and then bringing them all the way to the store/restaurant? This does sound silly because, in real life, most people understand that a person using A thing is not the best person to create that thing. This is called as separation of concerns. You, as a consumer, are not concerned with creating things, only using them. Someone else better suited to constructing those things is constructing them. In real life, we have separation of concerns is necessary because you do not have equal capability. Inside the computer, theoretically, one piece of code that is executing in the same CPU is equally capable of constructing objects that are constructed in another piece of code executing in the same CPU, right? I believe this is the crux of your question, no?.
So, let’s look at some other advantages that separation of concerns gives you. Let’s say you are driving to work. You get into your Honda Civic, put the key in the ignition, turn it on, put the gear in drive, release the brake, press the gas pedal and off you go. On the way to work, you notice the car rattling a bit. You take your car to the mechanic, and he says he has to keep the car for a few days. He lends you a Toyota Corolla. You get into the Corolla, put the key in the ignition, turn it on, put the gear in drive, release the brake, press the gas pedal and off you go. Wait a minute! Something weird happened here. You are driving a completely different car! But you aren’t doing anything different. If you were a airplane pilot, you would be licensed to fly one kind of plane, and moving to another kind of plane would require hours of training and years of practice! ANd here you are driving a completely different car without any need for training and practice. What wizardry is this?
It’s not wizardry. It’s what programmers call called building to the interface. See, you have learnt to operate the car through it’s interface(steering wheel, gas pedal, brake and gear shift) The complexity of turning the machinery that operates the hundreds of components in the car are all hidden from you. Car manufacturers have more or less standardized this interface across the industry. So, one you know how to drive one car, you know how to drive all of them. The same thing happens with software modules. Once a module is implemented to call another component through it’s interface, then it can call any other component through the same interface. This is a huge advantage that separation of concerns gives to programming code: It provides flexibility. More importantly, it helps you write code that is cohesive. Cohesive code is code that is written a way in which each module does one thing and one thing only.
Now, at this point, some people will say, “Gah! I have already built to the interface. I am doing this”
代码语言:javascript复制Car myCar = new Honda.Civic() // construct the civicmyCar.drive() // use it
Yes, this is better but doesn’t meet our goal of complete seperation fo concerns. Imagine if you went to the Honda dealership and told them that you want to buy a Civic, and they give you all the parts and you have to construct it yourself. Do you even care about a standard interface now? You have intimate knowledge of making the Civic. You are already dependent on your car being a Civic. How does it matter if you are building to the interface. By forcing you to construct a Civic from scratch, the dealership has already put Civic specific business logic into your code. Who cares if it’s the interface now?
What you really want to do is this
代码语言:javascript复制Car myCar = HondaDealership.buyCivic()myCar.drive()
THis is much better. Now, the dealership takes care of all the details of actually making the car, and you don’t have construction business logic in your code. Essentially, this is what we call the Factory Pattern (named so, because it emulates the real life behavior of factories) But, you see what happenned here? You are now dependent on the HondaDealership. It’s much better than before, but not perfect yet. You are still dependent on knowing that the car is a Honda, because you need to know whcih dealership to go to get the car.
You know what would be awesome? It would be awesome if, one day, you are walking down the road, and you think “Hey, I’m tired of walking. I would sure like to have a car now”. And a car appears in front of you! There is a fairy godmother listening to you, and whenever you wish for something, she just makes it appear. This is called dependency injection. You were dependent on something, and a magic fairy injected that thing into reality for you. Spring is that magic fairy. It creates objects for you and injects them wherever you need. By having a framework that uses configuration to decide what objects to construct and who needs what objects, you have completed separated concerns. The construction of objects is the concern of the DI framework. Objects don’t need to know how to construct other objects.
Now, there are times, in real life where separation of concerns do not make sense.
One example is that until the middle of the 20th century, most people would make their own clothes, and the only clothes sold were those made of hard to obtain materials. This was because the cost of transporting and selling the ready-made clothes, and the overhead of running a factory was too great. But, once manufacturing costs came down, and infrastructures improved, people started moving to buying clothes. The same thing applies to DI too. DI incurs cost in terms of the overhead of parsing the configuration. You need to decide if the flexibility justifies the overhead. For most application, it does because for most applications, large initialization time is not something that will break functionality. However, if you are building a low latency application that can quickly recover from failure, init time becomes a priority.
Let’s say you are inventing something new, and you start with a prototype. You won’t create a factory just to make prototypes, right? You will construct the objects yourself SImilarly, if you are prototyping, or just plain playing around with the API, you wouldn’t want to create all that configuration only to throw it away.
翻译成中文,就是以下的意思:
关于对象的创建有很多种方式,我们最开始学习的就是使用new
关键字配合着构造器来创建一个对象,但是不仅仅只有这种方式。
好比你去一个快餐店买一个三明治,它们给你的将是一个完整的三明治,而不是给你一些小麦种子、西红柿种子、莴苣根、一堆泥土、水…还有一头牛…然后告诉你“这是你的三明治。“这个例子蕴含着如下道理:作为消费者,你无需也并不会关系创建事物,而关系使用它们。大多数人明白,一个人可以使用一件东西,但却往往不适合创建那个东西(这被称为 separation of concerns)。在计算机中,对象的创建也有这番性质。
使用而不创建的好处可以见之于下面源于生活的例子:假设你开车去上班。你进入你的本田思域,把钥匙放在点火开关上,打开它,把齿轮放在驱动器上,松开刹车,踩下油门,然后离开。在上班的路上,你注意到汽车有点嘎嘎作响。你把车交给修理工,他说他得把车保养几天。他借给你一辆丰田花冠。你进入花冠,把钥匙放在点火开关上,把它打开,把齿轮放在前进档,松开刹车,踩下油门,然后离开。
等一下!这里发生了奇怪的事。你开的是一辆完全不同的车!但你没做什么不同的事。如果你是一名飞行员,你将获得驾驶一种飞机的执照,而移动到另一种飞机将需要数小时的训练和多年的实践!在这里你驾驶的是一辆完全不同的车,不需要任何训练和练习。这是什么魔法?
体现在计算机中,就是接口:汽车的点火、刹车、油门、换挡等操作是汽车行业的标准化接口。会开一辆车,你机会就相当于会开所有车。这就是接口所带来的”低耦合、高内聚“特性。
讲到这里,你可能会说:啊哈,早就知道基于接口编程了,可这个和这里的 JavaBean 主题有啥联系吗?下面还是以汽车为例子来展开:
代码语言:javascript复制Car myCar = new Honda.Civic() // construct the civicmyCar.drive() // use it
上述已经好多了,但是还是没能完成我们关于 separation of concerns 的目标,这是因为上述过程用文字语言来描述的话就是:你跑到 Honda 经销商那里,然后说你要一辆思域,然后经销商给了你一辆思域的所有零件,让你自己构造。即使思域本身是面向接口而编写的,但是你现在还在乎面向接口编程吗?或者说由于你已经在代码中将思域本身的特定业务逻辑放入代码中(这里主要指的是构造的业务逻辑),谁还在乎你说的思域本身实现于一个接口。
一个更好的方式是利用工厂设计模式,代码如下:
代码语言:javascript复制Car myCar = HondaDealership.buyCivic()myCar.drive()
这样好多了,因为经销商负责了实际生产汽车的所有细节(细节包括new
关键字的使用),代码中没有没有构造的业务逻辑。但是这样就完美了吗?你现在仍然依赖于HondaDealership
这一个经销商,虽然比以前好多了,但是显然不够完美。这是因为仍然需要你明确知道这辆车是本田的,因为你需要知道什么样的经销商去买这辆车。
但是想象一下,假如上帝会满足你对汽车的要求。就如同你在 GTA5 的世界中,在控制台中输入一串代码,那么天上就会掉下来一种再载具。比如:comet 作弊码对应着 双门跑车。当你想要什么什么东西,它就会出现。这种被称为依赖注入(dependency injection)。当你依赖于某件事物,上帝就替你完成了实现注入。Spring 就是那个上帝。它为您创建对象并在您需要的任何地方注入它们。通过使用配置来决定要构造什么对象以及谁需要什么对象的框架,您已经完成了分离的关注点。对象的构造是DI框架关注的问题。对象不需要知道如何构造其他对象。
事实上,一个特性的满足必然需要其他地方有开销,这也许是隐形的。依赖注入的实现总算是满足了 separation of concerns 的要求,但是依赖注入在解析配置方面的开销是一项隐性成本,这会影响一个系统的初始化效率。你需要决定灵活性是否合理。对于大多数应用程序来说,较大的初始化时间不会破坏功能。但是,如果您正在构建一个能够快速从故障中恢复的低延迟应用程序,那么初始化时间将成为一个优先级。
假如,你在写一个新类,仅仅是验证逻辑以及原型编写,你最好使用 new
关键字,工厂方法以及 Spring 带来的依赖注入都不是必要的。
Spring 中的依赖注入,就是基于 JavaBean 规范,于是在此体现了我们为何使用 JavaBean 的原因。
相关引用:
- https://www.quora.com/What-are-Java-beans-and-why-they-are-used;
- https://stackoverflow.com/questions/1727603/places-where-javabeans-are-used
- https://www.quora.com/Why-do-we-need-beans-and-or-spring-in-Java#