AspectJ(四)

        AspectJ是一个基于java语言的AOP框架。Spring2.0以后新增了对AspectJ切点表达式的支持。@AspectJ是AspectJ1.5新增功能,通过JDK5注解技术,允许直接在Bean类中定义切面。主要用途:自定义开发

切点表达式 

1.  execution()   用于描述方法

 语法:

     execution(修饰符    返回值   包.类.方法名(参数) throws 异常) 

​
​
​
     修饰符,一般省略

           public   公共方法

           *      任意

     返回值,不能省略

          void    没有返回值

          String    返回字符串

          *      任意

     包,【省略】

          com.dsx.crm   固定包

          com.dsx.crm.*.service..    crm包下面任意子包,固定目录service,service目录下任意包
          com.dsx.crm..            crm包下面的所有子包(包含自己所在的包)

     类,【省略】

          EmployeeServiceImp    指定类

          *Impl    以Impl结尾

          Emp*     以Emp开头

          *       任意

     方法名,不能省略

          add      固定方法

          *add    以add结尾

          add*    以add开头

           *         任意

     (参数)

          ()             无参

          (int)          一个整型

          (int,int)      两个

          (..)         参数任意

​    throws,可以省略。一般不写

 execution(修饰符    返回值   包.类.方法名(参数) throws 异常) 

 案例1 :

       execution(* com.dsx.crm.*.service..*.*(..))  

 案例2:

      <aop:pointcut expression="execution(* com.dsx.crm.*do.*(..))  || execution(* com.dsx.crm.*service.*(..)) " id=" " /> 

      ||  匹配以上两种切点任意一个都可以

了解部分:

   2. within:  匹配包或子包中的方法          within(com.dsx.aop..*)

   3. this:匹配实现接口的代理对象中的方法     this(com.dsx.aop.EmployeeDao)

   4. target: 匹配实现接口的目标对象中的方法   target(com.dsx.aop.UserDao)

   5. args: 匹配参数格式符合标准的方法             args(int,int)

   6. bean(id) : 对指定的bean所有的方法     bean(UserServiceId)

AspectJ通知类型

aop联盟定义通知类型,具有特定的接口,必须实现,从而确定方法名称。

aspectJ通知类型,只定义类型名称,以及方法格式。

before前置通知 (应用:各种校验)

              在方法执行前执行,如果通知抛出异常,阻止方法运行

afterReturning后置通知 (应用:常规数据处理)

              方法正常返回后执行,如果方法中抛出异常,通知无法执行

              必须在方法执行后才执行,所以可以获得方法的返回值。

around:环绕通知 (应用:十分强大,可以做任何事情)

              方法执行前后分别执行,可以阻止方法的执行

              必须手动执行目标方法

afterThrowing:抛出异常通知(应用:包装异常信息)

              方法抛出异常后执行,如果方法没有抛出异常,无法执行

after:最终通知(应用:清理现场)

              方法执行完毕后执行,无论方法中是否出现异常都会执行 

导入的jar包有:

基于xml的配置

目标类

package com.dsx.spring_aspectJ;

public interface EmployeeService {
	public void addEmployee();
	public void updateEmployee();
	public void deleteEmployee();
}
package com.dsx.spring_aspectJ;
//目标类
public class EmployeeServiceImp implements EmployeeService {

	@Override
	public void addEmployee() {
		System.out.println("执行了添加用户的方法");
	}

	@Override
	public void updateEmployee() {
		System.out.println("执行了updateEmployee的方法");
	}

	@Override
	public void deleteEmployee() {
		System.out.println("执行了deleteEmployee的方法");
		int i=1/0;
	}

}

切面类

package com.dsx.spring_aspectJ;

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

//切面类  应用Aspectj,含有多个通知,方法名可以是任意的
public class MyAspect {
	public void myBefore(JoinPoint joinPoint) {
		System.err.println("前置通知"+joinPoint.getSignature().getName());
	}
	public void myAfterReturning(JoinPoint joinPoint,Object object) {
		//第二个参数为返回值
		System.err.println("后置通知"+joinPoint.getSignature().getName());
		System.out.println("后置通知"+object);
	}
	public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable {
		System.out.println("环绕通知--前");
		//手动执行目标方法
		Object obj = joinPoint.proceed();
		System.out.println("环绕通知--后");
		return obj;
	}
	public void myAfterThrowing(JoinPoint joinPoint,Throwable e) {
		System.out.println("异常通知"+e.getMessage());
	}
	public void myAfter(JoinPoint joinPoint) {
		System.out.println("最终通知");
	}
}

spring配置

