Spring AOP 使用摘要

mac2025-02-11  12

一、准备:

引入spring 4.0版本基础jar包使用aop需额外引入aspectj支持及cglib代理支持 <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.0</version> </dependency> <dependency> <groupId>aopalliance</groupId> <artifactId>aopalliance</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>cglib</groupId> <artifactId>cglib-nodep</artifactId> <version>2.2.2</version> </dependency>

3、在spring配置文件中添加对aop注解的支持

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd "> <!-- 启动@aspectj的自动代理支持--> <aop:aspectj-autoproxy /> </beans>

上述非完整配置文件,若aop标签报错,请检查scheme中是否包含Aop支持

二、编码

1、编写一个java bean,配置成spring bean

import org.springframework.stereotype.Component; import cn.com.guo.annotation.AopJoinPointTest; @Component public class Kingnight { private String name; private String age; public Kingnight() { this.age = "88"; this.name = "king"; } public void sayHello(){ System.out.println("My name is " + name + "!"); System.out.println("My age is " + age + "!"); } @AopJoinPointTest(name="Kingnight:say good bye") public void sayGoodbye(){ System.out.println("Nice to meeting you! Good bye!"); } }

2、切面编写

import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @Aspect @Component public class KingnightAopTest { private Logger logger = LoggerFactory.getLogger(this.getClass()); @Pointcut("execution(* cn.com.guo.beans.Kingnight.sayHello())") public void kingnightJoinPoint(){ } @After(value="kingnightJoinPoint()") public void doAfter(){ logger.info("KingnightAopTest============>>"); } @Before("within(@cn.com.guo.annotation.AopJoinPointTest *)") public void doBefore(){ System.out.println("Fight well and often!s"); } }

@Pointcut定义横切关注点,在增强实现(advice)中可引入其定义的关注点,以将advice以给定方式织入对应连接点中。

@After、@Before为增强实现,可通过:1>@Pointcut定义的切点;2>AspectJ指示器 找到对应的切点,并将方法织入其中。

上例中within表达式指定使用@AopJoinPointTest 自定义注解的方法,自定义注解代码:

import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface AopJoinPointTest { /** * 引入说明 * @return */ String name() default ""; }

3、调用(我在spring Controller中调用,未编写Junit测试):

import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import cn.com.guo.beans.Kingnight; /** * 测试spring配置 * @author GuoZhinan */ @Controller @ResponseBody public class BaseController { private Logger logger = LoggerFactory.getLogger(getClass()); @Autowired private Kingnight kingnight; @RequestMapping("/*.do") public void doTest(HttpServletRequest req, HttpServletResponse resp){ logger.info("--start--"); kingnight.sayHello(); logger.info("--the work is over--"); kingnight.sayGoodbye(); } }

测试结果:

14:00:05.976 [http-8080-2] INFO cn.com.guo.controller.BaseController - --start-- My name is king! My age is 88! 14:00:06.251 [http-8080-2] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'kingnightAopTest' 14:00:06.252 [http-8080-2] INFO cn.com.guo.aop.KingnightAopTest - KingnightAopTest============>> 14:00:06.252 [http-8080-2] INFO cn.com.guo.controller.BaseController - --the work is over-- Nice to meeting you! Good bye!

三、Api整理

1、@Pointcut 定义横切关注点

        (1) 类型匹配语法:

          *:匹配任何数量字符;

         ..:匹配任何数量字符的重复,如在类型模式中匹配任何数量子包;而在方法参数模式中匹配任何数量参数。

         +:匹配指定类型的子类型;仅能作为后缀放在类型模式后边。

java.lang.String    匹配String类型   java.*.String       匹配java包下的任何“一级子包”下的String类型,如匹配java.lang.String,但不匹配java.lang.XXX.String   java..*             匹配java包及任何子包下的任何类型, 如匹配java.lang.String、java.lang.annotation.Annotation   java.lang.*ing      匹配任何java.lang包下的以ing结尾的类型 java.lang.Number+   匹配java.lang包下的任何Number的自类型,如匹配java.lang.Integer,也匹配java.math.BigInteger 

注意:使用 且(&&)、或(||)、非(!)来组合切入点表达式       

(2) Spring兼容的AspectJ指示器:

AspectJ指示器描述args()限定连接点匹配参数为指定类型的执行方法@args()限定连接点匹配参数由指定注解标注的执行方法execution()用于匹配连接点执行的方法within()限定匹配连接点指定的类型@within()限定匹配连接点指定注解所标注的类型(当使用Spring AOP时,方法定义在指定的注解所标注的类里)@annotation限定匹配带有特定注解的连接点target()限定连接点匹配目标对象为指定类型的类this()限定连接点匹配AOP代理的类型bean引用为指定类型的类    

以上是spring Aop兼容的AspectJ指示器(若有错漏,还请指正),若要使用AspectJ其它指示器,需使用spring集成AspectJ。

2、增强实现定义

Advice类型定义@Before前置通知:在切入点运行前执行,不会影响切入点的逻辑@After后置通知:在切入点正常运行结束后执行,如果切入点抛出异常,则在抛出异常前执行@AfterThrowing异常通知:在切入点抛出异常前执行,如果切入点正常运行(未抛出异常),则不执行@AfterReturning返回通知:在切入点正常运行结束后执行,如果切入点抛出异常,则不执行@Around环绕通知:在切入点执行前后自定义一些操作。需要负责决定是继续处理join point(调用ProceedingJoinPoint的proceed方法)还是中断执行

 

 

 

 

 

 

 

(1)JoinPoint 

用于获取连接点的相关信息

import org.aspectj.lang.reflect.SourceLocation; public interface JoinPoint { String toString(); //连接点所在位置的相关信息 String toShortString(); //连接点所在位置的简短相关信息 String toLongString(); //连接点所在位置的全部相关信息 Object getThis(); //返回AOP代理对象 Object getTarget(); //返回目标对象 Object[] getArgs(); //返回被通知方法参数列表 Signature getSignature(); //返回当前连接点签名 SourceLocation getSourceLocation();//返回连接点方法所在类文件中的位置 String getKind(); //连接点类型 StaticPart getStaticPart(); //返回连接点静态部分 }

(2)ProceedingJoinPoint

用于在环绕通知中执行被通知方法(下为接口源码):

package org.aspectj.lang; import org.aspectj.runtime.internal.AroundClosure; public interface ProceedingJoinPoint extends JoinPoint { void set$AroundClosure(AroundClosure arc); public Object proceed() throws Throwable; public Object proceed(Object[] args) throws Throwable; }

(3)在advice中获取连接点方法传入参数

可使用args指示器将参数自动传递给方法:

@Before(value="execution(* test(*)) && args(param)", argNames="param") public void doBefore(String param)

 

最新回复(0)