Spring使用AspectJ开发AOP:基于Annotation

基于 Annotation 的声明式

在 Spring 中,尽管使用 XML 配置文件可以实现 AOP 开发,但是如果所有的相关的配置都集中在配置文件中,势必会导致 XML 配置文件过于臃肿,从而给维护和升级带来一定的困难。

为此,AspectJ 框架为 AOP 开发提供了另一种开发方式——基于 Annotation 的声明式。AspectJ 允许使用注解定义切面、切入点和增强处理,而 Spring 框架则可以识别并根据这些注解生成 AOP 代理。

关于 Annotation 注解的介绍如表 1 所示。

表 1 Annotation 注解介绍
名称 说明
@Aspect 用于定义一个切面。
@Before 用于定义前置通知,相当于 BeforeAdvice。
@AfterReturning 用于定义后置通知,相当于 AfterReturningAdvice。
@Around 用于定义环绕通知,相当于MethodInterceptor。
@AfterThrowing 用于定义抛出通知,相当于ThrowAdvice。
@After 用于定义最终final通知,不管是否异常,该通知都会执行。
@DeclareParents 用于定义引介通知,相当于IntroductionInterceptor(不要求掌握)。

下面使用注解的方式重新实现《基于XML的声明式》部分的功能。

1. 创建切面类 MyAspect

在 src 目录下创建一个名为 com.mengma.aspectj.annotation 的包,在该包下创建一个切面类 MyAspect,如下所示。

package com.mengma.aspectj.annotation;

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;

//切面类
@Aspect
@Component
public class MyAspect {
// 用于取代:<aop:pointcut
// expression="execution(*com.mengma.dao..*.*(..))" id="myPointCut"/>
// 要求:方法必须是private,没有值,名称自定义,没有参数
@Pointcut("execution(*com.mengma.dao..*.*(..))")
private 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("后置通知,方法名称:" + 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("最终通知");
}
}

上述代码中,第 13 行 @Aspect 注解用于声明这是一个切面类,该类作为组件使用,所以要添加 @Component 注解才能生效。第 19 行中 @Poincut 注解用于配置切入点,取代 XML 文件中配置切入点的代码。

在每个通知相应的方法上都添加了注解声明,并且将切入点方法名“myPointCut”作为参数传递给要执行的方法,如需其他参数(如异常通知的异常参数),可以根据代码提示传递相应的属性值。

2. 为目标类添加注解

在 com.mengma.dao.CustomerDaoImpl 目标类中添加注解 @Repository("customerDao")。

import org.springframework.stereotype.Repository;
@Repository("customerDao")
public class CustomerDao {
    public void doSome(){
       // int i=1/0;
        System.out.println("正式业务");
    }
}

3. 创建Spring配置文件

在 com.mengma.aspectj.annotation 包下创建 applicationContext.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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--扫描含com.mengma包下的所有注解-->
<context:component-scan base-package="com.mengma"/>
<!-- 使切面开启自动代理 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

上述代码中,首先导入了 AOP 命名空间及其配套的约束,使切面类中的 @AspectJ 注解能够正常工作;第 13 行代码添加了扫描包,使注解生效。需要注意的是,这里还包括目标类 com.mengma.dao.CustomerDaoImpl 的注解,所以 base-package 的值为 com.mengma;第 15 行代码的作用是切面开启自动代理。

4. 创建测试类

在 com.mengma.aspectj.annotation 包下创建一个名为 AnnotationTest 的测试类,如下所示。

package com.mengma.aspectj.annotation;

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

import com.mengma.dao.CustomerDao;

public class AnnotationTest {
@Test
public void test() {
String xmlPath = "com/mengma/aspectj/xml/applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
xmlPath);
// 从spring容器获取实例
CustomerDao customerDao = (CustomerDao) applicationContext
.getBean("customerDao");
// 执行方法
customerDao.add();
}
}

5. 运行项目并查看结果

使用 JUnit 测试运行 test() 方法,运行成功后,控制台的输出结果如图 3 所示。


图 3  运行结果

删除 add() 方法中的“int i=1/0;”,重新运行 test() 方法,此时控制台的输出结果如图 4 所示。


图 4  运行结果

从图 3 和图 4 的输出结果中可以看出,已成功使用 Annotation 的方式实现了 AOP 开发。与其他方式相比,基于 Annotation 方式实现 AOP 的效果是最方便的方式,所以实际开发中推荐使用注解的方式。

