切面(aspects)应用

DI能够让你的软件组件间保持松耦合,而面向切面编程(AOP)能够让你捕获到在整个应用中可重用的组件功能。在软件系统中,AOP通常被定义为提升关注点分离的一个技术。系统由很多的组件组成,每个组件负责一部分的功能。但是这些组件往往除了核心功能外,还有些额外的责任。比如像日志,事务管理和安全这些系统服务会被引进到组件中。这些服务通常被称为横切关注点(cross-cutting-concerns),因为它们常常贯穿于多个组件中。

在多个组件中传播这些概念,会有两个复杂层面内容将被引进到你的代码中

实现系统级概念代码将会在多个组件中重复出现,这意味着如果你需要改变这些概念的话,你必须修改多个组件的内容。即使你将这些概念抽象到一个独立的方法中来使它成为一个单一的方法,但是方法的调用还是会出现在多个地方。

你的组件现在充斥着和核心代码无关的功能。

下图展示的它的复杂度。左边的业务对象和右边的系统服务紧密的关联在一起。

AOP能够使这些服务成为模块并且很方便的使用它们(声明方式),来达到在组件中消除这些影响。这样让组件更有粘合性,使它们只关注于自己具体的业务,完全忽略系统服务。简而言之,切面让POJOS保持简单。

你可以将切面设想为覆盖了很多组件的毛毯,如下图所示。一个应用由多个实现业务功能的模块组成。使用AOP,你可以使用这些功能来覆盖你的核心应用。这些层可以通过声明的方式来贯穿到你的应用中,而你核心代码根本不用知道它们的存在。这是一个强大的概念,因为它将应用核心业务和系统服务独立开来。

下面我们来看个具体的例子,现在是个骑士的故事,故事如何流传下来呢,当然是通过歌手的歌声来传递

public classMinstrel {privatePrintStream stream;publicMinstrel(PrintStream stream) {this.stream =stream;

}public voidsingBeforeQuest() {

stream.println("Fa la la, the knight is so brave!");

}public voidsingAfterQuest() {

stream.println("Tee hee hee, the brave knight " +

"did embark on a quest!");

}

}

如你所见,Minstrel是个简单的类并有两个方法。singBeforeQuest()方法在骑士开始探索的之前被调用,而singAfterQuest()方法应当在骑士探索结束后调用。在这两个用例中,Minstrel通过在构造器中注入的PrintSteam来歌颂骑士的事迹。

现在你只需要注入BraveKnight就能使用,让我们微调下BraveKnight来使用Minstrel。下面展示如何将他们合并在一起

public class BraveKnight implementsKnight {privateQuest quest;privateMinstrel minstrel;publicBraveKnight(Quest quest, Minstrel minstrel) {this.quest =quest;this.minstrel =minstrel;

}public void embarkOnQuest() throwsQuestException {

minstrel.singBeforeQuest();

quest.embark();

minstrel.singAfterQuest();

}

}

它应该能够运行,你要做的就是回到你的配置文件中,然后声明一个Minstrel bean并且注入到BraveKnight的构造器中。但是等等...是否需要在knight中来管理minstrel?minstrel类不是只要关注于自己的功能?因为knight需要知道minstrel存在。这将迫使你将Minstrel注入到BraveKnight中,这样不仅使BraveKnight的代码变得复杂,而且用户可能需要个没有minstrel的knight。如果Minstrel为空?是否需要进行空值逻辑检测?

但是如果你使用AOP,minstrel和knight只需要关心各自的事情。要将Minstrel转化成一个切面,你只需要在Spring配置文件中声明它。下面在原来的knights.xml基础上进行修改。

<?xml version="1.0" encoding="UTF-8"?>>

http://www.springframework.org/schema/aop/spring-aop-3.2.xsd

http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans.xsd">

上面使用spring aop命名空间配置来声明Minstrel作为一个切面。首先你声明Minstrel作为一个bean。然后在元素中引用它。接着进一步对切面定义,你使用来声明在执行embarkOnQuest()执行前调用singBeforeQuest方法,这个叫做前置通知。使用来声明在执行embarkOnQuest()执行后调用singAfterQuest方法,这个叫做后置通知。在这两个用例中,pointcut-ref属性都引用了叫embark的切点。这个切点在前面的元素中定义,并且它有个叫做expression属性,该属性用来选择那些地方需要使用通知。这个表达式语法是AspectJ的切点表达式语言。

