Spring的AOP切面编程

AOP切面编程:即对当前已添加入IOC容器Bean类进行相应的统一日志操作,一个切面即对Bean类的包装代理。

目录

一、注解方式进行AOP编程

二、XML文件方式进行AOP编程


一、注解方式进行AOP编程

1、导包:

                * com.springsource.net.sf.cglib-2.2.0.jar
                * com.springsource.org.aopalliance-1.0.0.jar
                * com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
                * spring-aspects-4.0.0.RELEASE.jar

2、在<beans>标签添加属性

        xmlns:aop="http://www.springframework.org/schema/aop"

     或者鼠标点击快速导入

                        Spring的AOP切面编程

3、 在XML文件里添加配置

使用注解方式自动扫描并自动装载入IOC容器的配置:<context:component-scan base-package="包名"></context:component-scan>

使 @AspjectJ 注解起作用的配置: <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

4、编写切面类,并在类前添加注解@Aspect,@Component。

       @order(int):可不加,有多个切面类时可以指定切面类的优先级,索引从0开始

      给切面类的方法前添加@注解名(切面表达式)

                     方法的注解:有5种,代表了当前是什么类型的包装;

                     切面表达式:对哪个类或者哪个方法的包装及动态代理。

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

               @After: 后置通知, 在方法执行之后执行,无论当前方法是否发送异常

               @AfterReturning: 返回通知, 在方法返回结果之后(正常结束后)执行

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

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

       切面表达式格式:

                            @注解类型("execution(public int 包名.类名.方法名(参数类型,..))")

                                   注意: public int可用一个*表示通配符,int也可用一个*表示通配符,public不可以。

                                               包名、类名、方法名都可以用*表示通配符。

                                               参数类型可用..表示匹配数目不限的所有类型。

       切面表达式例子:

                                                public * 包名.类名.*(参数类型,..):该类所有匹配参数类型的所有公有方法

                                                public * AOP.*.*(..)):该类所有方法

       切面表达式可以提取为方法给多个注解使用:

@Component
@Aspect
class LogAspect{
        @Pointcut("切面表达式")
        public void 切面表达式名() {}
    	//前置通知
    	@Before("切面表达式名()")
    	public void beforeAdd(JoinPoint joinPoint) {
	    	String methodName=joinPoint.getSignature().getName();
	    	List<Object> list=Arrays.asList(joinPoint.getArgs());
	    	System.out.println("方法开始了,方法名:"+methodName+",方法列表"+list);
    	}

}


 

示例:切面类的方法可以定义一个JoinPoint类型参数,getSignature().getName():获取被包装代理的方法名

            getArgs():获取被包装代理方法的Object类型参数数组

package AOP;

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;

/*
 * 日志切面类
 */
@Order(2)
@Component
@Aspect
public class LoggingAspect {
	//切面表达式可以复用
	@Pointcut("execution(public int AOP.CountService.add(..))")
	public void addExecution() {}
	
	//前置通知
	@Before("addExecution()")
	public void beforeAdd(JoinPoint joinPoint) {
		String methodName=joinPoint.getSignature().getName();
		List<Object> list=Arrays.asList(joinPoint.getArgs());
		System.out.println("方法开始了,方法名:"+methodName+",方法列表"+list);
	}
	//后置通知
	@After("addExecution()")
	public void afterAdd() {
		System.out.println("当前操作已执行完毕");
	}
	//返回通知
	@AfterReturning(value="addExecution()"
			,returning="result")
	public void returnAdd(Object result) {
		System.out.println("当前返回结果:"+result);
	}
	//异常通知
	@AfterThrowing(value="execution(public * AOP.CountService.*(..))"
			,throwing="e")
	public void exceptionDiv(Exception e) {
		System.out.println("异常信息:"+e.toString());
	}
}
/*
 * 验证切面类
 */
@Order(1)
@Component
@Aspect
class ValidateAspect{
	//前置通知
	@Before("execution(public int AOP.CountService.add(..))")
	public void beforeAdd(JoinPoint joinPoint) {
		System.out.println("我是验证,我先开始");
	}
}

待包装代理类:需要装载入IOC容器,所以使用了@Service注解 

package AOPAnnotation;

import org.springframework.stereotype.Service;

