OOP(Object Oriented Programming)面向对象编程解决了纵向上的层次分割,例如MVC模式将展示层、持久化层、逻辑处理层一一分开了,使得开发效率得到了较大提高,但是这只是纵向上的分割,如果从水平方向上来看,即如果一个项目中的很多类都需要实现某一个方法(例如:在网购平台上,登录,下单,付款都需要对身份进行验证)如果要在这些类一一将这些都要执行的方法添加到其中这无疑将会增加代码量,这会使得程序显得很臃肿。基于以上的操作便诞生了我们今天的主角—-Spring-AOP。AOP即(Aspect Oriented Programming)面向切面编程。Spring-AOP就是实现一闪刚提出的问题。接下来我们就为大家揭开Spring-AOP的“神秘面纱”。
1 AOP简介
1.1 什么是AOP
AOP(Aspect Oriented Programming)面向切面编程,是对传统的OOP(ObjectOriented Programming)面向对象编程的补充。
1.2 AOP的作用
如果A,B,C三个方法都要在执行前做验证操作,执行后做日志打印操作。肿么办?
![图片描述][1]
1.3 AOP专业术语
切面(Aspect): A,B,C,方法执行前都要调用的验证逻辑和执行后都要调用的日志逻辑,这两个就是切面。
通知(Advice): 有五种通知,执行前,执行后,执行成功后,执行抛出异常后,环绕通知。就是切面执行的方法。
目标(Target): 被通知的对象,这里就是A,B,C三个方法。
连接点(Joinpoint):连接点是一个应用执行过程中能够插入一个切面的点。
切点(pointcut):每个类都拥有多个连接点,即连接点是程序类中客观存在的事务。AOP 通过切点定位到特定的连接点
打个比方:一天,三位侠客(被通知的对象Target)来我府上做客,被大门(切面Aspect)拦住,门前有五个保安(负责通知的Advice),因为其中一位侠客会降龙十八掌(满足被通知的一个条件Joinpoint),其中一位保安告知他:”你可以进去了”。另外两个侠客因为武艺超群(满足被通知的统一标准poincut)也都进去了。
实例讲解:
下面我们以一段实例来讲解基于XML配置文件和基于注解的方式来说明Spring-AOP的运行机制。
该程序的整体运行机制是:将入一个项目都想执行加、减、乘、除这四个方法,所以我们将这四个操作封装在一个类中并将其作为一个切面,从而提高代码的复用率。
基于XML的使用
//这个便是我们的切面,即许多类要执行的方法
package com.zhangguo.Spring052.aop01;
public class Math {//加 public int add(int n1,int n2){ int result=n1+n2; System.out.println(n1+"+"+n2+"="+result); return result; } //减 public int sub(int n1,int n2){ int result=n1-n2; System.out.println(n1+"-"+n2+"="+result); return result; } //乘 public int mut(int n1,int n2){ int result=n1*n2; System.out.println(n1+"X"+n2+"="+result); return result; } //除 public int div(int n1,int n2){ int result=n1/n2; System.out.println(n1+"/"+n2+"="+result); return result; }
}
//这个就是通知啦,好比是上面所打比方的那五个门卫,所有类要使用上面的切面首先要经过这个类的“审核”
package com.zhangguo.Spring052.aop01;
import org.aspectj.lang.JoinPoint;
public class Advices {
public void before(JoinPoint jp){
System.out.println("----------前置通知----------");
System.out.println(jp.getSignature().getName());
}
public void after(JoinPoint jp){
System.out.println("----------最终通知----------");
}
}
//下面我们列出本实例的核心,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"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<!-- 被代理对象 -->
<!-- 此为在横向切面被统一抽象出来的方法 -->
<bean id="math" class="com.zhangguo.Spring052.aop01.Math"></bean>
<!-- 通知 -->
<bean id="advices" class="com.zhangguo.Spring052.aop01.Advices"></bean>
<!-- aop配置 -->
<aop:config proxy-target-class="true">
<!--切面 -->
<aop:aspect ref="advices">
<!-- 切点 -->
<aop:pointcut expression=”execution( com.zhangguo.Spring052.aop01.Math.(..))”id=”pointcut1″/>
<!--连接通知方法与切点 -->
//当实现了通知中的before方法时执行切面中方法
<aop:before method="before" pointcut-ref="pointcut1"/>
//当实现了通知中的after方法时执行切面中方法
<aop:after method="after" pointcut-ref="pointcut1"/>
</aop:aspect>
</aop:config>
</beans>
//此为测试类
package com.zhangguo.Spring052.aop01;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("aop01.xml");
Math math = ctx.getBean("math", Math.class);
int n1 = 100, n2 = 5;
math.add(n1, n2);
math.sub(n1, n2);
math.mut(n1, n2);
math.div(n1, n2);
}
}
基于注解的使用
package com.zhangguo.Spring052.aop02;
import org.springframework.stereotype.Service;
//此处使用@Service说明该类为切面
@Service("math")
public class Math{
//加
public int add(int n1,int n2){
int result=n1+n2;
System.out.println(n1+"+"+n2+"="+result);
return result;
}
//减
public int sub(int n1,int n2){
int result=n1-n2;
System.out.println(n1+"-"+n2+"="+result);
return result;
}
//乘
public int mut(int n1,int n2){
int result=n1*n2;
System.out.println(n1+"X"+n2+"="+result);
return result;
}
//除
public int div(int n1,int n2){
int result=n1/n2;
System.out.println(n1+"/"+n2+"="+result);
return result;
}
}
package com.zhangguo.Spring052.aop02;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class Advices {
//此注解可以将Advices设置为通知类,即当使用到before方法时,便执行execution方括号中的号码
@Before("execution(* com.zhangguo.Spring052.aop02.Math.*(..))")
public void before(JoinPoint jp){
System.out.println("----------前置通知----------");
System.out.println(jp.getSignature().getName());
}
@After("execution(* com.zhangguo.Spring052.aop02.Math.*(..))")
public void after(JoinPoint jp){
System.out.println("----------最终通知----------");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<context:component-scan base-package="com.zhangguo.Spring052.aop02">
</context:component-scan>
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
</beans>
//测试类
package com.zhangguo.Spring052.aop02;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("aop02.xml");
Math math = ctx.getBean("math", Math.class);
int n1 = 100, n2 = 5;
math.add(n1, n2);
math.sub(n1, n2);
math.mut(n1, n2);
math.div(n1, n2);
}
}
最后附上项目源码地址:
链接:http://pan.baidu.com/s/1hrQIdvu 密码:eknb