spring aop aspect

本文介绍了一个使用Spring AOP实现的实战案例,展示了如何通过定义切面来增强目标类中的sayHello方法,包括前置通知、后置通知、异常通知、返回通知及环绕通知等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

package test;

/**
*
* @author neu_20063500
*
*/
public class HelloWorld {

public void sayHello(String helloworld) {
System.out.println(helloworld);
throw new RuntimeException();
//这个异常是拿来测试,可有可无
}
}
package test;

/**
*
* @author neu_20063500
*
*/
public class HelloWorld {

public void sayHello(String helloworld) {
System.out.println(helloworld);
throw new RuntimeException();
//这个异常是拿来测试,可有可无
}
}


想使用AOP去处理这个sayHello方法

那么我们定义切面

view plaincopy to clipboardprint?
package test;

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;

/**
*
* @author neu_20063500
*
*/
@Aspect
public class AspectS {

// execution最常用,可以通过 & || !进行切入点表达式的连接
// 可是是表达式,可以通过切入点标识重用表达式
@Pointcut("execution(public void test.HelloWorld.sayHello(String))")
public void helloworld() {
}

@Before("execution(public void test.HelloWorld.sayHello(String))")
public void beforeSayHello() {
System.out.println("before sayHello");
}

@After("helloworld()")
public void afterSayHello() {
System.out.println("after sayHello");
}

@AfterThrowing("test.AspectS.helloworld()")
public void exceptionSayHello() {
System.out.println("throw runtime exception");
}

@AfterReturning("test.AspectS.helloworld()")
public void returnSayHello() {
System.out.println("method has returned");
}

@Around("test.AspectS.helloworld()")
public Object aroundSayHello(ProceedingJoinPoint pjp) {
Object obj = null;
try {
System.out.println("around start");
obj = pjp.proceed();
System.out.println("around end");
} catch (Throwable e) {
e.printStackTrace();
}
return obj;
}

/*

任意公共方法的执行:

execution(public * *(..))
任何一个以“set”开始的方法的执行:

execution(* set*(..))
AccountService 接口的任意方法的执行:

execution(* com.xyz.service.AccountService.*(..))
定义在service包里的任意方法的执行:

execution(* com.xyz.service.*.*(..))
定义在service包或者子包里的任意方法的执行:

execution(* com.xyz.service..*.*(..))
在service包里的任意连接点(在Spring AOP中只是方法执行) :

within(com.xyz.service.*)
在service包或者子包里的任意连接点(在Spring AOP中只是方法执行) :

within(com.xyz.service..*)
实现了 AccountService 接口的代理对象的任意连接点(在Spring AOP中只是方法执行) :

this(com.xyz.service.AccountService)
'this'在binding form中用的更多:- 请常见以下讨论通知的章节中关于如何使得代理对象可以在通知体内访问到的部分。
实现了 AccountService 接口的目标对象的任意连接点(在Spring AOP中只是方法执行) :

target(com.xyz.service.AccountService)
'target'在binding form中用的更多:- 请常见以下讨论通知的章节中关于如何使得目标对象可以在通知体内访问到的部分。
任何一个只接受一个参数,且在运行时传入的参数实现了 Serializable 接口的连接点 (在Spring AOP中只是方法执行)

args(java.io.Serializable)
'args'在binding form中用的更多:- 请常见以下讨论通知的章节中关于如何使得方法参数可以在通知体内访问到的部分。
请注意在例子中给出的切入点不同于 execution(* *(java.io.Serializable)): args只有在动态运行时候传入参数是可序列化的(Serializable)才匹配,而execution 在传入参数的签名声明的类型实现了 Serializable 接口时候匹配。

有一个 @Transactional 注解的目标对象中的任意连接点(在Spring AOP中只是方法执行)

@target(org.springframework.transaction.annotation.Transactional)
'@target' 也可以在binding form中使用:请常见以下讨论通知的章节中关于如何使得annotation对象可以在通知体内访问到的部分。
任何一个目标对象声明的类型有一个 @Transactional 注解的连接点(在Spring AOP中只是方法执行)

@within(org.springframework.transaction.annotation.Transactional)
'@within'也可以在binding form中使用:- 请常见以下讨论通知的章节中关于如何使得annotation对象可以在通知体内访问到的部分。
任何一个执行的方法有一个 @Transactional annotation的连接点(在Spring AOP中只是方法执行)

@annotation(org.springframework.transaction.annotation.Transactional)
'@annotation' 也可以在binding form中使用:- 请常见以下讨论通知的章节中关于如何使得annotation对象可以在通知体内访问到的部分。
任何一个接受一个参数,并且传入的参数在运行时的类型实现了 @Classified annotation的连接点(在Spring AOP中只是方法执行)

@args(com.xyz.security.Classified)
'@args'也可以在binding form中使用:- 请常见以下讨论通知的章节中关于如何使得annotation对象可以在通知体内访问到的部分。

*/
}
package test;

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;