原文地址:https://www.cnblogs.com/lowerma/p/11762100.html

时间: 2024-10-07 01:16:54

Spring使用AspectJ开发AOP:基于Annotation的相关文章

(转)Spring使用AspectJ进行AOP的开发:注解方式

http://blog.csdn.net/yerenyuan_pku/article/details/69790950 Spring使用AspectJ进行AOP的开发:注解方式 之前我已讲过Spring使用AspectJ通过配置文件的方式来进行AOP的开发,现在就来讲怎样使用注解方式进行AOP的开发. 创建一个Web项目, 引入相关的jar包.所要导入的jar包如下:  引入Spring的配置文件.主要引入AOP的约束: <?xml version="1.0" encoding=

Spring的AspectJ的AOP,基于注解(9.1)重点掌握

什么是AspectJ AspectJ是一个面向切面的框架,它扩展了Java语言.AspectJ定义了AOP语法所以它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件.AspectJ是一个基于Java语言的AOP框架Spring2.0以后新增了对AspectJ切点表达式支持@AspectJ 是AspectJ1.5新增功能,通过JDK5注解技术,允许直接在Bean类中定义切面新版本Spring框架,建议使用AspectJ方式来开发AOP AspectJ表达式: 语法:executi

Spring Security应用开发(19)基于方法的授权(三)AOP

本文介绍使用AOP的配置方式来实现基于方法的授权. (1)首先使用Spring Security提供的protect-pointcut进行配置. protect-pointcut结点配置访问符合指定条件的方法锁需要的角色列表. <!-- 使用AOP的方式来定义方法级别的访问控制 --> <sec:global-method-security> <sec:protect-pointcut access="ROLE_USER,ROLE_ADMIN" expre

Spring注解驱动开发-AOP、Tx和Servlet3.0

1 AOP 1.1 什么是AOP? 在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式. 底层就是动态代理. 1.2 AOP的应用 步骤: ①定义一个目标类以及目标方法. ②定义一个切面类,以及前置通知.后置通知等,使用各自的注解将通知织入到目标方法上. ③将目标类和切面类注册到容器中. ④在切面类上标注@Aspect注解,来告诉Spring这是一个切面类. ⑤在配置类上加上@EnableAspectJAutoProxy开启AspectJ自动代理. 示例: MathCalcu

spring与hibernate整合配置基于Annotation注解方式管理实务

1.配置数据源 数据库连接基本信息存放到properties文件中,因此先加载properties文件 1 <!-- jdbc连接信息 --> 2 <context:property-placeholder 3 location="classpath:io/shuqi/ssh/spring/transactionalAnnotation/jdbc.properties"/> 使用DBCP数据源配置xml如下 1 <!-- dbcp数据源配置 -->

Spring注解驱动开发--AOP功能测试

前言 Spring的AOP指的是在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式[动态代理]. AOP功能测试 ①导入AOP模块 <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>4.3.12.RELEASE</version> </depend

Spring Security应用开发(16)基于表达式的访问控制

1.1.1. 通用表达式 Spring Security 使用基于Spring EL的表达式来进行访问控制.内置的表达式如下表所示: 表达式 描述 hasRole(role) 当前主体(principal)是否支持role角色.支持则返回true hasAnyRole(role1,role2) 当前主体是否支持role1,role2中的任意一个角色. hasAuthority(authority) 跟hasRole(role)相似. hasAnyAuthority(authority1,auth

Spring Security应用开发(21)基于方法的授权(五)使用@Secured注解

Spring Security提供了@Secured注解来实现基于方法的授权控制. @Secured注解可以指定一个字符串数组参数作为value的值,表示当前用户具备这些角色中的任何一个角色即可满足授权条件. (1)启用@Secured注解. <sec:global-method-security secured-annotations="enabled" /> (2)使用Secured注解. //getUserByName()方法可以被具备ROLE_ADMIN或者ROLE

Spring Security应用开发(17)基于方法的授权(一)评估

Spring Security提供了4个用于方法的注解: @PreAuthorize.@PostAuthorize.@PreFilter和@PostFilter.本文介绍前面2个注解. @PreAuthorize 使用Spring Security的表达式来在方法执行之前控制允许执行某个方法. 如果表达式评估结果为false,则该方法不会被执行.@PreAuthorize的表达式通常是对方法的参数进行检查. @PostAuthorize 使用Spring Security的表达式在方法执行之后控