[一知半解,就是给自己挖坑]
本文我们来介绍一下Spring中另一个非常重要的概念:AOP。与前面不同的是,我们讲先来介绍AOP的概念,再用实例说明。
----------------------------------------------------------------------------------------------------------------------------------------------------------
1.什么是AOP:【摘自百科】
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
2.主要功能:
日志记录,性能统计,安全控制,事务处理,异常处理等
3.AOP的业务逻辑运行图:在示例中,实际运行的流程被划分成为不同的执行模块,各个模块之间界限分明。没有出现业务逻辑交织在一起的情况。并且各个模块之间原有的设计方式并没有改变,因此,也不会干扰到原有程序的执行过程。
4.换成白话来理解吧:
举个栗子:假设存在下面的业务代码:
@Override
public String registerUser(MgrUser user) {
<span style="white-space:pre"> </span>//获取用户信息
//存储用户信息
//返回存储结果
}
在这个流程中,如果我们需要记录这个环节的日志,那么日志处理的代码将会被加入到上面的方法中,可能变成下面的样子:
@Override
public void registerUser(MgrUser user) {
//logger.info("开始:保存用户信息方法")
//获取用户信息
//存储用户信息
//返回存储结果 //logger.info("结束:保存用户信息方法")
}
上面的例子中,日志处理的代码就已经侵入的业务流程的处理代码,如果换成其他的功能,如用户身份验证,权限验证,频率统计等,各种各样的代码都会交织在一起。这样的代码无论是从维护的角度,程序架构的角度都是不合适的。因此,这里我们就需要AOP的概念来帮助我们将各个功能的代码拆分开来。各个模块的代码独立,并且能够按照一定的顺序执行。
“面向切面”的概念,可以类比java中“面向对象”,类比数学上的两个形状不同的图形“相切”来理解。即我们设计的两段代码是职责单一的“对象”,业务功能上相互分离。但在执行顺序上,两者相邻,相互之间存在着一个“切面”。Spring将系统中的应用分为了两个大的部分:核心业务逻辑和横向的通用逻辑。这些通用的逻辑就是我们上文中提到的:持久化管理,事务管理,安全管理,日志管理等。
-------------------------------------------------------------------------------------------------------------------------------------
举个实例来说明吧!
准备工作:
a.操作系统:win7 x64
b.开发工具:eclipse mars j2ee版本,maven3.3.2,Spring 4,junit4.12
c.复制Spring08工程,重命名为Spring09工程。修改工程结构图如下:
-------------------------------------------------------------------------------------------------------------------------------------
1.创建ResigsterService.java文件,具体内容如下:
package com.java.ingo.service.itf;
import com.java.ingo.entity.Customer;
/**
*@author 作者 E-mail:ingo
*@version 创建时间:2016年3月3日上午17:54:19
*类说明
*/
public interface ResigsterService {
public void resigsterCustomer(Customer c);
}
2.创建RegisterServiceImpl.java,具体内容如下:
package com.java.ingo.service.impl;
import com.java.ingo.entity.Customer;
import com.java.ingo.service.itf.ResigsterService;
/**
*@author 作者 E-mail:ingo
*@version 创建时间:2016年3月3日上午17:55:29
*类说明
*/
public class RegisterServiceImpl implements ResigsterService{
public void resigsterCustomer(Customer c) {
System.out.println("调用dao层,存数客户"+c.getName());
}
}
3.修改beans.xml文件,具体内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="Register" class="com.java.ingo.service.impl.RegisterServiceImpl">
</bean>
</beans>
4.修改测试方法为如下内容:
@org.junit.Test
public void test1() {
System.out.println("Start Test1()");
ResigsterService resigster = (ResigsterService)ac.getBean("Register")
resigster.resigsterCustomer(new Customer("Tom","male",22));
}
5. 测试方法: 在test1方法上,右键run as--->junit test。观察控制台输出结果即可。
---------------------------------------------------------------------------------------
上面我们演示了我们正常情况下的基本示例。接下来看一下当需要日志时的场景
---------------------------------------------------------------------------------------
6.修改RegisterServiceImpl.java,具体内容如下:
public void resigsterCustomer(Customer c) {
System.out.println("-----------调用Log,保存日志------------");
System.out.println("开始注册用户:"+c.getName());
System.out.println("-----------调用Log,保存日志------------");
System.out.println("调用dao层,存数客户"+c.getName());
System.out.println("-----------调用Log,保存日志------------");
System.out.println("结束注册用户:"+c.getName());
System.out.println("-----------调用Log,保存日志------------");
}
7. 测试方法: 在test1方法上,右键run as--->junit test。观察控制台输出结果即可。-
-----------------------------------------------------------------------------------------------------------------------------------------------
上面的示例:日志的代码已经侵入到业务逻辑当中,代码的耦合度非常高。这是一种非常不合理的做法!
看完上面的简单例子,我们再来介绍更多的AOP概念吧。
-----------------------------------------------------------------------------------------------------------------------------------------------
Spring中比较重要的几个概念:
a.切面(aspect):用来切插业务方法的类。即如我们上面中将日志代码剥离出来成为一个单独的类,在需要使用的时候,自动调用这个类。
b.连接点(joinpoint):是切面类和业务类的连接点,其实就是封装了业务方法的一些基本属性,作为通知的参数来解析。
c.通知(advice):在切面类中,声明对业务方法做额外处理的方法。如,通知切面类的运行结果等。
d.切入点(pointcut):业务类中指定的方法,作为切面切入的点。其实就是指定某个方法作为切面切的地方。如上文中的resigsterCustomer方法。
------------------------------------------------------------------------------------------------------------------------------------------------
通知的分类:
a.前置通知(before advice):在切入点之前执行。
b.后置通知(after returning advice):在切入点执行完成后,执行通知。
c.环绕通知(around advice):包围切入点,调用方法前后完成自定义行为。
d.异常通知(after throwing advice):在切入点抛出异常后,执行通知。
-----------------------------------------------------------------------------------------------------------------------------------------------
至此,白话Spring(基础篇)---AOP(理论篇)结束
备注:
在下一篇中,我们会通过实例来演示Spring中AOP的使用,敬请期待!
参考资料:
Spring官网,百度百科