• Spring AOP:面向切面编程,AspectJ,是基于注解的方法


    面向切面编程的术语:

    切面(Aspect): 横切关注点(跨越应用程序多个模块的功能)被模块化的特殊对象

    通知(Advice): 切面必须要完成的工作

    目标(Target): 被通知的对象

    代理(Proxy): 向目标对象应用通知之后创建的对象

    连接点(Joinpoint):程序执行的某个特定位置:如类某个方法调用前、调用后、方法抛出异常后等,连接点是程序类中客观存在的事务

    切点(pointcut):每个类都拥有多个连接点,例如 ArithmethicCalculator类中 的所有方法实际上都是连接点,AOP 通过切点定位到特定的连接点

    实现过程:

      要在 Spring 中声明 AspectJ 切面, 只需要在 IOC 容器中将切面声明为 Bean 实例. 当在 Spring IOC 容器中初始化 AspectJ 切面之后, Spring IOC 容器就会为那些与 AspectJ 切面相匹配的 Bean 创建代理.

      在 AspectJ 注解中, 切面只是一个带有 @Aspect 注解的 Java 类. 

      AspectJ 是基于注解的,支持 5 种类型的通知注解: 

    @Before: 前置通知, 在方法执行之前执行

    @After: 后置通知, 在方法执行之后执行

    @AfterRunning: 返回通知, 在方法返回结果之后执行

    @AfterThrowing: 异常通知, 在方法抛出异常之后

    @Around: 环绕通知, 围绕着方法执行

    导入spring编程的架包多个:。。。。

     -------------------------------------------------------------------------------

      建立一个接口类:ArithmeticCalculator,其是抽象类,不能实例化

    package com.atguigu.spring.aop.impl;
    
    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);
    }

      创建一个类:ArithmeticCalculatorImpl 继承于接口 ArithmeticCalculator,为该类添加注解@Component("arithmeticCalculator"),并赋标识,

    package com.atguigu.spring.aop.impl;
    
    import org.springframework.stereotype.Component;
    
    //@Component基本注解, 标识了一个受 Spring 管理的组件
    @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;
        }
    
    }

      建立一个类:ArithmeticCalculatorLoggingProxy,为该类添加注解:@Order(2),指定切面的优先级,值越小,优先级越大,@Aspect:为切面注解,面向切面编程,必须加;@Component:指是在IOC容器中的,为类中的方法添加不同的注解,前置通知,后置通知.....

    package com.atguigu.spring.aop.impl;
    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;
    
    /*
     * 面向切面编程:Spring AOP(其  是基于注解的spring的bean配置):
     * @Component:指是在IOC容器中的
     * @Aspect:为切面注解,面向切面编程,必须加;
     * 可以使用 @Order 注解指定切面的优先级, 值越小优先级越高
    */
    @Order(2)
    @Aspect @Component public class ArithmeticCalculatorLoggingProxy { /* * @Before:为在执行该方法之前的---前置通知 * execution(public int com.atguigu.spring.aop.impl.ArithmeticCalculator.*(..)): * 是指,前置通知放在继承这个 接口(全类名为:com.atguigu.spring.aop.impl.ArithmeticCalculator) * 的类下的所有方法; * Joinpoint joinpoint:为连接点,获取连接细节信息 * */ @Before("execution(public int com.atguigu.spring.aop.impl.ArithmeticCalculator.*(..))") public void beforeMethod(JoinPoint joinPoint){ //获取方法名,和参数值,参数值要多个,所以用数组集合的方法 String methodName=joinPoint.getSignature().getName(); Object[] args=joinPoint.getArgs(); System.out.println("The method "+methodName+" begains "+Arrays.asList(args)); } //后置通知:在方法执行之后,无论该方法出现异常,都执行 @After("execution(public int com.atguigu.spring.aop.impl.ArithmeticCalculator.*(..))") public void afterMethod(JoinPoint joinPoint){ //获取方法名,和参数值 String methodName=joinPoint.getSignature().getName(); System.out.println("The method "+methodName+ " ends"); } //返回通知:是方法正常结束之后返回的代码,如果是非正常结束,抛出异常,如分母为0 //返回通知是可以访问到方法的返回值的,即是该方法的结果 @AfterReturning(value="execution(public int com.atguigu.spring.aop.impl.ArithmeticCalculator.*(..))" , returning="result") public void afterReturning(JoinPoint joinPoint,Object result){ //获取方法名,和参数值 String methodName=joinPoint.getSignature().getName(); System.out.println("The method "+methodName+ " *** ends :"+result); } //@AfterThrowing:异常通知,在目标方法出现异常时会执行的代码; //异常通知,可以访问到异常对象;且可以指定在出现特定异常时在执行通知代码 @AfterThrowing(value="execution(public int com.atguigu.spring.aop.impl.ArithmeticCalculator.*(..))" , throwing="e") public void afterThrowing(JoinPoint joinPoint, Exception e){ String methodName=joinPoint.getSignature().getName(); System.out.println("The method "+methodName+ " Exception :"+ e); } //@Around:环绕通知; //环绕通知需要携带 ProceedingJoinPoint 类型的参数. //环绕通知类似于动态代理的全过程: ProceedingJoinPoint 类型的参数可以决定是否执行目标方法. // 且环绕通知必须有返回值, 返回值即为目标方法的返回值 @Around("execution(public int com.atguigu.spring.aop.impl.ArithmeticCalculator.*(..))") public Object aroundMethod(ProceedingJoinPoint pjp){ Object result=null; //获取方法名 String methodName=pjp.getSignature().getName(); try { //前置通知,Arrays.asList(pjp.getArgs())为该方法的参数个数,为数组集合 System.out.println("The method "+methodName+" begains "+Arrays.asList(pjp.getArgs())); //执行目标方法 result=pjp.proceed(); //返回通知 System.out.println("The method "+methodName+ " ends with :"+result); } catch (Throwable e) { //异常通知 System.out.println("The method " +methodName+ " occurs exception "+ e); e.printStackTrace(); } //后置通知 System.out.println("The method " + methodName + " ends"); return result; } }

     在上边的类中,定义一个方法,将方法上注解里面的"execution(public int com.atguigu.spring.aop.ArithmeticCalculator.*(..))"值,换成统一的"declareJointPointExpression()",即可以简化注解里重复的代码,这里使用到了@Pointcut注解

    /**
         * 定义一个方法, 用于声明切入点表达式. 一般地, 该方法中再不需要添入其他的代码. 
         * 使用 @Pointcut 来声明切入点表达式. 
         * 后面的其他通知直接使用方法名来引用当前的切入点表达式. 
         */
        @Pointcut("execution(public int com.atguigu.spring.aop.ArithmeticCalculator.*(..))")
        public void declareJointPointExpression(){}

    建立一个spring bean configuration file的xml文件:applicationContext.xml

    <!-- 配置自动扫描的包 -->
    <context:component-scan base-package="com.atguigu.spring.aop.impl"></context:component-scan>
        
    <!-- 配置自动为匹配aspectJ 的java类生成代理对象 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

    建立类:Main,进行测试:注意该类中 ArithmeticCalculator,是上边接口类,注解的内容是继承该接口的类 ArithmeticCalculatorImpl  的注解内容

    package com.atguigu.spring.aop.impl;
    
    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 impl=(ArithmeticCalculator) ctx.getBean("arithmeticCalculator");
            
            System.out.println(impl.getClass().getName());
            
            int result=impl.add(12,2);
            System.out.println(result);
            
            double result2=impl.div(12, 2);
            System.out.println(result2);
        }
    }
  • 相关阅读:
    【转】java内存溢出的场景及解决办法
    系统架构
    【转】Linux tar命令详解
    【转】Java 开发必会的 Linux 命令
    【转】ps命令详解与使用
    【转】Linux命令:ps -ef |grep java
    linux grep命令详解
    【springcloud】Zuul 超时、重试、并发参数设置
    【springcloud】常见面试题总结
    php的函数应用
  • 原文地址:https://www.cnblogs.com/lxnlxn/p/5868495.html
Copyright © 2020-2023  润新知