aspect_aspectj - CSDN
精华内容
参与话题
  • @Aspect 注解使用详解

    万次阅读 多人点赞 2019-08-27 11:05:46
    AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是...

    AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

    在spring AOP中业务逻辑仅仅只关注业务本身,将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。

    相关注解介绍:

    @Aspect:作用是把当前类标识为一个切面供容器读取
    
    @Pointcut:Pointcut是植入Advice的触发条件。每个Pointcut的定义包括2部分,一是表达式,二是方法签名。方法签名必须是 public及void型。可以将Pointcut中的方法看作是一个被Advice引用的助记符,因为表达式不直观,因此我们可以通过方法签名的方式为 此表达式命名。因此Pointcut中的方法只需要方法签名,而不需要在方法体内编写实际代码。
    @Around:环绕增强,相当于MethodInterceptor
    @AfterReturning:后置增强,相当于AfterReturningAdvice,方法正常退出时执行
    @Before:标识一个前置增强方法,相当于BeforeAdvice的功能,相似功能的还有
    @AfterThrowing:异常抛出增强,相当于ThrowsAdvice
    @After: final增强,不管是抛出异常或者正常退出都会执行

    使用pointcut代码:

    package com.aspectj.test.advice;
    
    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.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    
    @Aspect
    public class AdviceTest {
        @Around("execution(* com.abc.service.*.many*(..))")
        public Object process(ProceedingJoinPoint point) throws Throwable {
            System.out.println("@Around:执行目标方法之前...");
            //访问目标方法的参数:
            Object[] args = point.getArgs();
            if (args != null && args.length > 0 && args[0].getClass() == String.class) {
                args[0] = "改变后的参数1";
            }
            //用改变后的参数执行目标方法
            Object returnValue = point.proceed(args);
            System.out.println("@Around:执行目标方法之后...");
            System.out.println("@Around:被织入的目标对象为:" + point.getTarget());
            return "原返回值:" + returnValue + ",这是返回结果的后缀";
        }
        
        @Before("execution(* com.abc.service.*.many*(..))")
        public void permissionCheck(JoinPoint point) {
            System.out.println("@Before:模拟权限检查...");
            System.out.println("@Before:目标方法为:" + 
                    point.getSignature().getDeclaringTypeName() + 
                    "." + point.getSignature().getName());
            System.out.println("@Before:参数为:" + Arrays.toString(point.getArgs()));
            System.out.println("@Before:被织入的目标对象为:" + point.getTarget());
        }
        
        @AfterReturning(pointcut="execution(* com.abc.service.*.many*(..))", 
            returning="returnValue")
        public void log(JoinPoint point, Object returnValue) {
            System.out.println("@AfterReturning:模拟日志记录功能...");
            System.out.println("@AfterReturning:目标方法为:" + 
                    point.getSignature().getDeclaringTypeName() + 
                    "." + point.getSignature().getName());
            System.out.println("@AfterReturning:参数为:" + 
                    Arrays.toString(point.getArgs()));
            System.out.println("@AfterReturning:返回值为:" + returnValue);
            System.out.println("@AfterReturning:被织入的目标对象为:" + point.getTarget());
            
        }
        
        @After("execution(* com.abc.service.*.many*(..))")
        public void releaseResource(JoinPoint point) {
            System.out.println("@After:模拟释放资源...");
            System.out.println("@After:目标方法为:" + 
                    point.getSignature().getDeclaringTypeName() + 
                    "." + point.getSignature().getName());
            System.out.println("@After:参数为:" + Arrays.toString(point.getArgs()));
            System.out.println("@After:被织入的目标对象为:" + point.getTarget());
        }
    }

    使用annotation代码:

    //注解实体类
    package com.trip.demo;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ ElementType.METHOD })
    public @interface SMSAndMailSender {
        /*短信模板String格式化串*/
        String value() default "";
    
        String smsContent() default "";
    
        String mailContent() default "";
        /*是否激活发送功能*/
        boolean isActive() default true;
        /*主题*/
        String subject() default "";
    }
    
    
    
    //切面类
    @Aspect
    @Component("smsAndMailSenderMonitor")
    public class SMSAndMailSenderMonitor {
    
        private Logger logger = LoggerFactory.getLogger(SMSAndMailSenderMonitor.class);
    
    
        /**
         * 在所有标记了@SMSAndMailSender的方法中切入
         * @param joinPoint
         * @param result
         */
        @AfterReturning(value="@annotation(com.trip.demo.SMSAndMailSender)", returning="result")//有注解标记的方法,执行该后置返回
        public void afterReturning(JoinPoint joinPoint , Object result//注解标注的方法返回值) {
            MethodSignature ms = (MethodSignature) joinPoint.getSignature();
            Method method = ms.getMethod();
            boolean active = method.getAnnotation(SMSAndMailSender.class).isActive();
            if (!active) {
                return;
            }
            String smsContent = method.getAnnotation(SMSAndMailSender.class).smsContent();
            String mailContent = method.getAnnotation(SMSAndMailSender.class).mailContent();
            String subject = method.getAnnotation(SMSAndMailSender.class).subject();
           
        }
    
        
    
        /**
         * 在抛出异常时使用
         * @param joinPoint
         * @param ex
         */
        @AfterThrowing(value="@annotation(com.trip.order.monitor.SMSAndMailSender)",throwing = "ex")
        public void afterThrowing(JoinPoint joinPoint, Throwable ex//注解标注的方法抛出的异常) {
            MethodSignature ms = (MethodSignature) joinPoint.getSignature();
            Method method = ms.getMethod();
            String subject = method.getAnnotation(SMSAndMailSender.class).subject();
            
        }
    
    }
    
    
    //实体类中使用该注解标注方法
    @Service("testService ")
    public class TestService {
    
    
        @Override
        @SMSAndMailSender(smsContent = "MODEL_SUBMIT_SMS", mailContent =     
        "MODEL_SUPPLIER_EMAIL", subject = "MODEL_SUBJECT_EMAIL")
        public String test(String param) {
            return "success";
        }
    }
    
    
    

    注意,记得在配置文件中加上:

    <aop:aspectj-autoproxy proxy-target-class="true"/>
    展开全文
  • Springboot(二十一)@Aspect 切面注解使用

    万次阅读 多人点赞 2020-03-10 23:24:41
    Spring AOP面向切面编程,可以...用@Aspect做一个切面,就可以直接实现。 1.首先定义一个切面类,加上@Component @Aspect这两个注解 @Component @Aspect public class LogAspect { private static final Lo...

           Spring AOP面向切面编程,可以用来配置事务、做日志、权限验证、在用户请求时做一些处理等等。用@Aspect做一个切面,就可以直接实现。

        1.首先定义一个切面类,加上@Component  @Aspect这两个注解   

    @Component
    @Aspect
    public class LogAspect {
    
        private static final Logger logger = LoggerFactory.getLogger(LogAspect.class);
        private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
    
    
    }

         2.定义切点     

        private final String POINT_CUT = "execution(public * com.xhx.springboot.controller.*.*(..))";
    
        @Pointcut(POINT_CUT)
        public void pointCut(){}

        切点表达式中,..两个点表明多个,*代表一个,  上面表达式代表切入com.xhx.springboot.controller包下的所有类的所有方法,方法参数不限,返回类型不限。  其中访问修饰符可以不写,不能用*,,第一个*代表返回类型不限,第二个*表示所有类,第三个*表示所有方法,..两个点表示方法里的参数不限。  然后用@Pointcut切点注解,想在一个空方法上面,一会儿在Advice通知中,直接调用这个空方法就行了,也可以把切点表达式卸载Advice通知中的,单独定义出来主要是为了好管理。

     

       3.Advice,通知增强,主要包括五个注解Before,After,AfterReturning,AfterThrowing,Around,下面代码中关键地方都有注释,我都列出来了。

       @Before  在切点方法之前执行

       @After  在切点方法之后执行

        @AfterReturning 切点方法返回后执行

       @AfterThrowing 切点方法抛异常执行

      @Around 属于环绕增强,能控制切点执行前,执行后,,用这个注解后,程序抛异常,会影响@AfterThrowing这个注解

          

    package com.xhx.springboot.config;
    
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.Signature;
    import org.aspectj.lang.annotation.*;
    import org.aspectj.lang.reflect.SourceLocation;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    
    import javax.servlet.http.HttpServletRequest;
    import java.util.Arrays;
    
    @Component
    @Aspect
    public class LogAspect {
    
        private static final Logger logger = LoggerFactory.getLogger(LogAspect.class);
        private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
    
        private final String POINT_CUT = "execution(public * com.xhx.springboot.controller.*.*(..))";
    
        @Pointcut(POINT_CUT)
        public void pointCut(){}
    
       @Before(value = "pointCut()")
        public void before(JoinPoint joinPoint){
            logger.info("@Before通知执行");
            //获取目标方法参数信息
            Object[] args = joinPoint.getArgs();
            Arrays.stream(args).forEach(arg->{  // 大大
                try {
                    logger.info(OBJECT_MAPPER.writeValueAsString(arg));
                } catch (JsonProcessingException e) {
                    logger.info(arg.toString());
                }
            });
    
    
            //aop代理对象
            Object aThis = joinPoint.getThis();
            logger.info(aThis.toString()); //com.xhx.springboot.controller.HelloController@69fbbcdd
    
            //被代理对象
            Object target = joinPoint.getTarget();
            logger.info(target.toString()); //com.xhx.springboot.controller.HelloController@69fbbcdd
    
            //获取连接点的方法签名对象
            Signature signature = joinPoint.getSignature();
            logger.info(signature.toLongString()); //public java.lang.String com.xhx.springboot.controller.HelloController.getName(java.lang.String)
            logger.info(signature.toShortString()); //HelloController.getName(..)
            logger.info(signature.toString()); //String com.xhx.springboot.controller.HelloController.getName(String)
            //获取方法名
            logger.info(signature.getName()); //getName
            //获取声明类型名
            logger.info(signature.getDeclaringTypeName()); //com.xhx.springboot.controller.HelloController
            //获取声明类型  方法所在类的class对象
            logger.info(signature.getDeclaringType().toString()); //class com.xhx.springboot.controller.HelloController
            //和getDeclaringTypeName()一样
            logger.info(signature.getDeclaringType().getName());//com.xhx.springboot.controller.HelloController
    
            //连接点类型
            String kind = joinPoint.getKind();
            logger.info(kind);//method-execution
    
            //返回连接点方法所在类文件中的位置  打印报异常
            SourceLocation sourceLocation = joinPoint.getSourceLocation();
            logger.info(sourceLocation.toString());
            //logger.info(sourceLocation.getFileName());
            //logger.info(sourceLocation.getLine()+"");
            //logger.info(sourceLocation.getWithinType().toString()); //class com.xhx.springboot.controller.HelloController
    
            ///返回连接点静态部分
            JoinPoint.StaticPart staticPart = joinPoint.getStaticPart();
            logger.info(staticPart.toLongString());  //execution(public java.lang.String com.xhx.springboot.controller.HelloController.getName(java.lang.String))
    
    
            //attributes可以获取request信息 session信息等
            ServletRequestAttributes attributes =
                    (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            logger.info(request.getRequestURL().toString()); //http://127.0.0.1:8080/hello/getName
            logger.info(request.getRemoteAddr()); //127.0.0.1
            logger.info(request.getMethod()); //GET
    
           logger.info("before通知执行结束");
        }
    
    
        /**
         * 后置返回
         *      如果第一个参数为JoinPoint,则第二个参数为返回值的信息
         *      如果第一个参数不为JoinPoint,则第一个参数为returning中对应的参数
         * returning:限定了只有目标方法返回值与通知方法参数类型匹配时才能执行后置返回通知,否则不执行,
         *            参数为Object类型将匹配任何目标返回值
         */
        @AfterReturning(value = POINT_CUT,returning = "result")
        public void doAfterReturningAdvice1(JoinPoint joinPoint,Object result){
            logger.info("第一个后置返回通知的返回值:"+result);
        }
    
        @AfterReturning(value = POINT_CUT,returning = "result",argNames = "result")
        public void doAfterReturningAdvice2(String result){
            logger.info("第二个后置返回通知的返回值:"+result);
        }
        //第一个后置返回通知的返回值:姓名是大大
        //第二个后置返回通知的返回值:姓名是大大
        //第一个后置返回通知的返回值:{name=小小, id=1}
    
    
        /**
         * 后置异常通知
         *  定义一个名字,该名字用于匹配通知实现方法的一个参数名,当目标方法抛出异常返回后,将把目标方法抛出的异常传给通知方法;
         *  throwing:限定了只有目标方法抛出的异常与通知方法相应参数异常类型时才能执行后置异常通知,否则不执行,
         *            对于throwing对应的通知方法参数为Throwable类型将匹配任何异常。
         * @param joinPoint
         * @param exception
         */
        @AfterThrowing(value = POINT_CUT,throwing = "exception")
        public void doAfterThrowingAdvice(JoinPoint joinPoint,Throwable exception){
            logger.info(joinPoint.getSignature().getName());
            if(exception instanceof NullPointerException){
                logger.info("发生了空指针异常!!!!!");
            }
        }
    
        @After(value = POINT_CUT)
        public void doAfterAdvice(JoinPoint joinPoint){
            logger.info("后置通知执行了!");
        }
    
        /**
         * 环绕通知:
         *   注意:Spring AOP的环绕通知会影响到AfterThrowing通知的运行,不要同时使用
         *
         *   环绕通知非常强大,可以决定目标方法是否执行,什么时候执行,执行时是否需要替换方法参数,执行完毕是否需要替换返回值。
         *   环绕通知第一个参数必须是org.aspectj.lang.ProceedingJoinPoint类型
         */
        @Around(value = POINT_CUT)
        public Object doAroundAdvice(ProceedingJoinPoint proceedingJoinPoint){
            logger.info("@Around环绕通知:"+proceedingJoinPoint.getSignature().toString());
            Object obj = null;
            try {
                obj = proceedingJoinPoint.proceed(); //可以加参数
                logger.info(obj.toString());
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
            logger.info("@Around环绕通知执行结束");
            return obj;
        }
    }
    

            执行前后顺序是这样

     : @Around环绕通知
     : @Before通知执行
     : @Before通知执行结束
     : @Around环绕通知执行结束
     : @After后置通知执行了!
     : @AfterReturning第一个后置返回通知的返回值:18

        

    org.aspectj.lang.JoinPoint :  方法中的参数JoinPoint为连接点对象,它可以获取当前切入的方法的参数、代理类等信息,因此可以记录一些信息,验证一些信息等。

    org.aspectj.lang.ProceedingJoinPoint: 为JoinPoint的子类,多了两个方法

    public Object proceed() throws Throwable;  //调用下一个advice或者执行目标方法,返回值为目标方法返回值,因此可以通过更改返回值,修改方法的返回值
    public Object proceed(Object[] args) throws Throwable;   //参数为目标方法的参数  因此可以通过修改参数改变方法入参

     

    可以用下面的方式获取request、session等对象

    //attributes可以获取request信息 session信息等
    ServletRequestAttributes attributes =
            (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
    HttpServletRequest request = attributes.getRequest();

     

    下面介绍一下切点表达式:

       1.execution(方法修饰符 返回类型 方法全限定名(参数))         主要用来匹配整个方法签名和返回值的

    "execution(public * com.xhx.springboot.controller.*.*(..))"

        *只能匹配一级路径  

        ..可以匹配多级,可以是包路径,也可以匹配多个参数

        + 只能放在类后面,表明本类及所有子类

       还可以按下面这么玩,所有get开头的,第一个参数是Long类型的

    @Pointcut("execution(* *..get*(Long,..))")

      2. within(类路径)   用来限定类,同样可以使用匹配符

           下面用来表示com.xhx.springboot包及其子包下的所有类方法

    "within(com.xhx.springboot..*)"

     

    3. this与target

         this与target在用法上有些重合,理解上有对比性。

          this表示当前切入点表达式所指代的方法的对象的实例,即代理对象是否满足this类型

          target表示当前切入点表达式所指代的方法的目标对象的实例   即是否是为target类做的代理

        如果当前对象生成的代理对象符合this指定的类型,则进行切面,target是匹配业务对象为指定类型的类,则进行切面。

         生成代理对象时会有两种方法,一个是CGLIB一个是jdk动态代理。

          用下面三个例子进行说明:     

    • this(SomeInterface)或target(SomeInterface):这种情况下,无论是对于Jdk代理还是Cglib代理,其目标对象和代理对象都是实现SomeInterface接口的(Cglib生成的目标对象的子类也是实现了SomeInterface接口的),因而this和target语义都是符合的,此时这两个表达式的效果一样;
    • this(SomeObject)或target(SomeObject),这里SomeObject没实现任何接口:这种情况下,Spring会使用Cglib代理生成SomeObject的代理类对象,由于代理类是SomeObject的子类,子类的对象也是符合SomeObject类型的,因而this将会被匹配,而对于target,由于目标对象本身就是SomeObject类型,因而这两个表达式的效果一样;
    • this(SomeObject)或target(SomeObject),这里SomeObject实现了某个接口:对于这种情况,虽然表达式中指定的是一种具体的对象类型,但由于其实现了某个接口,因而Spring默认会使用Jdk代理为其生成代理对象,Jdk代理生成的代理对象与目标对象实现的是同一个接口,但代理对象与目标对象还是不同的对象,由于代理对象不是SomeObject类型的,因而此时是不符合this语义的,而由于目标对象就是SomeObject类型,因而target语义是符合的,此时this和target的效果就产生了区别;这里如果强制Spring使用Cglib代理,因而生成的代理对象都是SomeObject子类的对象,其是SomeObject类型的,因而this和target的语义都符合,其效果就是一致的。

     

      4.args(paramType)

           args无论其类路径或者是方法名是什么,表达式的作用是匹配指定参数类型和指定参数数量的方法,类型用全路径     

    args(java.lang.String,..,java.lang.Integer)

      5.@within(annotationType) 匹配带有指定注解的类,,within为配置指定类型的类实例

           下面匹配含有 @Component注解的类

    "@within(org.springframework.stereotype.Component)"

      6.@annotation(annotationType) 匹配带有指定注解的方法

     

      7.@args(annotationType)

                @args表示使用指定注解标注的类作为某个方法的参数时该方法将会被匹配

     

    可以使用&&、||、!、三种运算符来组合切点表达式,表示与或非的关系。

    @Around(value = "pointcut1() || pointcut2()")

     

      

    参考文献:

        Spring AOP切点表达式用法总结

     

    实时内容请关注微信公众号,公众号与博客同时更新:程序员星星

    实时内容请关注微信公众号,公众号与博客同时更新

     

    展开全文
  • @Aspect 用法

    2019-09-11 21:49:16
    AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是...

    AOP的基本概念

    AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

           在Spring AOP中业务逻辑仅仅只关注业务本身,将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。

    相关注解介绍

    @Aspect:作用是把当前类标识为一个切面供容器读取
    @Pointcut:Pointcut是植入Advice的触发条件。每个Pointcut的定义包括2部分,一是表达式,二是方法签名。方法签名必须是 public及void型。可以将Pointcut中的方法看作是一个被Advice引用的助记符,因为表达式不直观,因此我们可以通过方法签名的方式为 此表达式命名。因此Pointcut中的方法只需要方法签名,而不需要在方法体内编写实际代码。
    @Around:环绕增强,相当于MethodInterceptor
    @AfterReturning:后置增强,相当于AfterReturningAdvice,方法正常退出时执行
    @Before:标识一个前置增强方法,相当于BeforeAdvice的功能,相似功能的还有
    @AfterThrowing:异常抛出增强,相当于ThrowsAdvice
    @After: final增强,不管是抛出异常或者正常退出都会执行

     @Around日志使用实例

     

    package com.wildcatcloud.wildcat.common.log.aspect;
    
    import com.wildcatcloud.wildcat.common.log.annotation.SysLog;
    import lombok.AllArgsConstructor;
    import lombok.SneakyThrows;
    import lombok.extern.slf4j.Slf4j;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    
    /**
     * @author samuelQin
     * @description
     * 操作日志AOP
     * 使用spring event异步入库
     */
    @Slf4j
    @Aspect
    @AllArgsConstructor
    public class SysLogAspect {
    
        @SneakyThrows
        @Around("@annotation(sysLog)")
        public Object around(ProceedingJoinPoint point, SysLog sysLog) {
            String strClassName = point.getTarget().getClass().getName();
            String strMethodName = point.getSignature().getName();
            log.debug("[类名]:{},[方法]:{}", strClassName, strMethodName);
    
    //        SysLog logVo = SysLogUtils.getSysLog();
    //        logVo.setTitle(sysLog.value());
            // 发送异步日志事件
            Long startTime = System.currentTimeMillis();
            Object obj = point.proceed();
            Long endTime = System.currentTimeMillis();
    //        logVo.setTime(endTime - startTime);
    //        publisher.publishEvent(new SysLogEvent(logVo));
            return obj;
        }
    
    }
    展开全文
  • @Aspect

    千次阅读 2019-06-12 14:34:59
    Spring只支持XML方式而没有实现注解的方式(也叫AspectJ方式)的AOP,所以要使用@Aspect注解,只能引入AspectJ相关的 jar 包 aopalliance-1.0.jar 和 aspectjweaver.jar,这个坑把我给坑惨了。 1 使用步骤如下: 1、...

    https://blog.csdn.net/qgfjeahn/article/details/60144241

    Spring只支持XML方式而没有实现注解的方式(也叫AspectJ方式)的AOP,所以要使用@Aspect注解,只能引入AspectJ相关的 jar 包 aopalliance-1.0.jar 和 aspectjweaver.jar,这个坑把我给坑惨了。
    1
    使用步骤如下:
    1、引入相关jar包

    2、Spring的配置文件 applicationContext.xml 中引入context、aop对应的命名空间;配置自动扫描的包,同时使切面类中相关方法中的注解生效,需自动地为匹配到的方法所在的类生成代理对象。

    <?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.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.qcc.beans.aop"></context:component-scan>
        <!-- 自动为切面方法中匹配的方法所在的类生成代理对象。 -->
        <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    </beans>

    3、创建简单计算器的接口ArithmeticCalculator.java及实现类ArithmeticCalculatorImpl.java

    package com.qcc.beans.aop;

    public interface ArithmeticCalculator {

        int add(int i, int j);

        int sub(int i, int j);

        int mul(int i, int j);

        int div(int i, int j);
    }

    package com.qcc.beans.aop;

    import org.springframework.stereotype.Component;

    //将实现类加入Spring的IOC容器进行管理
    @Component("arithmeticCalculator")
    public class ArithmeticCalculatorImpl implements ArithmeticCalculator {

        @Override
        public int add(int i, int j) {
            int result = i + j;
            return result;
        }

        @Override
        public int sub(int i, int j) {
            int result = i - j;
            return result;
        }

        @Override
        public int mul(int i, int j) {
            int result = i * j;
            return result;
        }

        @Override
        public int div(int i, int j) {
            int result = i / j;
            return result;
        }

    }

    4、现在想在实现类中的每个方法执行前、后、以及是否发生异常等信息打印出来,需要把日志信息抽取出来,写到对应的切面的类中 LoggingAspect.java 中 
    要想把一个类变成切面类,需要两步, 
    ① 在类上使用 @Component 注解 把切面类加入到IOC容器中 
    ② 在类上使用 @Aspect 注解 使之成为切面类

    下面直接上完整代码,用@Aspect注解方式来实现前置通知、返回通知、后置通知、异常通知、环绕通知。

    package com.qcc.beans.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.springframework.stereotype.Component;

    /**
     * 日志切面
     * 
     * @author QianChaoChen 00002336<br>
     * @date 2017年3月3日 下午3:03:29
     */
    @Component
    @Aspect
    public class LoggingAspect {

        /**
         * 前置通知:目标方法执行之前执行以下方法体的内容 
         * @param jp
         */
        @Before("execution(* com.qcc.beans.aop.*.*(..))")
        public void beforeMethod(JoinPoint jp){
            String methodName = jp.getSignature().getName();
            System.out.println("【前置通知】the method 【" + methodName + "】 begins with " + Arrays.asList(jp.getArgs()));
        }

        /**
         * 返回通知:目标方法正常执行完毕时执行以下代码
         * @param jp
         * @param result
         */
        @AfterReturning(value="execution(* com.qcc.beans.aop.*.*(..))",returning="result")
        public void afterReturningMethod(JoinPoint jp, Object result){
            String methodName = jp.getSignature().getName();
            System.out.println("【返回通知】the method 【" + methodName + "】 ends with 【" + result + "】");
        }

        /**
         * 后置通知:目标方法执行之后执行以下方法体的内容,不管是否发生异常。
         * @param jp
         */
        @After("execution(* com.qcc.beans.aop.*.*(..))")
        public void afterMethod(JoinPoint jp){
            System.out.println("【后置通知】this is a afterMethod advice...");
        }

        /**
         * 异常通知:目标方法发生异常的时候执行以下代码
         */
        @AfterThrowing(value="execution(* com.qcc.beans.aop.*.*(..))",throwing="e")
        public void afterThorwingMethod(JoinPoint jp, NullPointerException e){
            String methodName = jp.getSignature().getName();
            System.out.println("【异常通知】the method 【" + methodName + "】 occurs exception: " + e);
        }

    //  /**
    //   * 环绕通知:目标方法执行前后分别执行一些代码,发生异常的时候执行另外一些代码
    //   * @return 
    //   */
    //  @Around(value="execution(* com.qcc.beans.aop.*.*(..))")
    //  public Object aroundMethod(ProceedingJoinPoint jp){
    //      String methodName = jp.getSignature().getName();
    //      Object result = null;
    //      try {
    //          System.out.println("【环绕通知中的--->前置通知】:the method 【" + methodName + "】 begins with " + Arrays.asList(jp.getArgs()));
    //          //执行目标方法
    //          result = jp.proceed();
    //          System.out.println("【环绕通知中的--->返回通知】:the method 【" + methodName + "】 ends with " + result);
    //      } catch (Throwable e) {
    //          System.out.println("【环绕通知中的--->异常通知】:the method 【" + methodName + "】 occurs exception " + e);
    //      }
    //      
    //      System.out.println("【环绕通知中的--->后置通知】:-----------------end.----------------------");
    //      return result;
    //  }

    }

    5、编写Main方法进行测试

    package com.qcc.beans.aop;

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

    public class Main {

        public static void main(String[] args) {
            ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
            ArithmeticCalculator arithmeticCalculator = (ArithmeticCalculator) ctx.getBean("arithmeticCalculator");
            System.out.println(arithmeticCalculator.getClass());
            int result = arithmeticCalculator.add(3, 5);
            System.out.println("result: " + result);

            result = arithmeticCalculator.div(5, 0);
            System.out.println("result: " + result);

        }
    }

    运行结果:

    class com.sun.proxy.$Proxy10
    【前置通知】the method 【add】 begins with [3, 5]
    【后置通知】this is a afterMethod advice...
    【返回通知】the method 【add】 ends with 【8】
    result: 8
    【前置通知】the method 【div】 begins with [5, 0]
    【后置通知】this is a afterMethod advice...
    Exception in thread "main" java.lang.ArithmeticException: / by zero
        at com.qcc.beans.aop.ArithmeticCalculatorImpl.div(ArithmeticCalculatorImpl.java:28)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
        at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:52)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.aspectj.AspectJAfterAdvice.invoke(AspectJAfterAdvice.java:43)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:52)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:58)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
        at com.sun.proxy.$Proxy10.div(Unknown Source)
        at com.qcc.beans.aop.Main.main(Main.java:15)

    把其它代码都注释掉,把环绕通知的方法释放出来,测试结果如下:

    【环绕通知中的--->前置通知】:the method 【add】 begins with [3, 5]
    【环绕通知中的--->返回通知】:the method 【add】 ends with 8
    【环绕通知中的--->后置通知】:-----------------end.----------------------
    result: 8
    【环绕通知中的--->前置通知】:the method 【div】 begins with [5, 0]
    【环绕通知中的--->异常通知】:the method 【div】 occurs exception java.lang.ArithmeticException: / by zero
    【环绕通知中的--->后置通知】:-----------------end.----------------------
    Exception in thread "main" org.springframework.aop.AopInvocationException: Null return value from advice does not match primitive return type for: public abstract int com.qcc.beans.aop.ArithmeticCalculator.div(int,int)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:219)
        at com.sun.proxy.$Proxy7.div(Unknown Source)
        at com.qcc.beans.aop.Main.main(Main.java:15)

    从以上发现,返回通知和异常通知不会同时出现;不管是否发生异常,后置通知都会正常打印。

    展开全文
  • 基于注解@Aspect的AOP实现

    万次阅读 2018-03-27 10:13:31
    Spring只支持XML方式而没有实现注解的方式(也叫AspectJ方式)的AOP,所以要使用@Aspect注解,只能引入AspectJ相关的 jar 包 aopalliance-1.0.jar 和 aspectjweaver.jar,这个坑把我给坑惨了。 使用步骤如下:1、...
  • Aspect详解

    2020-03-04 08:55:21
    @Aspect @Pointcut(“execution(…)”) @Around("…()") @Before("…()") @After("…()") @AfterReturnning(…()) Aspect指示器 功能描述 args() 根据方法(函数层面)入参对象类型 @args() 根据方法(函数...
  • spring @Aspect注解

    万次阅读 2019-05-17 20:18:55
    •要在 Spring 应用中使用 AspectJ 注解, 必须在 classpath 下包含 AspectJ 类库: aopalliance.jar、aspectj.weaver.jar 和 spring-aspects.jar •将 aop Schema 添加到 <beans> 根元素中. ...
  • @Aspect 切面声明,标注在类、接口(包括注解类型)或枚举上。 @Pointcut 切入点声明,即切入到哪些目标类的目标方法。 value 属性指定切入点表达式,默认为 "",用于被通知注解引用
  • 感觉这一方面网上资源好少……整理一份出来作为学习笔记,方便以后忘记了还有地方可以查看…… 感谢师兄用他早饭中的鸡蛋给我讲懂了这个问题,摸摸大! 昨天看综述《情感分析综述》就正好讲到了这个...aspect-term.
  • @Aspect注解无效

    万次阅读 2016-05-24 16:39:16
    Pointcut的execution配置正确的话,检查下,是否加了以下jar包 org.aspectj aspectjrt 1.8.9 org.aspectj aspectjweaver 1.8.9 cglib cglib 3.2.2
  • 关于spring中 @Aspect的不起作用的问题

    万次阅读 2020-03-01 10:59:36
    今天用到 spring中的aop ,@Aspect 注解,当我将@Before中的 描述指定为 单独的1个类时,aop 不起作用; 而 当作用在1个 实现某个接口的实现类后, 或者继承于某个超类时 就奏效了。 或许这就是Aspect编程的一种模式...
  • 用过spring框架进行开发的人,多多少少会使用过它的AOP功能,都知道有@Before、@Around和@After等advice。最近,为了实现项目中的输出日志和权限控制这两个需求,我也使用到了AOP功能。我使用到了@Before、@Around这...
  • 在使用@Aspect 注解进行AOP编程时,如果项目中使用到了spring mvc 那么如果你想使用AOP 来拦截controller层的方法时,你的AOP注解需要声明在dispatcher-servlet.xml中与spring mvc的配置定义在一起!!!如果修改完后 报...
  • Spring AOP @Before @Around @After 等 advice 的执行顺序

    万次阅读 多人点赞 2016-08-12 08:13:37
    Spring AOP 中 @Before @Around @After 等 advice 的执行顺序用过spring框架进行开发的人,多多少少会使用过它的AOP功能,都知道有@Before、@Around和@After等advice。最近,为了实现项目中的输出日志和权限控制这两...
  • spring boot @aspect 注解不生效

    千次阅读 2019-03-14 15:31:53
    使用spring @aspect注解时,怎么配置都不生效,切面不运行。 原因:测试在main方法中测试,直接new 一个对象,没有托管给spring,导致不拦截。后来改为用junit测试,用注入方式spring 生成bean,可以正常完成切面。...
  • Aspect注解 pom文件

    千次阅读 2018-09-01 18:46:45
    今天呢,需要用到自定义注解@Aspect 然后呢,当然需要引入相关的依赖了,后来呢,查了相关资料找出来了 花了有5分钟左右把,在这里记录一下,帮助一下有需要的朋友 &lt;properties&gt; &lt;aspectj...
  • aspect-based情感分析的调研

    千次阅读 2016-12-29 12:45:19
    基于aspect的情感分析指的是挖掘句子中涉及的aspect,以及对每个aspect表现出来的情感。现有的工作一般把这个任务分成两个部分:aspect识别,可以是aspect term提取或者aspect分类;aspect的情感识别。aspect term...
  • 1、在使用切面注解@Aspect一直导入不了该包,网上很多说只要引入一下依赖就可以了 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop<...
  • 故事是这样的,想记录一个controller里面的部分数据到数据库中(因为只有三行代码就犯懒没有再写service),controller在SpringMVC的配置文件扫描,其他应该扫描的在spring配置文件扫描实现如下:@Aspect ...
  • 使用@Aspect不起作用

    千次阅读 2017-01-16 11:55:41
    在做spring aop练习中发现使用@Aspect不起作用,问题代码: package org.spring.ioc.core.aop; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.spring...
1 2 3 4 5 ... 20
收藏数 116,585
精华内容 46,634
关键字:

aspect