乐趣区

走进JavaWeb技术世界10从JavaBean讲到Spring

微信公众号【黄小斜】大厂程序员,互联网行业新知,终身学习践行者。关注后回复「Java」、「Python」、「C++」、「大数据」、「机器学习」、「算法」、「AI」、「Android」、「前端」、「iOS」、「考研」、「BAT」、「校招」、「笔试」、「面试」、「面经」、「计算机基础」、「LeetCode」等关键字可以获取对应的免费学习资料。

                     

Java 帝国之 Java bean (上)

转自:刘欣 码农翻身 2016-05-27

前言:最近看到到 spring 的 bean 配置,突然想到可能很多人不一定知道这个叫 bean 的东西的来龙去脉,所以就写个文章来讲一下。

另外,上次出了开源中国抄袭事件,为了防止转载以后我的公众号信息被故意删除,我在文章的内容中加上了一些 刘欣(微信公众号:码农翻身)这样的字样,可能会造成一些烦扰,请见谅。

我一手创立的 Java 帝国刚刚成立不久,便受到巨大的打击,我派出去占领桌面开发的部队几乎全军覆没。

情报说微软的 Visual Basic 和 Borland 的 Delphi 最近在宣传什么组件化开发,难道就是这东西把我们搞垮了?

刘欣(微信公众号:码农翻身)注:参见《Java:一个帝国的诞生》和《Basic:一个老兵的自述》

我赶紧买了一个 Visual Basic 过来研究,果然,这个家伙确实是方便,最让我惊叹的是:它有一个可视化编辑器!

我只需要把一个组件 (例如按钮) 拖拽到可一个表单上,  设置一下属性(颜色,字体),再添加一个事件(onClick), 最后在 onClick 中写点代码就搞定了!

不仅如此,我自己也可以把我的代码按规范包装成一个组件,发布出去让别人使用。

我看着手下给我买来的《程序员大本营》光盘,里边竟然包含了好几千个这样的组件,有数据库浏览组件,计时器组件,颜色选取组件,甚至还有收发邮件的组件 ……

天哪,这以后开发桌面程序岂不太简单了 !

怪不得我的 Java 被打得满地找牙!

刘欣(微信公众号:码农翻身)注:90 年代末的程序员和学生估计都知道《程序员大本营》,由 csdn 的创始人蒋涛制作。

我赶紧打电话给我的干将小码哥:小码啊,你赶紧看看这个 Visual Basic 和 Delphi , 给你 7 天时间,我们 Java 也得赶紧搞一套这样的东西出来。

小吗毫不含糊,三天就给我搞了一个东西出来:Java Bean API 规范。

我翻开一看,哇塞,长达 114 页,于是问他:“这是什么东西?我要的可视化编辑器呢 Visual Java 呢?”

刘欣(微信公众号:码农翻身)注:我下载浏览了 java bean 的规范,确实是 114 页

他说:“老大,我们是个开源的社区,得充分利用大家的力量,所以我没有去做像 VB 和 Delphi 那样的东西,相反,我定义了一套规范,只要大家按照这个规范做,谁都可以用 java 做出像 VB 那样的可视化开发工具出来。”

“那你说说这个 java bean 到底是什么规范?”我问。

“首先,一个 java bean 其实就是一个普通的 java 类,但我们对这个类有些要求:

1. 这个类需要是 public 的,然后需要有个无参数的构造函数

2. 这个类的属性应该是 private 的,通过 setXXX()和 getXXX()来访问

3. 这个类需要能支持“事件”,例如 addXXXXListener(XXXEvent e),  事件可以是 Click 事件,Keyboard 事件等等,当然咱们也支持自定义的事件。

4. 我们得提供一个所谓的自省 / 反射机制,这样能在运行时查看 java bean 的各种信息“

5. 这个类应该是可以序列化的,即可以把 bean 的状态保存的硬盘上,以便以后来恢复。

“这些要求看起来也没啥啊,对程序员来说,不就是个普通的 java 类吗?到底该怎么用?”

