spring配置总结——aop配置部分

接上篇beans部分,这部分说下aop的配置。

AOP(Aspect-Oriented Programming,面向切面编程):是一种新的方法论。是对传统OOP的补充。

AOP的主要编程对象是切面(aspect),而切面模块化横切点。

在应用AOP编程时,仍需要定义公共功能,但可以明确的定义这个功能在哪里,以什么方式应用,并且不必修改受影响的类,这样一来横切关注点就被模块化到特殊的独享(切面)里。

AOP的好处:

    每个业务逻辑唯一一个位置,代码不分散,便于维护和升级。

    业务模块简洁,值包含核心业务代码。


AOP术语:

    切面(Aspect):横切关注点(跨越应用程序多个模块的功能)被模块化的特殊对象。

    通知(Advice):切面必须要完成的工作。

    目标(Target):被通知的对象。

    代理(Proxy):向目标对象应用通知之后创建的对象。

    连接点(JoinPoint):程序执行的某个特定位置。如类某个方法调用前、调用后、方法抛出异常后等。连接点由两个信息确定:方法表示的程序执行点;相对点表示的方位。例如ArithmeticCalculator#add()方法执行前的连接点:执行点为ArithmeticCalculator#add()方位为该方法执行前的位置。

    切点(pointcut):每个类都拥有多个连接点。例如:ArithmeticCalculator的所有方法实际上都是连接点,即连接点是程序类中可观存在的事物。AOP通过切点定位到特点的连接点。类比:连接点相当于数据库中的记录,切点相当于查询条件。起点和连接点不是一对一的关系,一个切点匹配多个连接点,切点通过org.springframeword.Pointcut接口描述,它使用类和方法作为连接点的查询条件。

AspectJ:Java社区中最完整最流行的AOP框架。

在Spring中启用AspectJ注解支持;

要在Spring应用中应用AspectJ注解,必须在classpath下包含AspectJ类库:aopalliance.jar、aspectj.weaver.jar和Spring-aspects.jar.

将aop scheme添加到<beans>根元素中。

要在SpringIOC容器中启用AspectJ注解支持,只要在Bean配置文件中定义一个空的XM元素<aop:aspectj-autoproxy>

当SpringIOC容器侦测到Bean配置文件中的<aop:aspectj-autoproxy>元素时,会自动与AspectJ切面匹配的Bean创建代理。

用AspectJ注解声明切面

要在Spring中声明AspectJ切面,只需要在IOC容器中将切面生面为Bean实例,当在SpringIOC容器中初始化AspectJ切面之后,SpingIOC容器就会为那些与AspectJ切面相匹配的Bean创建代理。

在AspectJ注解中。切面只是一个带有@Aspect注解的Java类。

通知是标注有某种注解的简单的java方法。

AspectJ支持5种类型的通知注解:

    @Before:前置通知,在方法执行之前执行

    @After:后置通知,在方法执行之后执行

    @AfterRunning:返回通知,在方法返回结果之后执行

    @AfterThrowing:异常通知,在方法抛出异常之后执行

    @Around:环绕通知,围着着方法执行

利用方法签名编写AspectJ切入点表达式

最典型的切入点表达式是根据犯法的签名来匹配各种方法:

    execution * com.atguigu.spring.ArithmeticCalculator.*(...):匹配ArithmeticCalculator中声明的所有方法,第一个*表示任意修饰符机返回值。第二个*代表任意方法。...匹配任意数量的参数,若目标类与接口与接口与该切面在一个包中,可以省略包名。

    execution public * com.atguigu.spring.ArithmeticCalculator.*(...):匹配ArithmeticCalculator接口中所有public的方法。

    execution public double com.atguigu.spring.ArithmeticCalculator.*(...):匹配ArithmeticCalculator接口中返回double类型的方法

    execution public double com.atguigu.spring.ArithmeticCalculator.*(.double, ..):匹配第一个参数为double类型的方法,..匹配任意数量任意类型的参数。

    execution public double com.atguigu.spring.ArithmeticCalculator.*(double, double):匹配参数类型为double,double类型的方法。

在AspectJ中,切入点表达式可以通过操作符&&,||,!结合起来。




可以在通知方法中声明一个类型为JoinPoint的参数。然后就能访问连接细节。如方法名和参数值。

对于环绕通知来说连接点的参数类型必须是ProceedingJoinPoint。他是JoinPoint的子接口,允许控制何时执行,是否执行连接点。

在环绕通知中,需要明确调用ProceedingJoinPoint的proceed()方法来执行被代理的方法,如果忘记这样做就会导致通知被执行了,但是目标方法没有被执行。

注意:环绕通知的方法需要返回目标方法执行之后的结果,即调用jointPoint.proceed()的返回值,否则会出现空指针异常。

指定切面优先级: 可以使用@Order注解来指定切面的优先级,值越小优先级越高

