Spring框架笔记(二十三)——基于配置文件的方式来配置 AOP

配置实现IOC功能时,我们采用了配置文件xml和注解两类方式实现。实现AOP功能时我们也可以使用两种方式。前面我们介绍了AOP基于注解的实现方式,本文我将采用基于配置文件的方式完成从原始对象bean、切面bean、切点及通知配置的方法。

用基于 XML 的配置声明切面

除了使用 AspectJ 注解声明切面, Spring 也支持在 Bean 配置文件中声明切面. 这种声明是通过 aop schema 中的 XML 元素完成的.

正常情况下, 基于注解的声明要优先于基于 XML 的声明. 通过 AspectJ 注解, 切面可以与 AspectJ 兼容, 而基于 XML 的配置则是 Spring 专有的. 由于 AspectJ 得到越来越多的 AOP 框架支持, 所以以注解风格编写的切面将会有更多重用的机会.

好,我们还是用例子说话。我们重新构建一个包,建立核心业务的类和切面类:

核心类:加减乘除计算

切面1:数据验证

切面2:输出日志

package com.happBKs.spring.aopbasic.aop2;

public class AtithmeticCalculateImpl implements AtithmeticCalculate {

	public int add(int a, int b) {
		int result=a+b;
		return result;
	}

	public int sub(int a, int b) {
		int result=a-b;
		return result;
	}

	public int mul(int a, int b) {
		int result=a*b;
		return result;
	}

	public int div(int a, int b) {
		int result=a/b;
		return result;
	}

}
package com.happBKs.spring.aopbasic.aop2;

public class AtithmeticCalculateImpl implements AtithmeticCalculate {

	public int add(int a, int b) {
		int result=a+b;
		return result;
	}

	public int sub(int a, int b) {
		int result=a-b;
		return result;
	}

	public int mul(int a, int b) {
		int result=a*b;
		return result;
	}

	public int div(int a, int b) {
		int result=a/b;
		return result;
	}

}
package com.happBKs.spring.aopbasic.aop2;

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

import org.aspectj.lang.JoinPoint;

public class DataValidateAspect {

	public boolean beforeMethod(JoinPoint joinPoint)
	{
		String methodName=joinPoint.getSignature().getName();
		List<Object> args=Arrays.asList(joinPoint.getArgs());
		System.out.println("data validate---begin to "+methodName+" with "+args);
		if((Integer)(args.get(0))>0&&(Integer)(args.get(1))>0)
		{
			System.out.println("data is OK");
			return true;
		}
		else
		{
			System.out.println("data is bad");
			return false;
		}

	}

}
package com.happBKs.spring.aopbasic.aop2;

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

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

public class LoggingAspect {

	/*
	 * 在com.happBKs.spring.aopbasic.aop1.AtithmeticCalculate接口的每一个实现类的每一个方法开始之前执行
	 */
	public void beforeMethod(JoinPoint joinPoint)
	{
		String methodName=joinPoint.getSignature().getName();
		List<Object> args=Arrays.asList(joinPoint.getArgs());
		System.out.println("begin to "+methodName+" with "+args);
	}

	/*
	 * 在目标方法执行之后(无论是否发生异常),执行该通知
	 */
	public void afterMethod(JoinPoint joinPoint)
	{
		String methodName=joinPoint.getSignature().getName();
		System.out.println("end to "+methodName);
	}

	/*
	 * 在目标方法正常执行之后执行的代码
	 * 返回通知是可以访问目标方法的返回值的
	 */
	public void afterReturning(JoinPoint joinPoint, Object resultParam)
	{
		String methodName=joinPoint.getSignature().getName();
		System.out.println("after "+methodName+" with returning result "+resultParam);
	}

	/*
	 * 在目标方法出现异常时出现代码
	 * 可以访问到异常对象,且可以指定在特定异常时才执行代码
	 */
	public void afterThrowing(JoinPoint joinPoint, Exception exThrowing)
	{
		String methodName=joinPoint.getSignature().getName();
		System.out.println("after exception of "+methodName+" we find the exception is "+exThrowing);
	}

	/*
	 * 回环通知需要携带ProceedingJoinPoint类型参数
	 * 回环通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行目标方法
	 * 且回环通知必须有返回值,返回值即为目标方法的返回值
	 */
	public Object roundingMethod(ProceedingJoinPoint pjp)
	{
		Object result=null;
		String methodName=pjp.getSignature().getName();

		try {
			//前置通知
			System.out.println("Around: Begin Method"+methodName+" executed with "+Arrays.asList(pjp.getArgs()));

			result= pjp.proceed();
			//返回通知
			System.out.println("Around: Return Method"+methodName+"  with result"+result);
		} catch (Throwable e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			//异常通知
			System.out.println("Around: Exception in "+methodName+":"+e );

		}

		//后置通知
		System.out.println("Around: end Method"+methodName);

		return 100;
	}

}