“我们幻想一下,假设我们的 Java bean 大行其道了,有个用户在用一个 Visual Java Builder  这样的可视化开发工具,当他用这个工具创建应用的时候,可以选择一个叫 JButton 的组件,加到一个表单上,此时 Visual Java Builder 就需要把这 JButton 的类通过反射给 new 出来,所以就需要一个无参数的构造函数了。”

“如果用户想去设置一下这个 JButton 的属性,Visual Java Builder 就需要先用自省 / 反射来获取这个 JButton 有哪些属性(通过 getter/setter),拿到以后就可以给用户显示一个 属性清单 了,例如背景色,字体 等等。用户看到后就可以设置背景色和字体了,此时 Visual Java Builder 在内部就需要调用这个 Bean 的 setBackgroundCorlor()/setFont() 等方法,这就是所谓的 setXXXX()方法。”

“如果用户想对这个 JButton 编程,Visual Java Builder 还是通过自省 / 反射来获取这个 JButton 有哪些事件,给用户展示一个 事件清单,例如 click , keyboardPressed 用户可以选取一个,然后就可以写程序对这个事件编程了。”

“可是那个序列化有什么用呢?”

“这是因为用户设计完了以后,可能关掉 Visual Java Builder 啊 , 如果不通过序列化把设计好的 JButton 保存起来,下次再打开 Visual Java Builder , 可就什么都没有了”

我想了想,小码哥设计的不错,仅仅用了一个简单的规范就满足了可视化编辑器的所有要求。

“ 那我们就发布这个规范吧,咱们自己先做一个可视化编辑器,给别人做个榜样,名称我都想好了,叫 NetBean 吧。”

刘欣(微信公众号:码农翻身)注:这是我杜撰的,实际上 NetBean 这个名称可能和 java bean 并没有实际关联。

果然不出我们所料,Java bean 发布以后,有力的带动了 Java 的 IDE 市场,开发 Delphi 的 Borland 公司 也来插了一脚,搞出了一个 JBuilder, 风靡一时。

IBM 搞了一个 Visual Age for Java ,  后来摇身一变,成了一个叫 Eclipse 的开放平台,超级受大家欢迎,它反过头来把我们的 Netbean 和 JBuilder 逼的快没有活路了。

虽然我们玩的很欢,但是程序员根本不买账,Java 在桌面开发市场还是没有起色,使用 Java bean 创建桌面程序的程序员少之又少,只有部分像金融、ERP 这样的领地还在坚持。

看来是无药可救了。

但是 Java bean 何去何从?丢弃掉太可惜了,我和小码哥商量了一下,我们觉得:既然我们 Java 在统治了服务器端的编程,还是在那里想想办法吧 ……

上一篇提到 Java bean 的规范虽然定义的不错,但却没有获得意料中的成功,尤其是 Java 帝国所期待的桌面开发组件化市场上。

我和小码哥多么期待 CSDN 也能出一期《程序员大本营》,里边包含成千上万的 java bean 组件啊。

不要幻想了,赶紧把 java bean 应用在服务器端才是正事。

JSP + Java Bean

小码哥建议先用在 jsp 上试试,可以用 java bean 来封装业务逻辑,保存数据到数据库,像这样:

(微信公众号 ” 码农翻身 ” 注:这其实叫做 JSP Model 1 )

其中 jsp 直接用来接受用户的请求,然后通过 java bean 来处理业务,具体的使用方法是:

这就能把 HTTP request 中的所有参数都设置到 user 这个 java bean 对应的属性上去。

如果想偷懒,还可以这样:

当然要保证 http request 中的参数名和 java bean 中的属性名是一样的。

这个叫做 JSP Model 1 的模型受到了很多 Java 程序员的欢迎 ,  因为他们的应用规模都很小,用 Model 1 使得开发很快速。

实际上,这种方式和微软帝国的 asp , 以及和开源的 php 几乎一样。

但很快就有人来找我抱怨了,说他们的项目中使用了 Model 1 导致整个系统的崩溃。

