zoukankan      html  css  js  c++  java
  • Spring-Aop编程(三)-AspectJ

    AspectJ

    1. 介绍

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

    2.切入点表达式

      为了能够灵活定义切入点位置,Spring AOP提供了多种切入点指示符。

    execution———用来匹配执行方法的连接点

      语法结构:   execution(   方法修饰符  方法返回值  方法所属类 匹配方法名 (  方法中的形参表 )  方法申明抛出的异常  )

      其中红色字体的部分时不能省略的,各部分都支持通配符 “*” 来匹配全部

      比较特殊的为形参表部分,其支持两种通配符

    •   "*":代表一个任意类型的参数;
    •   “..”:代表零个或多个任意类型的参数。

      例如:

        ()匹配一个无参方法

        (..)匹配一个可接受任意数量参数和类型的方法

        (*)匹配一个接受一个任意类型参数的方法

        (*,Integer)匹配一个接受两个参数的方法,第一个可以为任意类型,第二个必须为Integer。

      下面举一些execution的使用实例:

    分类 示例 描述
    通过方法签名定义切入点 execution(public * * (..)) 匹配所有目标类的public方法,第一个*为返回类型,第二个*为方法名
    execution(* save* (..)) 匹配所有目标类以save开头的方法,第一个*代表返回类型
    execution(**product(*,String)) 匹配目标类所有以product结尾的方法,并且其方法的参数表第一个参数可为任意类型,第二个参数必须为String
    通过类定义切入点 execution(* aop_part.Demo1.service.*(..)) 匹配service接口及其实现子类中的所有方法
    通过包定义切入点 execution(* aop_part.*(..)) 匹配aop_part包下的所有类的所有方法,但不包括子包
    execution(* aop_part..*(..)) 匹配aop_part包下的所有类的所有方法,包括子包。(当".."出现再类名中时,后面必须跟“*”,表示包、子孙包下的所有类)
    execution(* aop_part..*.*service.find*(..)) 匹配aop_part包及其子包下的所有后缀名为service的类中,所有方法名必须以find为前缀的方法
    通过方法形参定义切入点 execution(*foo(String,int)) 匹配所有方法名为foo,且有两个参数,其中,第一个的类型为String,第二个的类型为int
    execution(* foo(String,..)) 匹配所有方法名为foo,且至少含有一个参数,并且第一个参数为String的方法(后面可以有任意个类型不限的形参)

    within————通过类匹配模式申明切入点(只能通过类型匹配连接点)

        例如:within(aop_part..*)             表示匹配包aop_part以及子包的所有方法

        由于execution可以匹配包、类、方法,而within只能匹配包、类,因此execution完全可以代替within的功能。


    this————限定AOP代理必须时指定类型的实例,用于匹配该对象的所有连接点

        例如:this(aop_part.service.GodService)        表示匹配了GodService接口的代理对象的所有连接点


    target————通过判断目标类的类型确定判断的是否匹配

        this通过判断代理类的类型来决定是否和切入点匹配,两者限定的对象都是指定类型的实例。

        例如: target(aop_part.service.GodService)      表示匹配实现了GodService接口的目标对象的所有连接点


    args————用于对连接点的参数类型进行限制,要求参数类型时指定类型的实例

        例如:args(aop_part.service)                     表示匹配时,出入的参数类型时service的方法

        其与execution(**(aop_part.service))的区别为,execution针对的时方法签名,而args针对的是运行时的实际参数类型。

        args既匹配buyGoods(service newService),也匹配buyGoods(Buyservice newService)   <Buyservice为service的子类>

        execution只匹配buyGoods(service newService)


    组合切入点

        支持 &&、 || 、!

        与其他语言所代表的意思相同

        例:args(aop_part.service)  &&execution(**(aop_part.service))

    3.AspectJ 通知类型

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

    aspectj 通知类型,只定义类型名称。已经方法格式。

    个数:6种,知道5种,掌握1中。

    before:前置通知(应用:各种校验)在方法执行前执行,如果通知抛出异常,阻止方法运行

    afterReturning:后置通知(应用:常规数据处理)方法正常返回后执行,如果方法中抛出异常,通知无法执行必须在方法执行后才执行,所以可以获得方法的返回值。

    around:环绕通知(应用:十分强大,可以做任何事情)方法执行前后分别执行,可以阻止方法的执行必须手动执行目标方法

    afterThrowing:抛出异常通知(应用:包装异常信息)方法抛出异常后执行,如果方法没有抛出异常,无法执行

    after:最终通知(应用:清理现场) 方法执行完毕后执行,无论方法中是否出现异常

    Spring Aop实例:

    方式一 :注解配置 

    UserService.java

    package com.zk.b_annotation;
    
    public interface UserService {
    	
    	public void addUser();
    	public String updateUser();
    	public void deleteUser();
    
    }
    

    UserServiceImpl.java

    package com.zk.b_annotation;
    
    import org.springframework.stereotype.Service;
    
    @Service("userServiceId")
    public class UserServiceImpl implements UserService {
    
    	@Override
    	public void addUser() {
    		System.out.println("d_aspect.b_anno addUser");
    	}
    
    	@Override
    	public String updateUser() {
    		System.out.println("d_aspect.b_anno updateUser");
    		int i = 1/ 0;
    		return "阳志就是";
    	}
    
    	@Override
    	public void deleteUser() {
    		
    		System.out.println("d_aspect.b_anno deleteUser");
    	}
    }
    

      

    切面

    MyAspect.java

    package com.zk.b_annotation;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.stereotype.Component;
    
    /**
     * 切面类,含有多个通知
     */
    @Component
    @Aspect
    public class MyAspect {
    	
    	//前置通知
    //	@Before("execution(* com.itheima.d_aspect.b_anno.UserServiceImpl.*(..))")
    @Before("myPointCut()") public void myBefore(JoinPoint joinPoint){ System.out.println("前置通知" + joinPoint.getSignature().getName()); } //声明公共切入点 @Pointcut("execution(* com.zk.b_annotation.UserServiceImpl.*(..))") private void myPointCut(){ } // @AfterReturning(value="myPointCut()" ,returning="ret")
    @AfterReturning("myPointCut()") public void myAfterReturning(JoinPoint joinPoint,Object ret){ System.out.println("后置通知" + joinPoint.getSignature().getName() + " , -->" + ret); } // @Around(value = "myPointCut()")
    @Around("myPointCut") public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{ System.out.println("前置通知"); //手动执行目标方法 Object obj = joinPoint.proceed(); System.out.println("后置通知"); return obj; } // @AfterThrowing(value="execution(* com.itheima.d_aspect.b_anno.UserServiceImpl.*(..))" ,throwing="e")
    @AfterThrowing("myPointCut()") public void myAfterThrowing(JoinPoint joinPoint,Throwable e){ System.out.println("抛出异常通知" + e.getMessage()); } @After("myPointCut()") public void myAfter(JoinPoint joinPoint){ System.out.println("后置通知"); } }

      

    beans.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.springframework.org/schema/context"
           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.xsd
           					   http://www.springframework.org/schema/context 
           					   http://www.springframework.org/schema/context/spring-context.xsd">
    	
    	<!-- 1.扫描 注解类 -->
    	<context:component-scan base-package="com.zk.b_annotation"></context:component-scan>
    	
    	<!-- 2.确定 aop注解生效 -->
    	<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    
    </beans>
    

      

    TestAspectAnno.java

    package com.zk.b_annotation;
    
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class TestAspectAnno {
    	
    	@Test
    	public void demo01(){
    		String xmlPath = "com/zk/b_annotation/beans.xml";
    		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
    		
    		//获得目标bean
    		UserService userService = (UserService) applicationContext.getBean("userServiceId");
    		userService.addUser();
    		userService.updateUser();
    		userService.deleteUser();
    	}
    
    }
    

      

    运行效果图:

    方式二:xml配置 

    UserService.java

    package com.itheima.d_aspect.a_xml;
    
    public interface UserService {
    	
    	public void addUser();
    	public String updateUser();
    	public void deleteUser();
    
    }
    

     

    UserServiceImpl.java

    package com.itheima.d_aspect.a_xml;
    
    public class UserServiceImpl implements UserService {
    
    	@Override
    	public void addUser() {
    		System.out.println("d_aspect.a_xml addUser");
    	}
    
    	@Override
    	public String updateUser() {
    		System.out.println("d_aspect.a_xml updateUser");
    		int i = 1/ 0;
    		return "阳志就是屌";
    	}
    
    	@Override
    	public void deleteUser() {
    		
    		System.out.println("d_aspect.a_xml deleteUser");
    	}
    
    }
    

      

    MyAspect.java

    package com.itheima.d_aspect.a_xml;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    
    /**
     * 切面类,含有多个通知
     */
    public class MyAspect {
    	
    	public void myBefore(JoinPoint joinPoint){
    		System.out.println("前置通知 : " + joinPoint.getSignature().getName());
    	}
    	
    	public void myAfterReturning(JoinPoint joinPoint,Object ret){
    		System.out.println("后置通知 : " + joinPoint.getSignature().getName() + " , -->" + ret);
    	}
    	
    	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("最终通知");
    	}
    
    }
    

      

    TestAspectXml.java

    package com.itheima.d_aspect.a_xml;
    
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class TestAspectXml {
    	
    	@Test
    	public void demo01(){
    		String xmlPath = "com/itheima/d_aspect/a_xml/beans.xml";
    		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
    		
    		//获得目标类
    		UserService userService = (UserService) applicationContext.getBean("userServiceId");
    		userService.addUser();
    		userService.updateUser();
    		userService.deleteUser();
    	}
    
    }
    

      

    beans.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: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.xsd">
    	<!-- 1 创建目标类 -->
    	<bean id="userServiceId" class="com.itheima.d_aspect.a_xml.UserServiceImpl"></bean>
    	<!-- 2 创建切面类(通知) -->
    	<bean id="myAspectId" class="com.itheima.d_aspect.a_xml.MyAspect"></bean>
    	<!-- 3 aop编程 
    		<aop:aspect> 将切面类 声明“切面”,从而获得通知(方法)
    			ref 切面类引用
    		<aop:pointcut> 声明一个切入点,所有的通知都可以使用。
    			expression 切入点表达式
    			id 名称,用于其它通知引用
    	-->
    	<aop:config>
    		<aop:aspect ref="myAspectId">
    			<aop:pointcut expression="execution(* com.itheima.d_aspect.a_xml.UserServiceImpl.*(..))" id="myPointCut"/>
    			
    			<!-- 3.1 前置通知 
    				<aop:before method="" pointcut="" pointcut-ref=""/>
    					method : 通知,及方法名
    					pointcut :切入点表达式,此表达式只能当前通知使用。
    					pointcut-ref : 切入点引用,可以与其他通知共享切入点。
    				通知方法格式:public void myBefore(JoinPoint joinPoint){
    					参数1:org.aspectj.lang.JoinPoint  用于描述连接点(目标方法),获得目标方法名等
    				例如:
    			
    			-->
    			<aop:before method="myBefore" pointcut-ref="myPointCut"/>
    			<!-- 3.2后置通知  ,目标方法后执行,获得返回值
    				<aop:after-returning method="" pointcut-ref="" returning=""/>
    					returning 通知方法第二个参数的名称
    				通知方法格式:public void myAfterReturning(JoinPoint joinPoint,Object ret){
    					参数1:连接点描述
    					参数2:类型Object,参数名 returning="ret" 配置的
    				例如:
    			
    			-->
    			<aop:after-returning method="myAfterReturning" pointcut-ref="myPointCut" returning="ret" />
    			<!-- 3.3 环绕通知 
    				<aop:around method="" pointcut-ref=""/>
    				通知方法格式:public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
    					返回值类型:Object
    					方法名:任意
    					参数:org.aspectj.lang.ProceedingJoinPoint
    					抛出异常
    				执行目标方法:Object obj = joinPoint.proceed();
    				例如:
    			
    			-->
    			<aop:around method="myAround" pointcut-ref="myPointCut"/>
    			<!-- 3.4 抛出异常
    				<aop:after-throwing method="" pointcut-ref="" throwing=""/>
    					throwing :通知方法的第二个参数名称
    				通知方法格式:public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
    					参数1:连接点描述对象
    					参数2:获得异常信息,类型Throwable ,参数名由throwing="e" 配置
    				例如:
    			
    			-->
    			<aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointCut" throwing="e"/>
    			<!-- 3.5 最终通知 -->			
    			<aop:after method="myAfter" pointcut-ref="myPointCut"/>
    			
    			
    			
    		</aop:aspect>
    	</aop:config>
    </beans>
    

      

    运行效果:

     

  • 相关阅读:
    MybatisPlus分页插件、常用查询
    object与map与json之间的相互转换
    MybatisPlus逻辑删除、执行性能
    MybatisPlus实现自动填充(表字段创建、修改时间自动填写)、version乐观锁
    Swagger2的使用
    uniapp小程序增加自定义字体
    新发安卓应用APP 怎么快速上应用市场 简单谈谈
    Android平台应用启动时读写手机存储、访问设备信息(如IMEI)等权限策略及提示信息
    ios真机调试,iTunes检测得到,hbuilder未检测到手机和模拟器的解决办法
    nohup命令
  • 原文地址:https://www.cnblogs.com/longlyseul/p/10023395.html
Copyright © 2011-2022 走看看