spring-aop学习【基于注解】
我个人觉得,这个好像就是用在定制日志输出上,和log4j很像。
用途:
如果业务方法调用每一步都需要详细的日志,那就用这个吧
好处就是:
方便维护,只包含业务代码
下面开始说明:
所需要的jar包:
com.springsource.net.sf.cglib-2.2.0.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
commons-logging-1.1.1.jar
spring-aop-4.0.0.RELEASE.jar
spring-aspects-4.0.0.RELEASE.jar
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar
spring-expression-4.0.0.RELEASE.jar
直接上代码:
声明一个接口
package com.spring.bean.aop; import java.util.List; /** * * @author Administrator * */ public interface UserService { // 打招呼 void say(); // 获取年龄 int getValue(List<Integer> array,int index); }
这是接口的实现类
package com.spring.bean.aop; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * * @author Administrator * 实现类 */ @Service("userService") public class UserServiceImpl implements UserService { /** * 自动装配use对象 */ @Autowired private User user; @Override public void say() { // TODO Auto-generated method stub System.out.println("我叫"+user.getName()+",今年"+user.getAge()+"岁,你好!!"); } @Override public int getValue(List<Integer> array, int index) { // TODO Auto-generated method stub return array.get(index); } }
用户对象信息
package com.spring.bean.aop; import org.springframework.stereotype.Component; /** * @author Administrator * 用户信息 */ @Component public class User { String name; int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
然后是两个切面代码
package com.spring.bean.aop; import java.util.Arrays; 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.core.annotation.Order; import org.springframework.stereotype.Component; /** * 声明一个切面 * @author Administrator * */
//order可以指定哪个切面先执行,数值越小,优先执行
@Order(1) @Aspect @Component public class MyLoggingAspectj { // 声明一个切入点 @Pointcut("execution(* *(..))") public void pointcut(){ } /** * 前置通知,该方法执行在被调用方法之前 * @param joinPoint */ @Before("pointcut())") public void beforeMethod(JoinPoint joinPoint){ // 获得调用的方法名 String methodName = joinPoint.getSignature().getName(); Object[] args = joinPoint.getArgs(); System.out.println("MyLoggingAspectj the method "+methodName+"begins with "+Arrays.asList(args)); } }
第二个切面代码
package com.spring.bean.aop; import java.util.Arrays; 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.core.annotation.Order; import org.springframework.stereotype.Component; /** * 声明一个切面 * @author Administrator * */ @Order(2) @Aspect @Component public class LoggingAspectj { // 声明一个切入点 @Pointcut("execution(* *(..))") public void pointcut(){ } /* *//** * 前置通知,该方法执行在被调用方法之前 * @param joinPoint *//* @Before("pointcut())") public void beforeMethod(JoinPoint joinPoint){ // 获得调用的方法名 String methodName = joinPoint.getSignature().getName(); Object[] args = joinPoint.getArgs(); System.out.println("the method "+methodName+"begins with "+Arrays.asList(args)); } *//** * 后置通知 * 该方法执行在被调用方法之后,报错也依然执行 * @param joinPoint *//* @After("pointcut())") public void afterMethod(JoinPoint joinPoint){ // 获得调用的方法名 String methodName = joinPoint.getSignature().getName(); Object[] args = joinPoint.getArgs(); System.out.println("the method "+methodName+"Ends with "+Arrays.asList(args)); } *//** * 返回通知, 在方法返回结果之后执行,异常无返回值 * @param joinPoint *//* @AfterReturning(value="pointcut())",returning="result") public void afterReturning(JoinPoint joinPoint,Object result){ // 获得调用的方法名 String methodName = joinPoint.getSignature().getName(); Object[] args = joinPoint.getArgs(); System.out.println("the method "+methodName+"afterReturning with "+Arrays.asList(args)+" ["+result+"]"); } *//** * 异常通知 * 在方法抛出异常之后 * @param joinPoint *//* @AfterThrowing(value="pointcut()",throwing="e") public void afterReturning(JoinPoint joinPoint,Exception e){ // 获得调用的方法名 String methodName = joinPoint.getSignature().getName(); Object[] args = joinPoint.getArgs(); System.out.println("the method "+methodName+"afterThrowing with "+Arrays.asList(args)+e); }*/ /** * 环绕通知需要配合ProceedingJoinPoint使用,相当于动态代理 * @param pjp * @return */ @Around(value="pointcut()") public Object aroundMethod(ProceedingJoinPoint pjp) { // 获得调用的方法名 String methodName = pjp.getSignature().getName(); Object result = null; // 调用目标方法 try { // 前置通知 System.out.println("the method " + methodName + "Begins with " + Arrays.asList(pjp.getArgs())); result = pjp.proceed(); // 后置通知 System.out.println("the method " + methodName + "Ends with " + Arrays.asList(pjp.getArgs())); // 后置有返回值 System.out.println( "the method " + methodName + "Ends with " + Arrays.asList(pjp.getArgs()) + " [" + result + "]"); } catch (Throwable e) { // TODO Auto-generated catch block // 异常通知 System.out.println("the method " + methodName + "AfterThrowing with " + Arrays.asList(pjp.getArgs()) + e); // e.printStackTrace(); // 不加这句,会报错,因为result返回值为null throw new RuntimeException(e); } System.out.println("the method " + methodName + "LastEnds with " + Arrays.asList(pjp.getArgs())); return result; } }
测试代码:
package com.spring.bean.aop; import java.util.ArrayList; import java.util.List; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main { public static void main(String[] args) { // TODO Auto-generated method stub ApplicationContext ctx=new ClassPathXmlApplicationContext("bean-aop.xml"); UserService userServiceImpl=(UserService) ctx.getBean("userService"); User user=(User) ctx.getBean("user"); List<Integer> arrayList = new ArrayList<Integer>(); arrayList.add(1); arrayList.add(2); int age = userServiceImpl.getValue(arrayList, 1); user.setName("xiaoqiang"); user.setAge(age); userServiceImpl.say(); } }
bean文件
<?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" xmlns:p="http://www.springframework.org/schema/p" 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-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!-- 自动扫描的包 --> <context:component-scan base-package="com.spring.bean.aop"></context:component-scan> <!-- 使 AspectJ 的注解起作用 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
总结:
1.在pom文件添加依赖,在 Spring 的配置文件中加入 aop 的命名空间。
<!--使用AspectJ方式注解需要相应的包--> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>${aspectj.version}</version> </dependency> <!--使用AspectJ方式注解需要相应的包--> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>${aspectj.version}</version> </dependency>
2.为接口实现类添加注解@Component
3.编写一个切面类,配置切面
* 3.1 在配置文件中配置自动扫描的包: <context:component-scan base-package="com.spring.bean.aop"></context:component-scan>
* 3.2 加入使 AspjectJ 注解起作用的配置: <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
* 为匹配的类自动生成动态代理对象.
4.编写前置通知方法,在方法上方添加注解
// 表达式注意格式: 修饰 +方法(有无返回)+包名+类名+方法名+参数
@Before("execution(public int com.spring.bean.annotation.aopimpl.Calculation.sub(int, int))")
* @Before 表示在目标方法执行之前执行 @Before 标记的方法的方法体.
* @Before 里面的是切入点表达式:
如关注详细参数,添加joinpoint对象,可以访问到方法的签名和参数
优秀不够,你是否无可替代
软件测试交流QQ群:721256703,期待你的加入!!
欢迎关注我的微信公众号:软件测试君

【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库