现在先不要关心AspectJ表达式细节,以后的章节会详细谈论。现在你应该有点感知切面在spring中是如何使用的,是的只要一点点的XML配置,你就能将minstrel转成spring的切面。现在你应该从这个例子中能获取到两点认识。

首先,Minstrel仍然是一个POJO ---- 没有任何指示能表明它是一个切面。但实际上它却是spring context中的一个切面

其次,更重要的是,Minstrel可以被用到BraveKnight中,而不用BraveKnight明确的去调用。事实上,BraveKnight完全不关心Minstrel是否存在

这里需要指出的是,在使用Spring魔法将Minstrel转换成一个切面前,需要将它声明为Spring的bean。所以只要注入依赖就能就其他的spring bean也变成一个切面。当然这个例子只是简单的spring aop应用,后面我们将介绍它在声明式事务和安全方面中的应用。接下来我们再来看一种spring使java开发变得更简单的方式。

使用模板消除样板代码

样板代码指的是你经常一次次编写相似的代码来完成普通、简单的任务。有很多Java APIs存在着样板代码。一个常见的样板代码就是使用JDBC来查询数据库操作。如果你有用过JDBC来操作的话,你可能会经常写下类似下面的一段代码

public Employee getEmployeeById(longid) {

Connection conn= null;

PreparedStatement stmt= null;

ResultSet rs= null;try{

conn=dataSource.getConnection();

stmt=conn.prepareStatement("select id, firstname, lastname, salary from " +

"employee where id=?");

stmt.setLong(1, id);

rs=stmt.executeQuery();

Employee employee= null;if(rs.next()) {

employee= newEmployee();

employee.setId(rs.getLong("id"));

employee.setFirstName(rs.getString("firstname"));

employee.setLastName(rs.getString("lastname"));

employee.setSalary(rs.getBigDecimal("salary"));

}returnemployee;

}catch(SQLException e) {

}finally{if(rs != null) {try{

rs.close();

}catch(SQLException e) {}

}if(stmt != null) {try{

stmt.close();

}catch(SQLException e) {}

}if(conn != null) {try{

conn.close();

}catch(SQLException e) {}

}

}return null;

}

如你所见,你只是想查询id为某个值的employee数据,而这里却要写一堆的JDBC操作。首先你要创建个connection,然后创建statement,接着获取查询结果。而且,你还要捕获SQLException异常。最终当所有操作完成后,你必须清除乱七八糟的东西,关闭connection,statement和result set。很显然,上面的代码你可能有经历过。查询employee只要一条语句,但是却要进行大量的JDBC样板操作。

JDBC不是唯一的样板代码,很多活跃的代码也存在类似的问题,比如JMS,JNDI和REST客服端。Spring通过将样板代码封装到模板中来消除这些重复代码。Spring的JDBCTemplate使不用传统的JDBC来操作数据库成为可能。

举个例子,使用Spring的SimpleJdbcTemplate(利用java 5特性来实现的一个JDBCTemplate),getEmployeeById()方法可以被重写为,如何获取employee数据而不用在考虑JDBC API操作。下面是更新后的代码

public Employee getEmployeeById(longid) {returnjdbcTemplate.queryForObject("select id, firstname, lastname, salary " +

"from employee where id=?",new RowMapper() {publicEmployee mapRow(ResultSet rs,int rowNum) throwsSQLException {

Employee employee= newEmployee();

employee.setId(rs.getLong("id"));

employee.setFirstName(rs.getString("firstname"));

employee.setLastName(rs.getString("lastname"));

employee.setSalary(rs.getBigDecimal("salary"));returnemployee;}

},id);

}

如你所见,这个版本的getEmployeeById()更加的简单,它只关注于如何进行数据库查询employee操作。模板的queryForObject()只需要一个SQL query语句,以及如何将数据封装到domain object的RowMapper,你看不到任何的JDBC样板代码,所有的样板代码都会在模板中进行处理。

这里我们使用spring DI、aspect、template来使复杂的java开发变得简单。上面我们举例说明如何配置bean和aspect。下面我们就来解释下这些文件如何加载以及将他们加载到什么地方去。