上面的这些类,我们不再需要加入各种注解,所有的切面、通知、切点等我们都在配置文件中进行配置:

新建配置文件applicationContext-xml.xml。(加入beans和aop命名空间)

<?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"
	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.1.xsd">

	<!-- 配置bean -->
	<bean id="atithmeticCalculate"
		class="com.happBKs.spring.aopbasic.aop2.AtithmeticCalculateImpl"></bean>

	<!-- 配置切面bean -->
	<bean id="dataValidateAspect" class="com.happBKs.spring.aopbasic.aop2.DataValidateAspect"></bean>
	<bean id="loggingAspect" class="com.happBKs.spring.aopbasic.aop2.LoggingAspect"></bean>

	<!-- 配置AOP -->
	<aop:config>
		<!-- 配置切点表达式 -->
		<aop:pointcut id="pointCutData"
			expression="execution(* com.happBKs.spring.aopbasic.aop2.AtithmeticCalculateImpl.*(..))" />

		<!-- 配置切面及通知 -->
		<aop:aspect ref="dataValidateAspect" order="2">
			<aop:before method="beforeMethod" pointcut-ref="pointCutData" />
		</aop:aspect>
		<aop:aspect ref="loggingAspect" order="1">
			<aop:before method="beforeMethod" pointcut-ref="pointCutData" />
			<aop:after method="afterMethod" pointcut-ref="pointCutData"/>
			<aop:after-throwing method="afterThrowing" pointcut-ref="pointCutData" throwing="exThrowing"/>
			<aop:after-returning method="afterReturning" pointcut-ref="pointCutData" returning="resultParam"/>

			<aop:around method="roundingMethod" pointcut-ref="pointCutData" />
		</aop:aspect>
	</aop:config>

</beans>

这里的步骤是:

1,首先把所有原始对象的bean配置好

2,然后把所有切面bean配置好,配置切面的bean 的id与切面类的映射。

3,配置aop

(1)配置切点:关系到哪些方法执行时会调用相关切面的通知。切点先配置好,一会儿留着引用。

(2)配置每一个切面:

a。配置切面bean的id与order切面优先级的映射,以及切面内的各个通知。

b。配置各个切面内部的通知与切点的映射,切点以引用方式给出。

测试代码:

package com.happBKs.spring.aopbasic;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.happBKs.spring.aopbasic.aop2.AtithmeticCalculate;

public class TestSpringAOP2 {
	@Test
	public void testSpringAOP()
	{
		//1. 创建spring 的 IOC 容器
		ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext-xml.xml");
		//2. 从IOC容器获取bean实例
		AtithmeticCalculate atithmeticCalculate = (AtithmeticCalculate)ac.getBean(AtithmeticCalculate.class);
		//考察一下代理对象是否生成
		System.out.println(atithmeticCalculate.getClass().getName());
		//3. 使用bean
		System.out.println("Example 1:");
		int result=atithmeticCalculate.add(10, 5);
		System.out.println(result);
		System.out.println("\r\nExample 2:");
		int result2=atithmeticCalculate.div(10, 0);
		System.out.println(result2);
	}
}

运行结果:

com.sun.proxy.$Proxy4

Example 1:

begin to add with [10, 5]

Around: Begin Methodadd executed with [10, 5]

data validate---begin to add with [10, 5]

data is OK

Around: Return Methodadd  with result15

Around: end Methodadd

after add with returning result 100

end to add

100

Example 2:

begin to div with [10, 0]

Around: Begin Methoddiv executed with [10, 0]

data validate---begin to div with [10, 0]

data is bad

java.lang.ArithmeticException: / by zero

at com.happBKs.spring.aopbasic.aop2.AtithmeticCalculateImpl.div(AtithmeticCalculateImpl.java:24)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)

at java.lang.reflect.Method.invoke(Unknown Source)

at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)

at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)

at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)

at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:52)

at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)

at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:85)

at com.happBKs.spring.aopbasic.aop2.LoggingAspect.roundingMethod(LoggingAspect.java:76)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)

at java.lang.reflect.Method.invoke(Unknown Source)

at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:621)

at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:610)

at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:68)

at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)

at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:52)

at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)

at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:58)

at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)

at org.springframework.aop.aspectj.AspectJAfterAdvice.invoke(AspectJAfterAdvice.java:43)

at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)

at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:52)

at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)

at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)

at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)

at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)

