AOP(Aspect Oriented Programming),也就是面向切面编程,作为面向对象编程的一种补充,AOP已经成为一种比较成熟的编程方式。可以这样理解:OOP是从静态角度考虑程序结构,而AOP是从动态角度考虑程序运行过程。
>为什么要用?
公共业务?复制粘贴?NO
抽象出方法?依赖耦合!NO
AOP专门用于处理系统中分布于各个模块中的交叉关注点的问题,在Java EE应用中,常常通过AOP来处理一些具有横切性质的系统级服务,如事务管理、安全检查、缓存、对象池管理等,AOP已经成为一种非常常用的解决方案。
>AOP实现可分为两类:
一般来说,静态AOP实现具有较好的性能,但需要使用特殊的编译器。动态AOP实现是纯Java实现,因此无须特殊的编译器,但是通常性能较差。
>AOP基本概念
AOP从程序运行角度考虑程序的流程,提取业务处理过程的切面。AOP面向的是程序运行中各个步骤,希望以更好的方式来组合业务处理的各个步骤。
AOP框架并不与特定的代码耦合,AOP框架能处理程序执行中特定的切入点pointcut,而不与某个具体类耦合。AOP框架具有如下两个特征。
下面是关于面向切面编程的一些术语。
pointcut xxxPointcut():execution(void H*.say*)
每个方法被调用都只是连接点,但如果方法属于H开头的类,且方法以say开头,则该方法的执行将变成切入点。也可以认为符合条件的连接点即为切入点。如何用表达式来定义切入点是AOP的核心,Spring默认使用AspectJ切入点的语法。
由前面的介绍知道,AOP代理就是由AOP框架动态生成一个对象,该对象可作为目标对象使用。AOP代理包含了目标对象的全部方法,但AOP代理中的方法与目标对象的方法存在差异——AOP方法在特定的切入点加入了增强处理,并回调了目标对象的方法。
AOP代理所包含的方法与目标对象的方法示意图如下所示:
>基于xml的AOP处理
(首先要引入AOP的命名空间)
在Spring配置文件中,所有的切面,切入点和增强处理都必须定义在aop:config元素内部。beans元素下可以包含多个aop:config元素,一个aop:config元素可以包含pointcut、advisor和aspect元素,并且这三个元素必须按照彼此顺序来定义。关于aop:config元素所包含的子元素如下图所示:
在上图中已经非常清楚的绘制出aop:config元素下能包含三个有序的子元素:pointcut、advisor和aspect,其中aspect下可以包含多个子元素,通过使用这些子元素就可以在XML文件中配置切面、切入点和增强处理了。
>hello AOP配置
Spring配置:
切面类:
package com.langsin.aop;
import org.aspectj.lang.ProceedingJoinPoint;
/**
* RepairAspect 切面类:增强处理类
*
*/
public class RepairAspect {
// 进行before增强处理的方法
public void beforeAspect() {
System.out.println("----目标方法执行之前,Before进行增强处理----");
}
// 进行after增强处理的方法
public void afterAspect() {
System.out.println("----目标方法执行之前,After进行增强处理----");
}
// 进行around增强处理的方法:除了before 和after ,环绕增强处理可以指定目标方法在哪个位置执行,hai可以让目标方法不执行
public Object aroundAspect(ProceedingJoinPoint point){
System.out.println("----环绕前,around进行增强处理----");
try {
return point.proceed(point.getArgs());
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("----环绕后,around进行增强处理----");
return null;
}
}
测试类:
@Test
public void testRoleDao() throws Exception{
//容器启动加载
String configLocations="SpringConfig.xml";
@SuppressWarnings("resource")
ApplicationContext context = new ClassPathXmlApplicationContext(configLocations);
//获取 形参(要获取bean的id ,获取bean的类型)
RoleDao dao = (RoleDao) context.getBean("dao", RoleDao.class);
String string = dao.queryRoleList(12);
System.out.println(string);
}
>基于注解的AOP处理(基于注解的“零配置”方式)
AspectJ允许使用注解定义切面、切入点和增强处理,而Spring框架则可以识别这些注解并根据注解来生成AOP代理。Spring只是使用了和AspectJ 1.5一样的注解,但并没有使用AspectJ的编译器或者织入器,底层依然使用的是Spring AOP,依然是在运行时动态生成AOP代理,并不依赖AspectJ的编译器或者织入器。
为了启用Spring对@AspectJ切面配置的支持,并保证Spring容器中的目标Bean被一个或多个切面自动增强,必须在Spring配置文件中配置如下片段:
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
如果希望完全启动Spring的“零配置”功能,则需要按照Spring的“零配置”方式进行配置。
如果不喜欢用Spring的XML Schema的配置方式,即
AnnotationAwareAspectJAutoPoxyCreater类是一个Bean后处理器,该Bean后处理器将会为容器中所有的Bean生成AOP代理。
为了在Spring应用中启动@AspectJ支持,还需要在应用的类加载路径下增加两个AspectJ库:asectjweaver.jar和aspectjrt.jar,直接使用AspectJ安装路径下lib目录中增加的两个JAR文件即可。除此之外,Spring AOP还需要依赖一个aopalliance.jar。
>hello 注解aop
Spring配置:
切面类:
/**
* RepairAspect 切面类:增强处理类
*
*/
@Aspect
public class RepairAspect {
//配置切入点
@Pointcut("execution(* com.langsin.dao.impl.*.*(..))")
public void myPointCut(){}
// 进行before增强处理的方法
@Before("myPointCut()")
public void beforeAspect() {
System.out.println("----目标方法执行之前,Before进行增强处理----");
}
// 进行after增强处理的方法
@After("myPointCut()")
public void afterAspect() {
System.out.println("----目标方法执行之前,After进行增强处理----");
}
// 进行around增强处理的方法:除了before 和after ,环绕增强处理可以指定目标方法在哪个位置执行,hai可以让目标方法不执行
@Around("myPointCut()")
public Object aroundAspect(ProceedingJoinPoint point){
System.out.println("----环绕前,around进行增强处理----");
try {
return point.proceed(point.getArgs());
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("----环绕后,around进行增强处理----");
return null;
}
}
>aop 查看目标方法相关信息
以Before增强处理为例:
/**
* RepairAspect 切面类:增强处理类
*
*/
@Aspect
public class RepairAspect {
//配置切入点
@Pointcut("execution(* com.langsin.dao.impl.*.*(..))")
public void myPointCut(){}
// 进行before增强处理的方法
@Before("myPointCut()")
public void beforeAspect(JoinPoint point) {
//想看看目标方法的一些信息? 通过连接点JoinPoint
//获取目标方法的执行参数列表
System.out.println(Arrays.toString(point.getArgs()));
//获取目标方法的对象
System.out.println(point.getTarget());
//获取目标方法的方法签名
System.out.println(point.getSignature().getName());
System.out.println("----目标方法执行之前,Before进行增强处理----");
}
}
除此之外,如果只要看参数,Spring还提供了另外一种更为简洁的方式:
/**
* RepairAspect 切面类:增强处理类
*
*/
@Aspect
public class RepairAspect {
//配置切入点,&& args(userId),对切入点表达式增加了额外的限制
@Pointcut("execution(* com.langsin.dao.impl.*.*(..))&& args(userId)")
public void myPointCut(Integer userId){}
// 进行before增强处理的方法
@Before("myPointCut(userId)")
public void beforeAspect(JoinPoint point,Integer userId) {
System.out.println(userId);
System.out.println("----目标方法执行之前,Before进行增强处理----");
}
}