栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

2021SC@SDUSC-SDUDOC-blog05

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

2021SC@SDUSC-SDUDOC-blog05

2021SC@SDUSC
此篇记录:AOP by冰弦qwq

AOP

几个基础:

  1. 切入点(Pointcut)
    在哪些类,哪些方法上切入(where)
    通知(Advice)
    在方法执行的什么实际(when:方法前/方法后/方法前后)做什么(what:增强的功能)

  2. 切面(Aspect)
    切面 = 切入点 + 通知,通俗点就是:在什么时机,什么地方,做什么增强!

  3. 织入(Weaving)
    把切面加入到对象,并创建出代理对象的过程。(由 Spring 来完成)

实现底层原理(JDK动态代理)

1、使用JDK动态代理,使用Proxy类里面的方法创建代理对象

static newProxyInstance(ClassLoader, Class[], InvocationHandler);

有三个参数:

  • ClassLoader : 类加载器
  • Class[] : 多个接口
  • InvocationHandler : 实现这个接口,创建代理对象,写增强方法

2、编写JDK动态代理

(1)创建接口,定义方法

(2)创建接口实现类,实现方法

(3)使用proxy

public class MyProxy {

    public static void main(String[] args) {
        Class[] interfaces = {UserInter.class};
        UserImpl user = new UserImpl();
        UserInter inter = (UserInter) Proxy.newProxyInstance(MyProxy.class.getClassLoader(), interfaces, new UserInterProxy(user));
        inter.add(1, 2);
        inter.update("123");
    }

}

// 创建代理
class UserInterProxy implements InvocationHandler {

    private Object object;
    // 把需要代理的对象传入
    // 通过有参构造进行传递
    public UserInterProxy(Object o) {
        this.object = o;
    }

    // 写增强的逻辑
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        // 在方法之前
        System.out.println("invoke before method : " + method.getName() + ":传递的参数..." + Arrays.toString(args));

        Object res = method.invoke(object,args);
        System.out.println(res);

        // 在方法之后
        System.out.println("方法执行之后 : " + object.toString());

        return res;
    }
}
术语
  1. 连接点

    类里面哪些方法可以被增强,这些方法称为连接点

  2. 切入点

    实际被增强的方法,称为切入点

  3. 通知(增强)

    (1)实际增强的逻辑部分称为通知

    (2)通知有多种类型

    • 前置通知
    • 后置通知
    • 环绕通知
    • 异常通知
    • 最终通知 finally
  4. 切面

    是一个动作:把通知应用到切入点的过程

准备工作

Spring框架中,一般基于AspectJ实现AOP操作

(1)什么是AspectJ

  • AspectJ不是Spring组成部分,是一个独立的AOP框架,一般把他和Spring一起使用,进行AOP操作

操作:

(1)基于xml配置文件实现

(2)基于注解方式实现(常用)

步骤:

  1. 引入依赖

切入点表达式

(1)切入点表达式作用:知道对哪个类里面的哪个方法进行增强

(2)语法结构:

execution([权限修饰符][返回类型][类全路径][方法全名]([参数列表]))

示例一:

对com.company.dao.UserDao类里面的add进行增强

execution(* com.company.dao.UserDao.add(..))
// *号表示所有的修饰符

示例二:

对com.company.dao.UserDao类里面的所有方法进行增强

execution(* com.company.dao.UserDao.*(..))
// *号表示所有的修饰符

示例三:

对com.company.dao.包内所有类类里面的所有方法进行增强

execution(* com.company.dao.*.*(..))
// *号表示所有的修饰符
基于注解操作AspectJ
  1. 创建类,在类里面定义方法

    public class User {
        public void add() {
            System.out.println("User.add");
        }
    }
    
  2. 创建增强类(编写增强逻辑)

    • 在增强类里面,创建方法,让不同方法代表不同通知类型

      public class UserProxy {
      
          // 前置通知
          public void before() {
              System.out.println("before...");
          }
      }
      
  • 使用注解创建User和UserProxy对象

  • 在增强类中添加注解@Aspect

    @Component
    public class User {
        public void add() {
            System.out.println("User.add");
        }
    }
    
    @Component
    @Aspect
    public class UserProxy {
    
        // 前置通知
        public void before() {
            System.out.println("before...");
        }
    }
    
  • 在Spring配置文件中开启生成代理对象


    

        
        
  • 配置不同类型的通知

    在我们的增强类里面,在作为通知方法上面添加通知类型注释,使用切入点表达式配置

    @Component
    @Aspect
    public class UserProxy {
    
        // 前置通知
        // @Before注解表示作为前置通知
        @Before(value = "execution(* AOP.User.add(..))")
        public void before() {
            System.out.println("before...");
        }
    
        @AfterReturning(value = "execution(* AOP.User.add(..))")
        public void afterRet() {
            System.out.println("after Returning...");
        }
    
        @After(value = "execution(* AOP.User.add(..))")
        public void after() {
            System.out.println("after...");
        }
    
        @AfterThrowing(value = "execution(* AOP.User.add(..))")
        public void afterThrowing() {
            System.out.println("throw...");
        }
    
        @Around(value = "execution(* AOP.User.add(..))")
        public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
            System.out.println("around bef...");
    
            proceedingJoinPoint.proceed();
    
            System.out.println("around aft");
        }
        
    }
    
    // ... 结果 : 
    around bef...
    before...
    User.add
    after Returning...
    after...
    around aft
    

注意,如果报错,则afterReturning和aournd后半段不会执行,afterReturning表示方法执行成功才会执行。

而after可以成为最终通知,一定会执行

  1. 对于相同切入点进行抽取

    // 相同切入点抽取
    @Pointcut(value = "execution(* AOP.User.add(..))")
    public void pointDemo() {
    
    }
    
    // 前置通知
    // @Before注解表示作为前置通知
    @Before(value = "pointDemo()")
    public void before() {
    System.out.println("before...");
    }
    
  2. 多个增强类对同一个方法进行增强,可以设置优先级

在增强类上面添加注解@Order(数字值类型),数字越小优先级越高 高优先级会包裹低优先级.

注释实现扫描包配置和启动AspectJ服务:

@Configuration
@ComponentScan(value = {"AOP"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class ConfigAop {
}

...

    ApplicationContext context = new 				AnnotationConfigApplicationContext(ConfigAop.class);
User user = context.getBean("user", User.class);
user.add();
基于配置文件操作AOP

by@冰弦qwq

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/346082.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号