@Service
public class CountService {
	public int add(int i,int j) {
		System.out.println("now["+i+","+j+"]");
		return i+j;
	}
	public int Div(int i,int j) throws Exception{
		System.out.println("now["+i+","+j+"]");
		return i/j;
	}
}

5、调用方法测试,日志打印是否成功

		//测试AOP切面编程
		CountService countService=context.getBean(CountService.class);
		countService.add(2, 3);
		
		//关闭IOC容器:必须先转为子类ClassPathXmlApplicationContext对象后才能关闭
		((AbstractApplicationContext) context).close();

注意:如果被包装代理的类是继承了接口的,则@Service,@Controller@Component@Respository是加在被包装代理类上,

           而不是接口中。如果想让该接口的所有方法都被包装动态代理,则修改切面表达式如下。

           格式:@注解类型("execution(public * 包名.接口名.*(参数类型,..))")

二、XML文件方式进行AOP编程

1、导包:

                * com.springsource.net.sf.cglib-2.2.0.jar
                * com.springsource.org.aopalliance-1.0.0.jar
                * com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
                * spring-aspects-4.0.0.RELEASE.jar

2、在<beans>标签添加属性

        xmlns:aop="http://www.springframework.org/schema/aop"

     或者鼠标点击快速导入

                        Spring的AOP切面编程

3、添加待包装类和切面类(此时不用添加注解,使用的是XML文件方式)

package AOPXML;

public class CountService {
	public int add(int i,int j) {
		System.out.println("now["+i+","+j+"]");
		return i+j;
	}
	public int Div(int i,int j) throws Exception{
		System.out.println("now["+i+","+j+"]");
		return i/j;
	}
}
package AOPXML;

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;

/*
 * 日志切面类
 */
public class LoggingAspect {
	//前置通知
	public void beforeAdd(JoinPoint joinPoint) {
		String methodName=joinPoint.getSignature().getName();
		List<Object> list=Arrays.asList(joinPoint.getArgs());
		System.out.println("方法开始了,方法名:"+methodName+",方法列表"+list);
	}
	//后置通知
	public void afterAdd() {
		System.out.println("当前操作已执行完毕");
	}
	//返回通知
	public void returnAdd(Object result) {
		System.out.println("当前返回结果:"+result);
	}
	//异常通知
	public void exceptionDiv(Exception e) {
		System.out.println("异常信息:"+e.toString());
	}
}
/*
 * 验证切面类
 */
class ValidateAspect{
	//前置通知
	public void beforeAdd(JoinPoint joinPoint) {
		System.out.println("我是验证,我先开始");
	}
}

4、在XML文件里添加配置

	 <!-- AOPXML文件方式切面编程 -->
	 <!-- 配置服务类(待包装类) -->
	<bean id="countService" 
		class="AOPXML.CountService"></bean>

	<!-- 配置切面类bean. -->
	<bean id="loggingAspect"
		class="AOPXML.LoggingAspect"></bean>

	<bean id="vlidateAspect"
		class="AOPXML.ValidateAspect"></bean>

	<!-- 配置 AOP -->
	<aop:config>
		<!-- 配置切点表达式 -->
		<aop:pointcut expression="execution(* AOPXML.*.*(int, int))" 
			id="expressionOne"/>
		<!-- 配置切面及通知 -->
		<aop:aspect ref="loggingAspect" order="2">
			<aop:before method="beforeAdd" pointcut-ref="expressionOne"/>
			<aop:after method="afterAdd" pointcut-ref="expressionOne"/>
			<aop:after-throwing method="exceptionDiv" pointcut-ref="expressionOne" throwing="e"/>
			<aop:after-returning method="returnAdd" pointcut-ref="expressionOne" returning="result"/>
		</aop:aspect>	
		<aop:aspect ref="vlidateAspect" order="1">
			<aop:before method="beforeAdd" pointcut-ref="expressionOne"/>
		</aop:aspect>
	</aop:config>

5、调用方法测试,日志打印是否成功

		//测试AOP切面编程
		CountService countService=context.getBean(CountService.class);
		countService.add(2, 3);
		
		//关闭IOC容器:必须先转为子类ClassPathXmlApplicationContext对象后才能关闭
		((AbstractApplicationContext) context).close();
上一篇:AOP-错误:org.aspectj.runtime.internal.AroundClosure上的java.lang.*Error


下一篇:IOC,AOP,SpringAOP/AspectJ AOP