他说:“你知道吗?我们的系统中有好几千个 jsp,这些 jsp 互相调用(通过 GET/POST), 到了最后调用关系无人能搞懂。”

其实我们已经预料到了,小码哥对此有个形象的比喻:意大利面条

这几千个 JSP 就像这碗面条一样,搅在一起,根本理不清楚。

为了解决这个问题,小码哥又推出了:JSP Model 2 ,    这是个模型真正的体现了 Model-View-Controller 的思想:

Servlet 充当 Controller ,  jsp 充当 View 

Java bean 当然就是 Model 了!

业务逻辑,页面显示,和处理过程做了很好的分离。

基于这个模型的扩展和改进,很多 Web 开发框架开始如雨后春笋一样出现,其中最著名的就是 Struts,SpringMVC 了。

Java Web 开发迅速的繁荣了。

我们再一次体会到了开放的好处!

Enterprise Java bean

但是好景不长,自从 Java 帝国统治了所谓的“企业级应用”开发领地,各种各样的游行和抗议层出不穷:

“我们要分布式”

“我们要安全”

“我们要事务”
“我们要高可用性”

“……”

帝国分析了一下,其实这些程序员的诉求可以归结为:

“我们只想关注我们的业务逻辑,我们不想,也不应该由我们来处理‘低级’的事务,多线程,连接池,以及其他各种各种的‘低级’API,此外 Java 帝国一定得提供集群功能,这样我们的一台机器死机以后,整个系统还能运转。”

我们不能坐着不管,企业级应用是我们的命根子。

小码哥彻夜工作,最终拿出了一个叫做 J2EE 的东西,像 Java bean 一样,这还是一个规范,但是比 Java bean 复杂的多,其中有:

JDBC:  Java 数据库连接,没有数据库的支持怎么能叫企业级应用?

JNDI :  Java 命名和目录接口,通过一个名称就可以定位到一个数据源,连 jdbc 连接都不用了

RMI:远程过程调用,让一个机器上的 java 对象可以调用另外一个机器上的 java 对象,你们不是要分布式吗?

JMS :   Java 消息服务,可以使用消息队列了,这不是企业级应用非常需要的吗?

JTA:Java 事务管理,支持分布式事务,能在访问、更新多个数据库的时候,仍然保证事务,还是分布式。

Java mail : 收发邮件也是必不可少的啊。

刘欣(微信公众号号:码农翻身)注:J2EE 后来改成了 Java EE。

当然还有最最最重要的升级,小码哥把 java bean 变成了 Enterprise Java bean , 简称 EJB

小码哥宣称:

使用了 EJB,你就可以把精力只放在业务上了,那些烦人的事务管理,安全管理,线程 统统交给容器(应用服务器)来处理吧。

我们还提供了额外的福利,只要你的应用服务器是由多个机器组成的集群,EJB 就可以无缝的运行在这个集群上,你完全不用考虑一个机器死掉了应用该怎么办。我们都帮你搞定了。

使用 Session Bean,可以轻松的处理你的业务。

使用实体 Bean (Entity bean) , 你和数据库打交道会变得极为轻松,甚至 sql 都不用写了。

使用消息驱动 Bean(Message Driven bean) , 你可以轻松的和一个消息队列连接,处理消息。

听起来很美好是不是?

企业级开发领地的程序员们欢呼雀跃,坐上了 J2EE 这条船,似乎一下子高贵起来,开始鄙视微软的 ASP, 开源的 PHP, Python 等“不入流”的语言了。

Weblogic , Websphere 等符合 J2EE 规范的应用服务器趁势而上,摇旗呐喊,仿佛一个新的时代要来临了,当然他们在背后一直闷声发大财。

Sring

有句古话是对的,捧的越高,跌的越惨。

很快,大部分的程序员就发现,美好的前景并没有实现,EJB 中用起来极为繁琐和笨重,性能也不好,为了获得所谓的分布式,反而背上了沉重的枷锁。

实体 Bean 很快没人用了,就连简单的无状态 Session bean 也被大家所诟病,其中一条罪状就是“代码的侵入性”。

