Spring AOP(面向切面编程)

AOP(Aspect Oriented Programming),也就是面向切面编程,作为面向对象编程的一种补充,AOP已经成为一种比较成熟的编程方式。可以这样理解:OOP是从静态角度考虑程序结构,而AOP是从动态角度考虑程序运行过程。

>为什么要用?

公共业务?复制粘贴?NO

Spring AOP(面向切面编程)_第1张图片

抽象出方法?依赖耦合!NO

Spring AOP(面向切面编程)_第2张图片 

AOP专门用于处理系统中分布于各个模块中的交叉关注点的问题,在Java EE应用中,常常通过AOP来处理一些具有横切性质的系统级服务,如事务管理、安全检查、缓存、对象池管理等,AOP已经成为一种非常常用的解决方案。

>AOP实现可分为两类:

  • 静态AOP实现:AOP框架在编译阶段对程序进行修改,即:实现对目标类的增强,生成静态的AOP代理类,即生成的*.class已经被改掉了,需要特定的编译器。以AspectJ为代表(针对字节码class文件进行修改)。
  • 动态AOP实现:AOP框架在运行阶段生成AOP代理,即:在内存中以JDK动态代理或cglib动态地生成AOP代理类,以实现对目标对象的增强以Spring AOP为代表

一般来说,静态AOP实现具有较好的性能,但需要使用特殊的编译器。动态AOP实现是纯Java实现,因此无须特殊的编译器,但是通常性能较差。

>AOP基本概念

AOP从程序运行角度考虑程序的流程,提取业务处理过程的切面。AOP面向的是程序运行中各个步骤,希望以更好的方式来组合业务处理的各个步骤。

AOP框架并不与特定的代码耦合,AOP框架能处理程序执行中特定的切入点pointcut,而不与某个具体类耦合。AOP框架具有如下两个特征。

  • 各步骤之间的良好隔离性。
  • 源代码无关性。

下面是关于面向切面编程的一些术语。

  • 切面(Aspect):切面用于组织多个Advice(增强处理),Advice放在切面中定义。即:被加入执行的代码块。
  • 连接点(Joinpoint):程序执行过程中明确的接入点,比如方法的调用,或者异常的抛出。在Spring AOP中,连接点总是方法的调用。
  • 增强处理(Advice):AOP框架在特定的切入点上执行的增强处理。增强处理有“around”、“before”、“after”等类型。所谓的增强处理:就是在原代码不改动的情况下,额外多执行的那些代码。
  • 切入点(Pointcut):可以插入增强处理的连接点。简而言之,当某个连接点满足指定要求时,该连接点将被添加增强处理,该连接点也就变成了切入点。例如如下代码:

pointcut xxxPointcut():execution(void H*.say*)

每个方法被调用都只是连接点,但如果方法属于H开头的类,且方法以say开头,则该方法的执行将变成切入点。也可以认为符合条件的连接点即为切入点。如何用表达式来定义切入点是AOP的核心,Spring默认使用AspectJ切入点的语法。

  • 引入:将方法或字段添加到被处理的类中。
  • 目标对象:被AOP框架进行增强处理的对象,也被称为增强对象。如果AOP框架采用的是动态AOP实现,那么该对象就是一个被代理的对象。
  • AOP代理:AOP框架创建的对象,简单地说,代理就是对目标对象的增强。Spring中的AOP代理可以是JDK动态代理,也可以是cglib(Code Generation Library:代码生成库)代理。前者为实现接口的目标对象的代理,后者是不实现接口的目标对象的代理。
  • 织入(Weaving):将增强处理添加到目标对象中,并创建一个被增强的对象的过程就是织入。织入有两种方式——编译时增强和运行时增强。

由前面的介绍知道,AOP代理就是由AOP框架动态生成一个对象,该对象可作为目标对象使用。AOP代理包含了目标对象的全部方法,但AOP代理中的方法与目标对象的方法存在差异——AOP方法在特定的切入点加入了增强处理,并回调了目标对象的方法。

AOP代理所包含的方法与目标对象的方法示意图如下所示:

Spring AOP(面向切面编程)_第3张图片

>基于xml的AOP处理

(首先要引入AOP的命名空间)

在Spring配置文件中,所有的切面,切入点和增强处理都必须定义在aop:config元素内部。beans元素下可以包含多个aop:config元素,一个aop:config元素可以包含pointcut、advisor和aspect元素,并且这三个元素必须按照彼此顺序来定义。关于aop:config元素所包含的子元素如下图所示:

Spring AOP(面向切面编程)_第4张图片

在上图中已经非常清楚的绘制出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的配置方式,即这种方式,则应该在Spring配置文件中增加以下片段来启用@AspectJ支持。

org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoPoxyCreater/>

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进行增强处理----");
	}

}

 

你可能感兴趣的:(SSM)