重用切入点定义:通过@Pointcut注解将一个切入点声明称简单的方法,切入点的方法体通常是空的。切入点方法的访问控制同时也控制着这个切入点的可见性。如果切入点要在多个切面找那个共用,最好将他们几种在一个公共类中。在引入切入点时,必须将类名也包括在内,如果类没有与这个切面放在同一个包中,还必须包含包名。

基于注解的aop示例:

public interface ArithmeticCalculator {
	int add(int i ,int j);
	int sub(int i,int j );
	int mul(int i,int j);
	int div (int i,int j);
}
@Component
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {

	@Override
	public int add(int i, int j) {
		int result = i + j;
		return result;
	}

	@Override
	public int sub(int i, int j) {
		int result = i - j;
		return result;
	}

	@Override
	public int mul(int i, int j) {
		int result = i * j;
		return result;
	}

	@Override
	public int div(int i, int j) {
		int result = i / j;
		return result;
	}

}
@Order(1)
@Component
@Aspect
public class ValidationAspect {
	/*@Before("execution(public int com.atguigu.spring.aop.impl.ArithmeticCalculator.*(int, int))")*/
	@Before("LoggingAspect.declareJoinPoint()")
	public void validate(JoinPoint joinPoint){
		System.out.println("--> validation" + Arrays.asList(joinPoint.getArgs()));
	}
}
package com.atguigu.spring.aop.impl;

import java.util.Arrays;
import java.util.List;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

//把这个类声明为一个切面:首先把这个类放到IOC容器中、在声明为一个切面
//然后在考虑在哪个类的哪个方法执行前插入通知的方法。
/**
 * 可以使用@Order注解来指定切面的优先级,值越小优先级越高
 * @author adminitrator
 *
 */
@Order(2)
@Component
@Aspect
public class LoggingAspect {
	/**
	 * 定义一个方法,用于声明切入点表达式,一般地,该方法中不需要添加其他代码
	 * 使用@Pointcut注解来声明切入点表达式
	 * 后面的其他同志直接使用方法名来引用当前的额切入点表达式。
	 */
	@Pointcut("execution(public int com.atguigu.spring.aop.impl.ArithmeticCalculator.*(int, int))")
	public void declareJoinPoint(){
		
	}
	
	//声明该方法是一个前置通知:在目标方法之前执行
		//注解中的* 表示ArithmeticCalculator接口下的所有方法
		//注解参数中的 public int 也可也用* 来代替,表示任意修饰符,任意返回类型
		@Before("declareJoinPoint()")
		public void beforeMethod(JoinPoint joinPoint){//joinPoint 连接点
			String  methodName = joinPoint.getSignature().getName();
			List<Object> args = Arrays.asList(joinPoint.getArgs());
			System.out.println("The method "+ methodName+" begins with "+ args);
		}
		
		//后置通知:在目标方法执行之后(无论是否发生异常),执行的通知
		//后置通知中还不能访问目标方法执行的结果
		@After(value = "declareJoinPoint()")
		public void afterMethod(JoinPoint joinPoint){
			String  methodName = joinPoint.getSignature().getName();
			List<Object> args = Arrays.asList(joinPoint.getArgs());
			System.out.println("The method "+ methodName+" begins with "+ args);
		}
		
		//在方法正常返回结束后执行的代码
		//放回通知是可以范文到方法的返回值的
		@SuppressWarnings("unused")
		@AfterReturning(value = "execution(public int com.atguigu.spring.aop.impl.ArithmeticCalculator.*(int, int))",
				returning="result")
		public void afterReturning(JoinPoint joinPoint,Object result){
			String  methodName = joinPoint.getSignature().getName();
			List<Object> args = Arrays.asList(joinPoint.getArgs());
			System.out.println("The method "+ methodName+ " result-->" +result);
		}
		//异常通知
		/**
		 * 在目标方法出现异常时,会执行代码
		 * 可以方位到异常对象;可以指定出现特定异常时在执行通知。通诺throwing参数中异常,在方法参数中执行异常类型。
		 * @param joinPoint
		 * @param ex
		 */
		@SuppressWarnings("unused")
		@AfterThrowing(value = "execution(public int com.atguigu.spring.aop.impl.ArithmeticCalculator.*(int, int))",throwing="ex")
		public void afterThrowing(JoinPoint joinPoint,Exception ex){
			String  methodName = joinPoint.getSignature().getName();
			List<Object> args = Arrays.asList(joinPoint.getArgs());
			System.out.println("The method "+ methodName +" occurs exception " + ex);
		}
	