at com.sun.proxy.$Proxy4.div(Unknown Source)

at com.happBKs.spring.aopbasic.TestSpringAOP2.testSpringAOP(TestSpringAOP2.java:24)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)

at java.lang.reflect.Method.invoke(Unknown Source)

at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)

at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)

at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)

at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)

at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)

at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)

at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)

at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)

at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)

at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)

at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)

at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)

at org.junit.runners.ParentRunner.run(ParentRunner.java:300)

at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)

at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)

at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)

at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)

at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)

at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

Around: Exception in div:java.lang.ArithmeticException: / by zero

Around: end Methoddiv

after div with returning result 100

end to div

100

时间: 2024-10-12 23:58:02

Spring框架笔记(二十三)——基于配置文件的方式来配置 AOP的相关文章

使用Spring框架入门二:基于注解+XML配置的IOC/DI的使用

一.简述 本文主要讲使用注解+xml配合使用的几种使用方式.基础课程请看前一节. 二.步骤 1.为Pom.xml中引入依赖:本例中使用的是spring-context包,引入此包时系统会自动导入它的依赖包spring-beans\spring-core\spring-expression\spring-context. <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http:

Mybatis学习笔记-CURD(基于配置文件的方式)

User.java实体类 public class User { private int id; private String username; private int age; //... } userMapper.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" &q

angular学习笔记(二十三)-$http(1)-api

之前说到的$http.get和$http.post,都是基于$http的快捷方式.下面来说说完整的$http: $http(config) $http接受一个json格式的参数config: config的格式如下: { method:字符串 , url:字符串, params:json对象, data:请求数据, headers:请求头, transformRequest:函数,转换post请求的数据的格式, transformResponse:函数,转换响应到的数据的格式, cache:布尔

Spring框架基本概念之POJO,EJB,DI,AOP,IOO,JCA

1.POJO(Plain Old Java Object),一个正规的Java对象(不是JavaBean,EntityBean等),该对象也不担当任何的特殊的角色,也不实现任何Java框架指定的接口. POJO不是我们开始认为的JavaBean,当然更不是EJB,它不依赖于框架(即继承或实现某些框架类或接口).例如:Struts1中的Action和ActionForm当然不属于POJO了,而在Struts2中的Action由于可以不继承任何的接口,所以在这种情况下Action是POJO,但是St

Spring框架中利用注解进行自动装配的环境配置步骤和常见问题

第1步:配置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:context="http://www.spring

【Spring学习笔记-MVC-4】返回Json数据-方式2

摘要 本文讲解另外一种利用spring MVC返回json数据的方法. 前文回顾 在<[Spring学习笔记-MVC-3]返回Json数据-方式1>中介绍了通过: @ResponseBody声明返回值: 配置<mvc:annotation-driven />: 来返回json数据.效果如下:   ==>, 从上面的效果看,只能返回一个对象,不能返回多个对象,不能做到形如下图的返回结果, 存在局限性(可能可以返回多个,自己不知道如何实现). 下面介绍的方式2,利用spring

Android笔记二十三.Android基于事件监听器处理机制

转载请表明出处:http://blog.csdn.net/u012637501(嵌入式_小J的天空) 一.Android的事件处理 Android事件处理包括两个部分:Android事件处理机制(基本)和Android消息传递机制(进阶).前者包含三种处理方式,即基于监听的事件处理.基于回调的事件处理.直接绑定到标签;后者包含两种处理方式,即Handler消息传递.异步任务处理. 1.Android的事件处理机制 (1)基于监听的事件处理方式 通常做法是为Android界面组件绑定特定的事件监听

3.Spring框架中的标签与配置文件分离

1.Spring框架中标签的配置 1. id属性和name属性的区别 * id -- Bean起个名字,在约束中采用ID的约束,唯一 * 取值要求:必须以字母开始,可以使用字母.数字.连字符.下划线.句话.冒号 id:不能出现特殊字符 * name -- Bean起个名字,没有采用ID的约束(基本不在使用) * 取值要求:name:出现特殊字符.如果<bean>没有id的话 , name可以当做id使用 * Spring框架在整合Struts1的框架的时候,Struts1的框架的访问路径是以/

Spring学习笔记二

第四章 Spring与数据库 一. DataSource Spring提供了在Spring上下文配置数据源bean的多种方式包括 l 通过JDBC驱动程序定义的数据源 l 通过JNDI查找的数据源 l 连接池的数据源 1. 使用数据源连接池 DBCP(database conection pool)是一个不错的连接池选择. 其中的BasicDataSource的最常用的,因为它在Spring中易于配置.在Spring中可以使用以下代码来配置dbcp. <bean id="datasourc