栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

AspectJ开发

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

AspectJ开发

AspectJ是一个基于Java语言的AOP框架,它提供了强大的AOP功能。

使用AspectJ实现AOP有两种方式:

  • 基于XML的声明式AspectJ
  • 基于注解的声明式AspectJ

基于XML的声明式AspectJ

基于XML的声明式AspectJ是指通过XML文件来定义切面、切入点及通知,所有的切面、切入点和通知都必须定义在元素内。

Spring配置文件中的元素中可以包含多个元素,一个 元素中又可以包含属性和子元素,其子元素包括元素下,同样包含了属性和多个子元素,通过使用元素及其子元素就可以在XML文件中配置切面、切入点和通知。

配置切面

在Spring的配置文件中,配置切面使用的是  元素,该元素会将一个已定义好的Spring Bean转换成切面Bean,所以要在配置文件中先定义一个普通的Spring Bean,最后通过元素的ref属性即可引用该Bean。

属性名称描述
id用于定义该切面的唯一标识
ref用于引用普通的Spring Bean

配置切入点

在Spring的配置文件中,切入点是通过元素来定义的。

当元素作为元素的子元素时,表示该切入点是全局切入点,它可被多个切面所共享;

当元素作为元素的子元素时, 表示该切入点只对当前切面有效。

当元素写到的外部时,就变成了所有的切面都可使用,但是要想写在外面必须写在元素的上方。

属性名称描述
id用于指定切入点的唯一标识名称
expression用于指定切入点关联的切入点表达式
        
       
            
     

该切入点表达式的含义是:匹配 cn.itcast.service.Impl 包中任意类的任意方法的执行

execution():是方法的主体

第一个 * :返回的类型,使用 * 表示代表所有类型

后面的包名:表示需要拦截的包名

第二个 * :表示类名,使用 * 表示所有的类

第三个 * :表示方法,使用 * 表示所有的方法

. . :表示方法的参数,这里表示任意参数

需要注意的是:第一个 * 与 包名之间有一个空格

配置通知

在配置代码中,分别使用 的子元素配置了5种常用通知

通知的常用属性及其描述
属性名称描述
pointcut用于指定一个切入点表达式
pointcut-ref指定一个已经存在的切入点名称,即pointcut中的id的值
method最终通知,无论切入点方法是否正常执行它都会在其后面执行
throwing异常通知,在切入点方法执行产生异常之后执行。注:它和后置通知永远只能执行一个
returning后置通知,在切入点方法执行之后执行。注:它和异常通知永远只能执行一个

部分代码如下:

//切面  在此类中编写通知


public class MyAspect {

    //前置通知
    public void myBefore(JoinPoint joinPoint) {
        System.out.print(" 前置通知:模拟执行权限检查. . . , ");
        System.out.print(" 目标类是: " + joinPoint.getTarget());
        System.out.println("被植入增强处理的目标方法为: " + joinPoint.getSignature().getName());
    }

    //后置通知
    public void myAfterReturning(JoinPoint joinPoint) {
        System.out.print(" 后置通知:模拟记录日志. . . ,");
        System.out.println(" 被植入增强处理的目标方法为: " + joinPoint.getSignature().getName());
    }

    
    public Object myAround(ProceedingJoinPoint proceedingJoinPoint)
            throws Throwable {
        //开始
        System.out.println("环绕开始:执行目标方法之前,模拟开启事务. . .");
        //执行当前门标
        Object obj = proceedingJoinPoint.proceed();
        //结束
        System.out.println("环绕结束 执行门标方法之后 模拟关闭事务.. ");
        return obj;
    }

    //异常通知
    public void myAfterThrowing(JoinPoint joinPoint, Throwable e) {
        System.out.println("异常通知:" + "出错了" + e.getMessage());
    }

    //最终通知
    public void myAfter() {
        System.out.println("最终通知 模拟方法结束后的释放资源 . . ");
    }

}
    
    

    
    

    
    
    
        
        
            
            
            
            

            
            

            
            

            
            

            
            
            
        
    
 前置通知:模拟执行权限检查. . . ,  目标类是: com.dfbz.aspectj.dao.Impl.UserDaoImpl@d706f19被植入增强处理的目标方法为: addUser