​
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns="http://www.springframework.org/schema/beans" 
  xmlns:p="http://www.springframework.org/schema/p" 
   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.2.xsd
  http://www.springframework.org/schema/aop 
  http://www.springframework.org/schema/aop/spring-aop.xsd">
  <!-- 业务类 -->
  <bean id="employeeServiceImp" class="com.dsx.spring_aspectJ.EmployeeServiceImp" />
  <!-- 切面类,通知 -->
  <bean id="myAspect" class="com.dsx.spring_aspectJ.MyAspect"/>
  <!-- aop编程
  	<aop:aspect>将切面类声明"切面",从而 获得通知(方法)
  	    ref:切面类引用
  	<aop:pointcut >声明一个切入点表达式,所有的通知都可以使用
  		expression切入点表达式
  		id:名称,用于其他通知的引用
   -->
  <aop:config>
  	<aop:aspect ref="myAspect">
  		<aop:pointcut expression="execution(* com.dsx.spring_aspectJ.EmployeeServiceImp.*(..))" id="myPointcut"/>
  		<!-- <aop:before 	method="通知,即方法名" 
  							pointcut="切入点表达式,此表达式只能当前通知使用" 
  							pointcut-ref="切入点引用,可以与其它通知共享切入点"/>
  		通知方法格式:public void myBefore(JoinPoint joinPoint) 
  			参数一:org.aspectj.lang.JoinPoint;用于描述连接点(目标方法),获得目标方法名等。					
  		-->
  		<aop:before method="myBefore" pointcut-ref="myPointcut"/>
  		<!-- 后置通知,目标方法后执行,获得返回值
  		<aop:after-returning method="通知,即方法名" 
  					pointcut-ref="切入点引用" 
  					returning="object"/>
  		通知方法的格式:public void myAfterReturning(JoinPoint joinPoint,Object object) {
  			参数一:连接点描述
  			参数二:返回值类型Object,参数名 returning="object"配置的
  		<aop:after-returning method="myAfterReturning" pointcut-ref="myPointcut" returning="object"/>
  		 -->
  		 <!-- 环绕通知
  		 通知方法的格式:public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable 
  		 	返回值类型:Object
  		 	方法名:任意
  		 	参数:org.aspectj.lang.ProceedingJoinPoint;
  		 	抛出异常:Throwable
  		 	执行目标方法:Object obj = joinPoint.proceed();
  		如:
  		<aop:around method="myAround" pointcut-ref="myPointcut"/>
  		  -->
  		<!-- 抛出异常
  		通知方法的格式:public void myAfterThrowing(JoinPoint joinPoint,Throwable e) 
  		参数一:连接点描述对象
  		参数二:获得异常信息,类型Throwable,参数名由throwing="e"配置
  		 如: 
  		<aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointcut" throwing="e"/>
  	   -->
  	   <!-- 最终通知,无论是否有异常,都会执行
  		   通知方法的格式:public void myAfter(JoinPoint joinPoint)
  	  	 如:
  		  <aop:after method="myAfter" pointcut-ref="myPointcut"/>
  	    -->
  	</aop:aspect>
  </aop:config>

</beans>

​

测试类

package com.dsx.spring_aspectJ;

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

public class AspectJTest {
@Test
public void test1() {
	ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("com/dsx/spring_aspectJ/bean.xml");
	EmployeeService employeeServiceImp = (EmployeeService) context.getBean("employeeServiceImp");
	employeeServiceImp.addEmployee();
	employeeServiceImp.deleteEmployee();
}

}

在对通知类型进行测试时,建议一个一个类型的去测试,更利于我们的理解。

基于注解的配置

spring的配置

切面类

package com.dsx.spring_aspectJ2;

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

//切面类  应用Aspectj,含有多个通知,方法名可以是任意的
@Component
@Aspect //声明为切面类
public class MyAspect {
	//为了方便书写,声明一个公共的切入点
	@Pointcut("execution(* com.dsx.spring_aspectJ2.EmployeeServiceImp.*(..))")
	public void myPointCut() {}
	
//	@Before(value="myPointCut()")
	@Before("execution(* com.dsx.spring_aspectJ2.EmployeeServiceImp.*(..))")
	public void myBefore(JoinPoint joinPoint) {
		System.err.println("前置通知"+joinPoint.getSignature().getName());
	}
	@AfterReturning(value="myPointCut()",returning="object")
	public void myAfterReturning(JoinPoint joinPoint,Object object) {
		//第二个参数为返回值
		System.err.println("后置通知"+joinPoint.getSignature().getName());
		System.out.println("后置通知"+object);
	}
	@Around(value="myPointCut()")
	public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable {
		System.out.println("环绕通知--前");
		//手动执行目标方法
		Object obj = joinPoint.proceed();
		System.out.println("环绕通知--后");
		return obj;
	}
	@AfterThrowing(value="myPointCut()",throwing="e")
	public void myAfterThrowing(JoinPoint joinPoint,Throwable e) {
		System.out.println("异常通知"+e.getMessage());
	}
	@After(value="myPointCut()")
	public void myAfter(JoinPoint joinPoint) {
		System.out.println("最终通知");
	}
}

AspectJ属于静态AOP代理的增强,在项目中,我们一般都采用注解的方式去实现。用来完成自定义的功能的开发。

如有不足,欢迎留言指正。望不吝赐教。。。

发布了171 篇原创文章 · 获赞 1 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/duan196_118/article/details/104829463