也是,小码哥定义 EJB 的时候没考虑那么多,程序员在定义一个 Session bean 的时候,需要写一大堆和业务完全没有关系的类。

还需要被迫实现一些根本不应该实现的接口及其方法:

为了哪怕一点点业务逻辑,我们都得写这么多无用的代码!程序员们出离愤怒了!

他们发起了一场叫做 POJO (Plain Old Java Object)的运动,高唱这 POJO 之歌,要求我们整改。

他们希望这个样子:

public class HelloworldBean{

    public String hello(){

        return “hello world”

    }

}

与此同时,他们还过分的要求保留事务了,安全了这些必备的东西。

程序员确实不好伺候,但是我们已经被 Weblogic, Websphere 这些大佬们“绑架”,想改动谈何容易!

2002 年,小码哥看到了 Rod Johnson 写的一本书《Expert one on one J2EE development withoutEJB》,赶紧跑来找我:

“老大,坏了坏了,你快看看这本书吧,这个叫 Rod 的家伙写的这本书直击我们的命门,这厮要搞 without EJB”

(微信公众号 ” 码农翻身 ” 注:虽然这本书翻译的很差,但由于是 spring 的开山之作,还是值得读一下,最好中英文对照)

岂止是 without EJB,  他还“偷偷的”推出了一个叫什么 Spring 的框架,已经迅速的流行开了。

Spring 框架顺应了 POJO 的潮流,提供了一个 spring 的容器来管理这些 POJO, 好玩的是也叫做 bean。

看来我们的 java bean 走了一圈又回到了原点。

对于一个 Bean 来说,如果你依赖别的 Bean , 只需要声明即可,spring 容器负责把依赖的 bean 给“注入进去“,起初大家称之为控制反转(IoC)

后来 Martin flower 给这种方式起来个更好的名字,叫“依赖注入”。

如果一个 Bean 需要一些像事务,日志,安全这样的通用的服务,也是只需要声明即可,spring 容器在运行时能够动态的“织入”这些服务,这叫 AOP。

后来我和小码哥商量,我们 EJB 也学习 Spring , 简化开发和配置,但是为时已晚,Spring 已经成为事实上的标准了!程序员已经被 spring 拉走了!

不过令我们欣慰的是,spring 和 spring mvc 极大的增加了我们对 web 开发领地的统治力, java 帝国更加强盛了。

(全文完)

Spring 的本质系列(1) — 依赖注入

转自:刘欣 码农翻身 2016-06-25

转载 码农翻身微信公众号 2016-06-25 刘欣《Spring 的本质系列(1) — 依赖注入》

1. 对象的创建

       面向对象的编程语言是用类 (Class) 来对现实世界进行抽象,在运行时这些类会生成对象 (Object)。
       当然,单独的一个或几个对象根本没办法完成复杂的业务,实际的系统是由千千万万个对象组成的,这些对象需要互相协作才能干活,例如对象 A 调用对象 B 的方法,那必然会提出一个问题:对象 A 怎么才能获得对象 B 的引用呢?
       最简单的办法无非是:当对象 A 需要使用对象 B 的时候,把它给 new 出来,这也是最常用的办法,java 不就是这么做的?例如:Apple a = new Apple();
       后来业务变复杂了,抽象出了一个水果(Fruit) 的类,创建对象会变成这个样子:
       Fruit f1 = new Apple();
       Fruit f2 = new Banana();
       Fruit f3 = ……
      很自然的,类似下面的代码就会出现:

       这样的代码如果散落在各处,维护起来将会痛苦不堪,例如你新加一个水果的类型 Orange, 那得找到系统中所有的这些创建 Fruit 的地方,进行修改,这绝对是一场噩梦。
 解决办法也很简单,前辈们早就总结好了:工厂模式 

       工厂模式,以及其他模式像抽象工厂,Builder 模式提供的都是创建对象的方法。这背后体现的都是“封装变化”的思想。这些模式只是一些最佳实践而已:起了一个名称、描述一下解决的问题、使用的范围和场景,码农们在项目中还得自己去编码实现他们。

