zoukankan      html  css  js  c++  java
  • Spring:SpringAop配合自定义注解实现切面编程

    此文章只作为笔记记录,不作为讲解文章。

    1. SpringAop简介

          传统的OOP开发中的代码逻辑是自上而下的,而这些过程会产生一些横切性问题,这些横切性的问题和我们的主业务逻辑关系不大,这些横切性问题不会影响到主逻辑实现的,但是会散落到代码的各个部分,难以维护。AOP是处理一些横切性问题,AOP的编程思想就是把这些问题和主业务逻辑分开,达到与主业务逻辑解耦的目的。

          SpringAop的应用场景
    • 日志记录
    • 权限验证
    • 效率检查
    • 事务管理
    • exception

    2. 依赖包引入

    //SpringBoot项目引入Aop依赖
           <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-aop</artifactId>
                <version>2.1.5.RELEASE</version>
            </dependency>
    
    
    //Spring项目引入Aop依赖
            <!-- springAop依赖包 -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-aop</artifactId>
                <version>5.2.4.RELEASE</version>
            </dependency>
            <!--  springAop依赖Aspect的语法标准包 -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-aspects</artifactId>
                <version>5.0.7.RELEASE</version>
            </dependency>

    3. Aop实现示例

    项目结构

    3.1 定义依赖注入扫描器

    AppConfig配置类

    package com.java.study.config;
    
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.EnableAspectJAutoProxy;
    
    //扫描注解
    @ComponentScan("com.java.study")
    //开启Aop,默认为false(JDK代理模式) true(Cglib模式)
    // (this) JDK代理时,指向接口和代理类proxy,cglib代理时 指向接口和子类(不使用proxy)
    @EnableAspectJAutoProxy(proxyTargetClass = true) public class AppConfig { }

    3.2 自定义service方法

    TestService测试方法类

    package com.java.study.service;
    
    import org.springframework.stereotype.Component;
    
    @Component("testService")
    public class TestService {
    
        public void Test1(){
            System.out.println("这是测试方法 test1 ......");
        }
    
    }

    3.3 定义切面类

    TestAdvice切面类

    package com.java.study.aspect;
    
    import com.java.study.custom.KthLog;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.springframework.stereotype.Component;
    import java.util.logging.Logger;
    
    @Component
    @Aspect
    public class TestAdvice {
        private final static Logger logger = Logger.getLogger("TestAdvice.class");
    
         // @annotation匹配的是自定义注解所标注的方法
        @Pointcut("@annotation(com.java.study.custom.KthLog)")
        public void loggerMother(){}
    
        @Pointcut("execution(* com.java.study..*())")
        public void loggerMother2(){}
    
        @Pointcut("execution(* com.java.study.*(java.lang.String))")
        public void loggerMother3(){}
    
        @Before("loggerMother() && @within(log)")
        public void Before(JoinPoint pointcut, KthLog log){
            System.out.println(" 方法名:"+ pointcut.getSignature().getName() +"日志输出:"+log.value());
        }
    
        @After("loggerMother2()")
        public void Before(){
            System.out.println(" 测试增强方法 。。。。。。");
        }
    
        @Around("loggerMother2()&&!loggerMother3()")
        public Object arround(ProceedingJoinPoint joinPoint) {
            logger.info("方法环绕start.....");
            try {
                Object o = joinPoint.proceed();
                logger.info("方法环绕proceed,结果是 :" + o);
                return o;
            } catch (Throwable e) {
                return null;
            }
        }
    
    }
    //execution表达式 (用于匹配方法)
    execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)
    问号 ? 表示当前项可以有也可以没有,其中各项的语义如下:
    modifiers-pattern:方法的可见性,如public,protected;(private不能被代理)
    ret-type-pattern:方法的返回值类型,如int,void等;
    declaring-type-pattern:方法所在类的全路径名,如com.spring.Aspect;
    name-pattern:方法名类型,如buisinessService();
    param-pattern:方法的参数类型,如java.lang.String;
    throws-pattern:方法抛出的异常类型,如java.lang.Exception;
    .. : 表示当前包及其子包
    //within表达式 (用于匹配类)
    within(declaring-type-pattern)
    declaring-type-pattern:方法所在类的全路径名,如com.spring.Aspect;
    //args表达式 (args匹配的是运行时传递给方法的参数类型) 与 execution 不同
    args(java.io.Serializable) //匹配运行时传递的参数类型为指定类型的、且参数个数和顺序匹配

    3.4 定义启动类

    TestApp启动类

    package com.java.study;
    
    import com.java.study.config.AppConfig;
    import com.java.study.service.TestService;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    public class TestApp {
    
        public static void main(String[] args) {
            AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
            TestService testService = (TestService) ac.getBean("testService");
            testService.Test1();
        }
    }

    4. 自定义注解

    定义 KthLog注解类

    package com.java.study.custom;
    
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    
    //元注解 @Retention @Retention(RetentionPolicy.RUNTIME)
    public @interface KthLog { String value() default ""; }

    元注解讲解

    java.lang.annotation 提供了四种元注解,专门注解其他的注解(在自定义注解的时候,需要使用到元注解

       @Retention – 什么时候使用该注解

       @Target – 注解用于什么地方   

       @Documented – 注解是否将包含在JavaDoc中   

       @Inherited – 是否允许子类继承该注解

    1.)@Retention – 定义该注解的生命周期
      ●   RetentionPolicy.SOURCE : 在编译阶段丢弃。这些注解在编译结束之后就不再有任何意义,所以它们不会写入字节码。@Override, @SuppressWarnings都属于这类注解。
      ●   RetentionPolicy.CLASS : 在类加载的时候丢弃。在字节码文件的处理中有用。注解默认使用这种方式
      ●   RetentionPolicy.RUNTIME : 始终不会丢弃,运行期也保留该注解,因此可以使用反射机制读取该注解的信息。我们自定义的注解通常使用这种方式。

    2.)@Target – 表示该注解用于什么地方。默认值为任何元素,表示该注解用于什么地方。可用的ElementType 参数包括
      ● ElementType.CONSTRUCTOR: 用于描述构造器
      ● ElementType.FIELD: 成员变量、对象、属性(包括enum实例)
      ● ElementType.LOCAL_VARIABLE: 用于描述局部变量
      ● ElementType.METHOD: 用于描述方法
      ● ElementType.PACKAGE: 用于描述包
      ● ElementType.PARAMETER: 用于描述参数
      ● ElementType.TYPE: 用于描述类、接口(包括注解类型) 或enum声明

    3.)@Documented – 一个简单的Annotations 标记注解,表示是否将注解信息添加在java 文档中。

    4.)@Inherited – 定义该注释和子类的关系
      ● @Inherited 元注解是一个标记注解,@Inherited 阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited 修饰的annotation 类型被用于一个class,则这个annotation 将被用于该class 的子类。

    5. 配合Aop增强类使用

    修改TestService测试方法类

    package com.java.study.service;
    
    import com.java.study.custom.KthLog;
    import org.springframework.stereotype.Component;
    
    @Component("testService")
    public class TestService {
    
        @KthLog("这是TestService类中******")
        public void Test1(){
            System.out.println("这是测试方法 test1 ......");
        }
    
    }

    之后使用TestAdvice切面类的loggerMother方法即可。

    ----------------------------------- 作者:怒吼的萝卜 链接:http://www.cnblogs.com/nhdlb/ -----------------------------------
  • 相关阅读:
    Docker 清理命令汇总
    Apache2.4.x版wampserver本地php服务器如何让外网访问及启用.htaccess
    github访问受限,通过更改host进行直接访问
    Python开发qq批量登陆
    Window安装Anaconda后,conda不是内部或者外部命令
    linux清空文件夹命令问题
    discuz添加管理员,找回管理员方法
    discuz论坛模板文件目录
    PyCharm创建文件时自动添加头注释
    python跳一跳辅助学习
  • 原文地址:https://www.cnblogs.com/nhdlb/p/15227384.html
Copyright © 2011-2022 走看看