环绕开始:执行目标方法之前,模拟开启事务. . .
添加用户
最终通知 模拟方法结束后的释放资源 . . 
环绕结束 执行门标方法之后 模拟关闭事务.. 
 后置通知:模拟记录日志. . . , 被植入增强处理的目标方法为: addUser
 前置通知:模拟执行权限检查. . . ,  目标类是: com.dfbz.aspectj.dao.Impl.UserDaoImpl@4b7dc788被植入增强处理的目标方法为: addUser
环绕开始:执行目标方法之前,模拟开启事务. . .
最终通知 模拟方法结束后的释放资源 . . 
异常通知:出错了/ by zero

基于注解的声明式AspectJ

基于XML的声明式AspectJ要便捷,但是也有一些缺点,就是在Spring配置文件中需要配置大量的代码信息。

AspectJ框架为AOP的实现提供了一套注解。

AspectJ的注解及其描述
注解名称描述
@Aspect用来定义一个切面
@Pointcut用来定义切入点表达式
@Before用来定义前置通知
@AfterReturning用来定义后置通知
@Around用来定义环绕通知
@AfterThrowing用来定义异常通知
@After用来定义最终通知

部分代码如下:

//切面  在此类中编写通知
@Aspect
@Component
public class MyAspect {

    //切入点表达式
    @Pointcut("execution(* com.dfbz.dao.Impl.*.*(..))")
    //切入点
    public void myPointCut(){}




    //前置通知
    @Before("myPointCut()")
    public void myBefore(JoinPoint joinPoint) {
        System.out.print(" 前置通知:模拟执行权限检查. . . , ");
        System.out.print(" 目标类是: " + joinPoint.getTarget());
        System.out.println("被植入增强处理的目标方法为: " + joinPoint.getSignature().getName());
    }

    //后置通知
    @AfterReturning(value = "myPointCut()")
    public void myAfterReturning(JoinPoint joinPoint) {
        System.out.print(" 后置通知:模拟记录日志. . . ,");
        System.out.println(" 被植入增强处理的目标方法为: " + joinPoint.getSignature().getName());
    }

    
    @Around("myPointCut()")
    public Object myAround(ProceedingJoinPoint proceedingJoinPoint)
            throws Throwable {
        //开始
        System.out.println("环绕开始:执行目标方法之前,模拟开启事务. . .");
        //执行当前门标
        Object obj = proceedingJoinPoint.proceed();
        //结束
        System.out.println("环绕结束 执行门标方法之后 模拟关闭事务.. ");
        return obj;
    }

    //异常通知
    @AfterThrowing(value = "myPointCut()",throwing = "e")
    public void myAfterThrowing(JoinPoint joinPoint, Throwable e) {
        System.out.println("异常通知:" + "出错了" + e.getMessage());
    }

    //最终通知
    @After("myPointCut()")
    public void myAfter() {
        System.out.println("最终通知 模拟方法结束后的释放资源 . . ");
    }
}

目标对象类需要添加注解 :

@Repository("userDao")

配置文件如下:

    
    

    
    

运行结果如下:

环绕开始:执行目标方法之前,模拟开启事务. . .
 前置通知:模拟执行权限检查. . . ,  目标类是: com.dfbz.dao.Impl.UserDaoImpl@765d7657被植入增强处理的目标方法为: addUser
添加用户
环绕结束 执行门标方法之后 模拟关闭事务.. 
最终通知 模拟方法结束后的释放资源 . . 
 后置通知:模拟记录日志. . . , 被植入增强处理的目标方法为: addUser

注意:

如果在同一个连接点有多个通知需要执行,那么在同一切面中,目标方法之前的前置通知和环绕通知的执行顺序是未知的;目标方法之后的后置通知和环绕通知的执行顺序也是未知的。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/530919.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号