2. 解除依赖

        我们再来看一个稍微复杂一点,更加贴近实际项目的例子:
        一个订单处理类,它会被定时调用:查询数据库中订单的处理情况,必要时给下订单的用户发信。

        看起来也没什么难度,需要注意的是很多类一起协作了,尤其是 OrderProcessor , 它依赖于 OrderService 和 EmailService 这两个服务,它获取依赖的方式就是通过单例方法。
        如果你想对这个 process 方法进行单元测试 – 这也是很多优秀的团队要求的 – 麻烦就来了。
        首先 OrderService 确实会从真正的数据库中取得 Order 信息,你需要确保数据库中有数据,数据库连接没问题,实际上如果数据库连接 Container(例如 Tomcat)管理的,你没有 Tomcat 很难建立数据库连接。
       其次这个 EmailService 真的会对外发邮件,你可不想对真正的用户发测试邮件,当然你可以修改数据库,把邮件地址改成假的,但那样很麻烦,并且 EmailService 会抛出一堆错误来,很不爽。
       所有的这些障碍,最终会导致脆弱的单元测试:速度慢,不可重复,需要手工干预,不能独立运行。
       想克服这些障碍,一个可行的办法就是不在方法中直接调用 OrderService 和 EmailService 的 getInstance()方法,而是把他们通过 setter 方法传进来。

       通过这种方式,你的单元测试就可以构造一个假的 OrderService 和假的 EmailService 了。
       例如 OrderService 的冒牌货可以是 MockOrderService , 它可以返回你想要的任何 Order 对象,而不是从数据库取。MockEmailService 也不会真的发邮件,而是把代码中试图发的邮件保存下来,测试程序可以检查是否正确。
       你的测试代码可能是这样的:

        当然,有经验的你马上就会意识到:需要把 OrderService 和 EmailService 变成 接口或者抽象类,这样才可以把 Mock 对象传进来。
        这其实也遵循了面向对象编程的另外一个要求:对接口编程,而不是对实现编程。

3. Spring 依赖注入

        啰啰嗦嗦说了这么多,快要和 Spring 扯上关系了。
       上面的代码其实就是实现了一个依赖的注入,把两个冒牌货注入到业务类中(通过 set 方法),这个注入的过程是在一个测试类中通过代码完成的。
       既然能把冒牌货注入进去,那毫无疑问,肯定也能把一个正经的类安插进去,因为 setter 方法接受的是接口,而不是具体类。

       用这种方式来处理对象之间的依赖,会强迫你对接口编程,好处显而易见。
       随着系统复杂度的增长,这样的代码会越来越多,最后也会变得难于维护。
       能不能把各个类之间的依赖关系统一维护呢?
       能不能把系统做的更加灵活一点,用声明的方式而不是用代码的方式来描述依赖关系呢?
       肯定可以,在 Java 世界里,如果想描述各种逻辑关系,XML 是不二之选:

        这个 xml 挺容易理解的,但是仅仅有它还不够,还缺一个解析器(假设叫做 XmlAppContext)来解析,处理这个文件,基本过程是:
         0. 解析 xml, 获取各种元素
         1. 通过 Java 反射把各个 bean 的实例创建起来:com.coderising.OrderProcessor   , OrderServiceImpl, EmailServiceImpl. 
         2. 还是通过 Java 反射调用 OrderProcessor 的两个方法:setOrderService(….)  和 setEmailService(…) 把 orderService , emailService 实例 注入进去。
        应用程序使用起来就简单了:
        XmlAppContext ctx = new XmlAppContext(“c:\bean.xml”);
        OrderProcessor op = (OrderProcessor) ctx.getBean(“order-processor”);
        op.process();
        其实 Spring 的处理方式和上面说的非常类似,当然 Spring 处理了更多的细节,例如不仅仅是 setter 方法注入,还可以构造函数注入,init 方法,destroy 方法等等,基本思想是一致的。

       既然对象的创建过程和装配过程都是 Spring 做的,那 Spring 在这个过程中就可以玩很多把戏了,比如对你的业务类做点字节码级别的增强,搞点 AOP 什么的,这都不在话下了。