	//环绕通知 就相当于动态代理
	/**
	 * 环绕通知需要携带ProceedingJoinPoint类型参数
	 * 环绕通知类似于动态代理的全过程:ProceedingJoinPoint 类型的参数可以决定是否执行目标方法
	 * 且环绕通知必须有返回值,返回值即为目标方法的返回值。
	 * @param joinPoint
	 */
/*	@Around(value = "execution(public int com.atguigu.spring.aop.impl.ArithmeticCalculator.*(int, int))")
	public Object aroundMethod(ProceedingJoinPoint pjd){
		//执行目标方法
		Object result = null;
		try {
			System.out.println("The method " + pjd.getSignature().getName()+ " begin " + Arrays.asList(pjd.getArgs()));
			result = pjd.proceed();
			//后置通知
			System.out.println("The method " + pjd.getSignature().getName()+ " ends  " +Arrays.asList(pjd.getArgs()));
		} catch (Throwable e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			//异常通知
			System.out.println("The method " + pjd.getSignature().getName()+ " occurs " + e);
			throw new RuntimeException(e);
		}
		//后置通知
		System.out.println("The method " + pjd.getSignature().getName()+ " ends");
		return result;
	}*/
}
<?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: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.atguigu.spring.aop.impl" />

	<!-- 这句话的作用是使我们在切面声明的注解(如:before)起作用:在我调用目标方法跟before注解中配置的方法相匹配的时候,aop自动为那个目标方法所在的类生成代理对象,在调用方法之前执行配置的方法。 -->
	<!-- 使AspectJ注解起作用:自动为匹配的类生成代理对象 -->
	<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

基于XML的AOP配置:

public interface ArithmeticCalculator {
	int add(int i ,int j);
	int sub(int i,int j );
	int mul(int i,int j);
	int div (int i,int j);
}
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {

	@Override
	public int add(int i, int j) {
		int result = i + j;
		return result;
	}

	@Override
	public int sub(int i, int j) {
		int result = i - j;
		return result;
	}

	@Override
	public int mul(int i, int j) {
		int result = i * j;
		return result;
	}

	@Override
	public int div(int i, int j) {
		int result = i / j;
		return result;
	}

}
public class LoggingAspect {

	public void declareJoinPoint() {

	}

	public void beforeMethod(JoinPoint joinPoint) {// joinPoint 连接点
		String methodName = joinPoint.getSignature().getName();
		List<Object> args = Arrays.asList(joinPoint.getArgs());
		System.out.println("The method " + methodName + " begins with " + args);
	}

	public void afterMethod(JoinPoint joinPoint) {
		String methodName = joinPoint.getSignature().getName();
		List<Object> args = Arrays.asList(joinPoint.getArgs());
		System.out.println("The method " + methodName + " begins with " + args);
	}

	@SuppressWarnings("unused")
	public void afterReturning(JoinPoint joinPoint, Object result) {
		String methodName = joinPoint.getSignature().getName();
		List<Object> args = Arrays.asList(joinPoint.getArgs());
		System.out.println("The method " + methodName + " result-->" + result);
	}

	@SuppressWarnings("unused")
	public void afterThrowing(JoinPoint joinPoint, Exception ex) {
		String methodName = joinPoint.getSignature().getName();
		List<Object> args = Arrays.asList(joinPoint.getArgs());
		System.out.println("The method " + methodName + " occurs exception " + ex);
	}

	public Object aroundMethod(ProceedingJoinPoint pjd) {
		// 执行目标方法
		Object result = null;
		try {
			System.out.println("The method " + pjd.getSignature().getName() + " begin " + Arrays.asList(pjd.getArgs()));
			result = pjd.proceed();
			// 后置通知
			System.out.println("The method " + pjd.getSignature().getName() + " ends  " + Arrays.asList(pjd.getArgs()));
		} catch (Throwable e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			// 异常通知
			System.out.println("The method " + pjd.getSignature().getName() + " occurs " + e);
			throw new RuntimeException(e);
		}
		// 后置通知
		System.out.println("The method " + pjd.getSignature().getName() + " ends");
		return result;
	}
}
public class ValidationAspect {

	public void validate(JoinPoint joinPoint){
		System.out.println("--> validation" + Arrays.asList(joinPoint.getArgs()));
	}
}
<?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: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">
	<!-- arithmeticCalculatorImpl 纳入IOC容器管理 -->
	<bean id="arithmeticCalculatorImpl" class="com.atguigu.spring.aop.xml.ArithmeticCalculatorImpl"></bean>
	
	<!-- 配置切面的Bean -->
	<bean id="loggingAspect" class="com.atguigu.spring.aop.xml.LoggingAspect"></bean>
	<bean id="validationAspect" class="com.atguigu.spring.aop.xml.ValidationAspect"></bean>
	
	<!--配置aop  -->
	<aop:config>
		<!-- 配置切点表达式 -->
		<aop:pointcut expression="execution(* com.atguigu.spring.aop.xml.ArithmeticCalculator.*(int, int))" id="pointcut"/>
		<!-- 配置切面和通知 -->
		<aop:aspect ref="loggingAspect" order="2" >
			<!-- <aop:before method="beforeMethod" pointcut-ref="pointcut"/>
			<aop:after method="afterMethod" pointcut-ref="pointcut"/>
			<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="ex"/>
			<aop:after-returning method="afterReturning" pointcut-ref="pointcut" returning="result"/> -->
			<aop:around method="aroundMethod" pointcut-ref="pointcut" />
		</aop:aspect>
		<aop:aspect ref="validationAspect" order="1">
			<aop:before method="validate" pointcut-ref="pointcut"/>
		</aop:aspect>
	</aop:config>
</beans>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值