/**
*
* @author neu_20063500
*
*/
@Aspect
public class AspectS {

// execution最常用,可以通过 & || !进行切入点表达式的连接
// 可是是表达式,可以通过切入点标识重用表达式
@Pointcut("execution(public void test.HelloWorld.sayHello(String))")
public void helloworld() {
}

@Before("execution(public void test.HelloWorld.sayHello(String))")
public void beforeSayHello() {
System.out.println("before sayHello");
}

@After("helloworld()")
public void afterSayHello() {
System.out.println("after sayHello");
}

@AfterThrowing("test.AspectS.helloworld()")
public void exceptionSayHello() {
System.out.println("throw runtime exception");
}

@AfterReturning("test.AspectS.helloworld()")
public void returnSayHello() {
System.out.println("method has returned");
}

@Around("test.AspectS.helloworld()")
public Object aroundSayHello(ProceedingJoinPoint pjp) {
Object obj = null;
try {
System.out.println("around start");
obj = pjp.proceed();
System.out.println("around end");
} catch (Throwable e) {
e.printStackTrace();
}
return obj;
}

/*

任意公共方法的执行:

execution(public * *(..))
任何一个以“set”开始的方法的执行:

execution(* set*(..))
AccountService 接口的任意方法的执行:

execution(* com.xyz.service.AccountService.*(..))
定义在service包里的任意方法的执行:

execution(* com.xyz.service.*.*(..))
定义在service包或者子包里的任意方法的执行:

execution(* com.xyz.service..*.*(..))
在service包里的任意连接点(在Spring AOP中只是方法执行) :

within(com.xyz.service.*)
在service包或者子包里的任意连接点(在Spring AOP中只是方法执行) :

within(com.xyz.service..*)
实现了 AccountService 接口的代理对象的任意连接点(在Spring AOP中只是方法执行) :

this(com.xyz.service.AccountService)
'this'在binding form中用的更多:- 请常见以下讨论通知的章节中关于如何使得代理对象可以在通知体内访问到的部分。
实现了 AccountService 接口的目标对象的任意连接点(在Spring AOP中只是方法执行) :

target(com.xyz.service.AccountService)
'target'在binding form中用的更多:- 请常见以下讨论通知的章节中关于如何使得目标对象可以在通知体内访问到的部分。
任何一个只接受一个参数,且在运行时传入的参数实现了 Serializable 接口的连接点 (在Spring AOP中只是方法执行)

args(java.io.Serializable)
'args'在binding form中用的更多:- 请常见以下讨论通知的章节中关于如何使得方法参数可以在通知体内访问到的部分。
请注意在例子中给出的切入点不同于 execution(* *(java.io.Serializable)): args只有在动态运行时候传入参数是可序列化的(Serializable)才匹配,而execution 在传入参数的签名声明的类型实现了 Serializable 接口时候匹配。

有一个 @Transactional 注解的目标对象中的任意连接点(在Spring AOP中只是方法执行)

@target(org.springframework.transaction.annotation.Transactional)
'@target' 也可以在binding form中使用:请常见以下讨论通知的章节中关于如何使得annotation对象可以在通知体内访问到的部分。
任何一个目标对象声明的类型有一个 @Transactional 注解的连接点(在Spring AOP中只是方法执行)

@within(org.springframework.transaction.annotation.Transactional)
'@within'也可以在binding form中使用:- 请常见以下讨论通知的章节中关于如何使得annotation对象可以在通知体内访问到的部分。
任何一个执行的方法有一个 @Transactional annotation的连接点(在Spring AOP中只是方法执行)

@annotation(org.springframework.transaction.annotation.Transactional)
'@annotation' 也可以在binding form中使用:- 请常见以下讨论通知的章节中关于如何使得annotation对象可以在通知体内访问到的部分。
任何一个接受一个参数,并且传入的参数在运行时的类型实现了 @Classified annotation的连接点(在Spring AOP中只是方法执行)

@args(com.xyz.security.Classified)
'@args'也可以在binding form中使用:- 请常见以下讨论通知的章节中关于如何使得annotation对象可以在通知体内访问到的部分。

*/
}


然后定义配置文件,注意将切面对象和实体对象交给Spring管理:

view plaincopy to clipboardprint?
<?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" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-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/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<context:annotation-config />
<aop:aspectj-autoproxy />
<bean id="aspects" class="test.AspectS"></bean>
<bean id="helloworld" class="test.HelloWorld"></bean>
</beans>
<?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" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-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/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<context:annotation-config />
<aop:aspectj-autoproxy />
<bean id="aspects" class="test.AspectS"></bean>
<bean id="helloworld" class="test.HelloWorld"></bean>
</beans>

然后使用客户端调用:

view plaincopy to clipboardprint?
package test;

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

public class Client {

public static void main(String[] args) {
ApplicationContext cx = new ClassPathXmlApplicationContext(
"applicationContext.xml");
HelloWorld bean = (HelloWorld)cx.getBean("helloworld");
bean.sayHello("hello world");
}
}
package test;

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

public class Client {

public static void main(String[] args) {
ApplicationContext cx = new ClassPathXmlApplicationContext(
"applicationContext.xml");
HelloWorld bean = (HelloWorld)cx.getBean("helloworld");
bean.sayHello("hello world");
}
}


当sayHello没有抛出异常时,执行结果是:

view plaincopy to clipboardprint?
before sayHello
around start
hello world
after sayHello
method has returned
around end
before sayHello
around start
hello world
after sayHello
method has returned
around end

当sayHello执行抛出异常时候,执行结果是

view plaincopy to clipboardprint?
around start
hello world
after sayHello
throw runtime exception
around start
hello world
after sayHello
throw runtime exception

给出一个比较典型和常用的切点:

view plaincopy to clipboardprint?
package test;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class SystemArchitecture {

/**
* A join point is in the web layer if the method is defined in a type in
* the com.xyz.someapp.web package or any sub-package under that.
*/
@Pointcut("within(com.xyz.someapp.web..*)")
public void inWebLayer() {
}

/**
* A join point is in the service layer if the method is defined in a type
* in the com.xyz.someapp.service package or any sub-package under that.
*/
@Pointcut("within(com.xyz.someapp.service..*)")
public void inServiceLayer() {
}

/**
* A join point is in the data access layer if the method is defined in a
* type in the com.xyz.someapp.dao package or any sub-package under that.
*/
@Pointcut("within(com.xyz.someapp.dao..*)")
public void inDataAccessLayer() {
}

/**
* A business service is the execution of any method defined on a service
* interface. This definition assumes that interfaces are placed in the
* "service" package, and that implementation types are in sub-packages.
*
* If you group service interfaces by functional area (for example, in
* packages com.xyz.someapp.abc.service and com.xyz.def.service) then the
* pointcut expression "execution(* com.xyz.someapp..service.*.*(..))" could
* be used instead.
*/
@Pointcut("execution(* com.xyz.someapp.service.*.*(..))")
public void businessService() {
}

/**
* A data access operation is the execution of any method defined on a dao
* interface. This definition assumes that interfaces are placed in the
* "dao" package, and that implementation types are in sub-packages.
*/
@Pointcut("execution(* com.xyz.someapp.dao.*.*(..))")
public void dataAccessOperation() {
}
}


本文来自优快云博客,转载请标明出处:http://blog.youkuaiyun.com/neusoftware_20063500/archive/2009/04/27/4129957.aspx
资源下载链接为: https://pan.quark.cn/s/22ca96b7bd39 在当今的软件开发领域,自动化构建与发布是提升开发效率和项目质量的关键环节。Jenkins Pipeline作为一种强大的自动化工具,能够有效助力Java项目的快速构建、测试及部署。本文将详细介绍如何利用Jenkins Pipeline实现Java项目的自动化构建与发布。 Jenkins Pipeline简介 Jenkins Pipeline是运行在Jenkins上的一套工作流框架,它将原本分散在单个或多个节点上独立运行的任务串联起来,实现复杂流程的编排与可视化。它是Jenkins 2.X的核心特性之一,推动了Jenkins从持续集成(CI)向持续交付(CD)及DevOps的转变。 创建Pipeline项目 要使用Jenkins Pipeline自动化构建发布Java项目,首先需要创建Pipeline项目。具体步骤如下: 登录Jenkins,点击“新建项”,选择“Pipeline”。 输入项目名称和描述,点击“确定”。 在Pipeline脚本中定义项目字典、发版脚本和预发布脚本。 编写Pipeline脚本 Pipeline脚本是Jenkins Pipeline的核心,用于定义自动化构建和发布的流程。以下是一个简单的Pipeline脚本示例: 在上述脚本中,定义了四个阶段:Checkout、Build、Push package和Deploy/Rollback。每个阶段都可以根据实际需求进行配置和调整。 通过Jenkins Pipeline自动化构建发布Java项目,可以显著提升开发效率和项目质量。借助Pipeline,我们能够轻松实现自动化构建、测试和部署,从而提高项目的整体质量和可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值