4. IoC vs DI

“不要给我们打电话,我们会打给你的(don‘t call us, we‘ll call you)”这是著名的好莱坞原则。
        在好莱坞,把简历递交给演艺公司后就只有回家等待。由演艺公司对整个娱乐项目完全控制,演员只能被动式的接受公司的差使, 在需要的环节中,完成自己的演出。
        这和软件开发有一定的相似性,演员们就像一个个 Java Object, 最早的时候自己去创建自己所依赖的对象,有了演艺公司(Spring 容器)的介入,所有的依赖关系都是演艺公司搞定的,于是控制就翻转了 
        Inversion of Control, 简称 IoC。但是 IoC 这个词不能让人更加直观和清晰的理解背后所代表的含义,于是 Martin Flower 先生就创造了一个新词 : 依赖注入 (Dependency Injection,简称 DI),  是不是更加贴切一点?

Spring 本质系列(2)-AOP

原创:刘欣 码农翻身 2016-06-30

   据说有些词汇非常热门和神奇,如果你经常把它挂在嘴边,就能让自己功力大涨,可以轻松找到理想的高薪的工作,这些词就包括上一篇文章 (《Spring 本质系列(1) – 依赖注入》) 中聊过的 IoC 和 DI,也包括今天要聊的 AOP。
       AOP(Aspect Oriented Programming)就是面向切面的编程,为什么是面向切面,而不是面向对象呢?

1. 问题来源

      我们在做系统设计的时候,一个非常重要的工作就是把一个大系统做分解,按业务功能分解成一个个低耦合、高内聚的模块,就像这样:

       但是分解以后就会发现有些很有趣的东西,这些东西是通用的,或者是跨越多个模块的:
       日志: 对特定的操作输出日志来记录
        安全:在执行操作之前进行操作检查
        性能:要统计每个方法的执行时间
        事务:方法开始之前要开始事务,结束后要提交或者回滚事务
       等等 ….
       这些可以称为是非功能需求,但他们是多个业务模块都需要的,是跨越模块的,把他们放到什么地方呢?
       最简单的办法就是把这些通用模块的接口写好,让程序员在实现业务模块的时候去调用就可以了,码农嘛,辛苦一下也没什么。

      这样做看起来没问题,只是会产生类似这样的代码:

      这样的代码也实现了功能,但是看起来非常的不爽,那就是日志,性能,事务 相关的代码几乎要把真正的业务代码给淹没了。
      不仅仅这一个类需要这么干,其他类都得这么干,重复代码会非常的多。
      有经验的程序员还好,新手忘记写这样的非业务代码简直是必然的。

2. 设计模式:模板方法

      用设计模式在某些情况下可以部分解决上面的问题,例如著名的模板方法:

       在父类(BaseCommand)中已经把那些“乱七八糟“的非功能代码都写好了,只是留了一个口子(抽象方法 doBusiness())让子类去实现。
       子类变的清爽,只需要关注业务逻辑就可以了。
       调用也很简单,例如:
       BaseCommand  cmd = …  获得 PlaceOrderCommand 的实例 …
       cmd.execute();
       但是这样方式的巨大缺陷就是父类会定义一切:要执行哪些非功能代码,以什么顺序执行等等
      子类只能无条件接受,完全没有反抗余地。
       如果有个子类,根本不需要事务,但是它也没有办法把事务代码去掉。

3. 设计模式:装饰者

      如果利用装饰者模式,针对上面的问题,可以带来更大的灵活性:

       现在让这个 PlaceOrderCommand 能够打印日志,进行性能统计
       Command cmd = new LoggerDecorator(
              new PerformanceDecorator(
                  new PlaceOrderCommand()));
       cmd.execute();

       如果 PaymentCommand 只需要打印日志,装饰一次就可以了:
       Command cmd = new LoggerDecorator(
              new PaymentCommand());
       cmd.execute();
       可以使用任意数量装饰器,还可以以任意次序执行(严格意义上来说是不行的),是不是很灵活?