java会变得更简单吗_spring 第一篇(1-1):让java开发变得更简单(下)相关推荐

  1. 第一篇:微信公众平台开发实战Java版之了解微信公众平台基础知识以及资料准备...

    相信很多人或多或少听说了微信公众平台的火热.但是开发还是有一点门槛,鉴于挺多朋友问我怎么开发,问多了,自己平时也进行以下总结. 所以下面给大家分享一下我的经验: 第一部分   介绍微信公众号的一些简单 ...

  2. JAVA之旅(三十五)——完结篇,终于把JAVA写完了,真感概呐!

    JAVA之旅(三十五)--完结篇,终于把JAVA写完了,真感概呐! 这篇博文只是用来水经验的,写这个系列是因为我自己的java本身也不是特别好,所以重温了一下,但是手比较痒于是就写出了这三十多篇博客了 ...

  3. LoadRunner的简单使用《第一篇》

    LoadRunner的简单使用<第一篇> LoadRunner是一个用压力测试的软件.这东西比较难上手,光安装就非常麻烦.好不容易一步步跟着安装说明安装好之后,还是用不了. 记录一个问题如 ...

  4. Java图像处理最快技术:ImageJ 学习第一篇

    ImageJ是世界上最快的纯Java的图像处理程序.它可以过滤一个2048x2048的图像在0.1秒内(*).这是每秒40万像素!ImageJ的扩展通过使用内置的文本编辑器和Java编译器的Image ...

  5. 第一篇博客,java学生管理系统(挑战全网最全)

    java学生信息管理系统,(课设必备),附有源码和简版链接 博主虽然技术不高,但是系统写的真的是没话说,留着开学java课设用了. 直接转载链接了,查看系统入口 https://blog.csdn.n ...

  6. 第一篇 博客:java从数据库读取数据,并写入到excel表格中

    今天,组长分配了查询数据库记录,并把这些记录写入到excel表格中,以前没有尝试过,借鉴了一些别人的代码,最终实现了功能,写一篇博客,总结一下这个过程. 1.准备需要用到的jar包 1.jxl.jar ...

  7. 【pyg】第一篇总结(基于karate的3层GCN+简单可视化,额外补充了cora)

    目录 Karate空手道俱乐部 数据集dataset统计查看 单张图graph数据data统计查看 可视化数据单张图数据

  8. 第三篇 :微信公众平台开发实战Java版之请求消息,响应消息以及事件消息类的封装...

    微信服务器和第三方服务器之间究竟是通过什么方式进行对话的? 下面,我们先看下图: 其实我们可以简单的理解: (1)首先,用户向微信服务器发送消息: (2)微信服务器接收到用户的消息处理之后,通过开发者 ...

  9. 基于JAVA实现的WEB端UI自动化 - WebDriver高级篇 - 关联

    文章目录 关联 (公共变量传递一些值) 基于JAVA实现的WEB端UI自动化 -自动化测试简单介绍 基于JAVA实现的WEB端UI自动化 - WebDriver基础篇 - 实现简单的浏览器操作 基于J ...

最新文章

  1. Load balancer does not have available server for client
  2. android----HttpClient的get,post和图片上传服务器
  3. unity3d中获得物体的size
  4. 散列查找 散列表(哈希表)
  5. 【学习笔记】DAG / 一般有向图的支配树 / 灭绝树
  6. 干货集锦:200+生信范文、30+款软件、12类图片素材PPT,今年的SCI稳了!(附下载)...
  7. 数据仓库之电商数仓-- 3.2、电商数据仓库系统(DWS层)
  8. Windows2000系统下Apache2和PHP4安装终级宝典
  9. whistle抓包工具学习
  10. 塞班系统微信连接不上服务器,充满情怀的塞班系统:手机QQ、微信将无法登陆使用...
  11. Vue3+Vite快速搭建vue项目
  12. cve_2019_0708_bluekeep复现采坑
  13. [数据采集笔记04]——网页解析——lxml、bs4、正则
  14. NET 2.0(C#)调用ffmpeg处理视频的方法(转载)
  15. RabbitMQ-Plugin configuration unchanged
  16. Unity3D代码动态修改材质球的颜色
  17. 区块链与merkle tree
  18. 阿里云服务器的基本配置
  19. Javascript(六十三)网络协议
  20. input使用自动输入autofill的时候,修改背景颜色

热门文章

  1. SpringBoot重启后,第一次请求接口请求慢的解决方案
  2. Gitee的第一次使用(图文)
  3. BIM模型文件下载——三层江湖别墅
  4. Studing Day1 - python基础1
  5. vxWorks启动时间
  6. ffmpeg代码实现往视频文件里面叠加文字
  7. 新浪微博API[赞]接口和[取消赞]接口
  8. 微博运营工具及数据分析实战全集百度云
  9. 半监督异常检测(Anomaly Detection)的研究线
  10. sql 当为空值时置0_SQL查询值为空时默认输出0的方法