zoukankan      html  css  js  c++  java
  • spring AOP

    准备工作

    依赖导入

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.itheima</groupId>
        <artifactId>day03_eesy_03springAOP</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>jar</packaging>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>5.0.2.RELEASE</version>
            </dependency>
    
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.8.7</version>
            </dependency>
    
    
        </dependencies>
    
    </project>
    View Code

    一个Service的实现类模拟业务操作,提供切入点方法

    package com.itheima.service;
    
    /**
     * 账户的业务层接口
     *
     */
    public interface IAccountService {
        /**
         * 模拟保存账户
         */
        void saveAccount();
    
        /**
         * 模拟更新账户
         * @param i
         */
        void updateAccount(int i);
    
        /**
         * 删除账户
         */
        int deleteAccount();
    
    }

    一个工具类提供通知

    package com.itheima.utils;
    
    /**
     * 用于记录日志的工具类,里面提供了公共的代码
     */
    public class Logger {
    
        /**
         * 用于打印日志,并且计划让其在切入点方法执行前执行
         *  切入点方法:就是业务层的方法
         */
        public void printLog(){
            System.out.println("Loggor中的printLog方法开始记录日志");
        }
    }

    重点:bean.xml配置切面,将切入点方法和通知关联在一起

    <?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"
           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.xsd">
    
        <!-- 配置spring的ioc,把service对象配置进来 -->
        <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
        </bean>
    
        <!-- spring中基于xml的aop配置步骤 -->
        <!-- 1.把通知的bean交给spring管理,配置Logger类-->
        <bean id="logger" class="com.itheima.utils.Logger"></bean>
    
        <!-- 2.使用aop:config标签表明开始AOP配置 -->
        <aop:config>
            <!-- 3.使用aop:aspect标签表明配置切面
                id:给切面提供一个唯一标识; ref:指定通知类bean的id-->
            <aop:aspect id="logAdvice" ref="logger" >
                <!-- 4.在aop:aspect标签的内部使用对应标签来配置通知类型,切入点方法的关联
                    目前的实例是让printLog方法在切入点方法执行之前执行,所以是前置通知
                    aop:before: 标识配置前置通知
                        method:用于指定Logger类中哪个方法是前置通知
                        pointcut属性:用于指定切入点表达式,该表达式的含义值得是对业务层中哪些方法增强
                    切入点表达式的写法:
                        关键字:execution(表达式)
                        表达式:
                            访问修饰符  返回值  全限定类名.方法名(参数)
                        【标准写法】:
                            public void com.itheima.service.impl.AccountServiceImpl.saveAccount()
                        【访问修饰符】可以省略,【返回值】可以用通配符表示任意返回值
                            * com.itheima.service.impl.AccountServiceImpl.saveAccount()
                        【包名】可以使用通配符,有几级包就用几个*.
                            * *.*.*.*.AccountServiceImpl.saveAccount()
                        【包名】可以使用..表示当前包及其子包
                            * *..AccountServiceImpl.saveAccount()
                        【类名】和【方法名】都可以使用*实现通配
                            * *..*.*()
                        【参数列表】可以直接写数据类型:基本类型直接写,引用类型写 包名.类名,
                            可以使用*表示任意类型,但是必须有参数
                            可以使用..表示有无参数均可
                        【全通配写法】
                            * *..*.*(..)
                        实际开发中切入点表达式的通常写法;
                            切刀业务层实现类下的所有方法
                            * com.itheima.service.impl.*.*(..)
                 -->
                <aop:before method="printLog"
                            pointcut="execution(* com.itheima.service.impl.*.*(..))"/>
            </aop:aspect>
    
        </aop:config>
    
    </beans>

    四种通知配置 和 切入点配置

    先在Logger类内写这四个通知方法

     /**
         * 前置通知
         * 用于打印日志,并且计划让其在切入点方法执行前执行
         *  切入点方法:就是业务层的方法
         */
        public void beforePrintLog(){
            System.out.println("前置通知:Loggor中的BeforePrintLog方法开始记录日志");
        }
        /**
         * 后置通知:切入点方法正常执行后
         */
        public void afterReturningPrintLog(){
            System.out.println("后置通知:Logger类中的afterReturningPrintLog方法开始记录日志了");
        }
        /**
         * 异常通知:切入点方法执行异常
         */
        public void afterThrowingPrintLog(){
            System.out.println("异常通知:Logger类中的afterThrowingPrintLog方法开始记录日志了");
        }
        /**
         * 最终通知
         */
        public void afterPrintLog(){
            System.out.println("最终通知:Logger类中的afterPrintLog方法开始记录日志了");
        }

    在bean.xml为这些通知方法进行配置

    <!-- 2.使用aop:config标签表明开始AOP配置 -->
        <aop:config>
            <!-- 配置切入点表达式 id:表达式唯一标识 expression:指定表达式内容
                    此标签写在aop:aspect标签内部,只能当期切面使用
                    它还可以写在aop:aspect外面,所有切面可用-->
            <aop:pointcut id="pt1" expression="execution(* com.itheima.service.impl.*.*(..))"/>
    
            <!-- 3.使用aop:aspect标签表明配置切面
                id:给切面提供一个唯一标识; ref:指定通知类bean的id-->
            <aop:aspect id="logAdvice" ref="logger" >
                <aop:before method="beforePrintLog" pointcut-ref="pt1"/>
                <aop:after-returning method="afterReturningPrintLog" pointcut-ref="pt1"/>
                <aop:after-throwing method="afterThrowingPrintLog" pointcut-ref="pt1"/>
                <aop:after method="afterPrintLog" pointcut-ref="pt1"/>
            </aop:aspect>
    
        </aop:config>

    配置环绕通知

    首先还是在bean.xml里配置环绕通知

    <!--配置环绕通知 -->
                <aop:around method="aroundPrintLog" pointcut-ref="pt1"/>

    重点:在Logger类中添加环绕通知方法

    /**
         * 环绕通知:配置了环绕通知后,切入点方法没有执行,而通知方法执行了
         * 分析:通过对比动态代理中的环绕通知,发现动态代理的环绕通知有明确的业务层切入点方法调用
         *       而我们的代码中没有
         * 解决:spring框架为我们提供了一个借口:ProceedingJoinPoint
         *      该借口有一个方法叫proceed(),明确调用切入点的方法
         *      该接口可以作为环绕通知的方法参数,在程序执行时,spring框架会为我们提供该接口的实现类供我们使用
         * 环绕通知:
         *      spring框架提供的一种可以在代码中手动控制增强方法何时执行的方法
         */
        public Object aroundPrintLog(ProceedingJoinPoint pjp){
            Object reValue = null;
            try{
                Object[] args = pjp.getArgs();//得到切入点方法执行所需的参数
    
                System.out.println("前置通知:Logger类中的aroundPrintLog方法开始记录日志了");
    
                reValue = pjp.proceed(args);//明确调用业务层的方法(调用切入点方法)
    
                System.out.println("后置通知:Logger类中的aroundPrintLog方法开始记录日志了");
    
                return reValue;
            }catch (Throwable e){
                System.out.println("异常通知:Logger类中的aroundPrintLog方法开始记录日志了");
                throw  new RuntimeException(e);
            }finally {
                System.out.println("最终通知:Logger类中的aroundPrintLog方法开始记录日志了");
            }
        }
  • 相关阅读:
    linux系统禁止root用户通过ssh登录及ssh的访问控制
    POJ 3670 , 3671 LIS
    hello world是怎样运行的?
    MFC框架中消失的WinMain()
    [置顶] android LBS的研究与分享(附PPT)
    POJ 3616 DP
    IMP 导入数据报错 OCI-21500 OCI-22275
    误删/tmp导致hadoop无法启停, jsp无法查看的解决方法
    java的文件操作类File
    C#的可空类型与不可空类型
  • 原文地址:https://www.cnblogs.com/zsben991126/p/12632333.html
Copyright © 2011-2022 走看看