4. AOP

       如果仔细思考一下就会发现装饰者模式的不爽之处:
       (1)  一个处理日志 / 性能 / 事务 的类为什么要实现 业务接口(Command)呢?
       (2) 如果别的业务模块,没有实现 Command 接口,但是也想利用日志 / 性能 / 事务等功能,该怎么办呢?

       最好把日志 / 安全 / 事务这样的代码和业务代码完全隔离开来,因为他们的关注点和业务代码的关注点完全不同,他们之间应该是正交的,他们之间的关系应该是这样的:

       如果把这个业务功能看成一层层面包的话,这些日志 / 安全 / 事务 像不像一个个“切面”(Aspect)?
       如果我们能让这些“切面“能和业务独立,并且能够非常灵活的“织入”到业务方法中,那就实现了面向切面编程(AOP)!

5. 实现 AOP

       现在我们来实现 AOP 吧,首先我们得有一个所谓的“切面“类(Aspect),这应该是一个普通的 java 类, 不用实现什么“乱七八糟”的接口。以一个事务类为例:

       我们想达到的目的只这样的:对于 com.coderising 这个包中所有类的 execute 方法,在方法调用之前,需要执行 Transaction.beginTx()方法,在调用之后,需要执行 Transaction.commitTx()方法。
       暂时停下脚步分析一下。
“对于 com.coderising 这个包中所有类的 execute 方法”,用一个时髦的词来描述就是切入点(PointCut), 它可以是一个方法或一组方法(可以通过通配符来支持,你懂的)
”在方法调用之前 / 之后,需要执行 xxx“, 用另外一个时髦的词来描述就是通知(Advice)
       码农翻身认为,PointCut,Advice 这些词实在是不直观,其实 Spring 的作者们也是这么想的 :  These terms are not Spring-specific… unfortunately, AOP terminology is not particularly intuitive; however, it would be even more confusing if Spring used its own terminology.
       当然,想描述这些规则,xml 依然是不二之选:

       注意:现在 Transaction 这个类和业务类在源代码层次上没有一点关系,完全隔离了。隔离是一件好事情,但是马上给我们带来了大麻烦。
       Java 是一门静态的强类型语言,代码一旦写好,编译成 java class 以后,可以在运行时通过反射(Reflection)来查看类的信息,但是想对类进行修改非常困难。
       而 AOP 要求的恰恰就是在不改变业务类的源代码(其实大部分情况下你也拿不到)的情况下,修改业务类的方法, 进行功能的增强,就像上面给所有的业务类增加事务支持。
      为了突破这个限制,大家可以说是费尽心机,现在基本是有这么几种技术:
      (1) 在编译的时候,根据 AOP 的配置信息,悄悄的把日志,安全,事务等“切面”代码 和业务类编译到一起去。
      (2) 在运行期,业务类加载以后,通过 Java 动态代理技术为业务类生产一个代理类,把“切面”代码放到代理类中,Java 动态代理要求业务类需要实现接口才行。
      (3) 在运行期,业务类加载以后,动态的使用字节码构建一个业务类的子类,将“切面”逻辑加入到子类当中去, CGLIB 就是这么做的。
      Spring 采用的就是(1) +(2) 的方式,限于篇幅,这里不再展开各种技术了,不管使用哪一种方式,在运行时,真正干活的“业务类”其实已经不是原来单纯的业务类了,它们被 AOP 了!、

一位阿里 Java 工程师的技术小站。作者黄小斜,专注 Java 相关技术:SSM、SpringBoot、MySQL、分布式、中间件、集群、Linux、网络、多线程,偶尔讲点 Docker、ELK,同时也分享技术干货和学习经验,致力于 Java 全栈开发!(关注公众号后回复”Java“即可领取 Java 基础、进阶、项目和架构师等免费学习资料,更有数据库、分布式、微服务等热门技术学习视频,内容丰富,兼顾原理和实践,另外也将赠送作者原创的 Java 学习指南、Java 程序员面试指南等干货资源)

退出移动版