zoukankan      html  css  js  c++  java
  • AOP底层原理及AOP操作

    AOP

    Aop(概念)

    1. 什么是AOP

      1)面向切面编程,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

      2)通俗描述:不通过修改源代码方式,在主干功能里面添加新功能。

      3)使用登陆例子说明AOP

      Snipaste_2020-10-19_09-24-37

    AOP(底层原理)

    1. AOP底层使用动态代理

      1)有两种情况动态代理

      ​ ①第一种 有接口情况,使用JDK代理

      ​ 创建接口实现类代理对象,增强类的方法

      Snipaste_2020-10-19_09-31-54

      ​ ②第二种 没有接口情况,使用CGLIB动态代理

      ​ 创建子类的代理对象,增强类的方法

      Snipaste_2020-10-19_09-35-06

    AOP(JDK动态代理)

    1. 使用JDK动态代理,使用Proxy类中的方法创建代理对象

      1)调用newProxyInstance方法

      Snipaste_2020-10-19_13-38-59

      ​ 方法有三个参数:

      ​ ①第一参数,类加载器

      ​ ②第二参数,增强方法所在的类,这个类实现的接口,支持多个 接口。

      ​ ③第三参数,实现这个接口,InvocationHandler,创建代理对 象,写增强的方法。

    2. 编写JDK动态代理代码

      1)创建接口,定义方法

      public interface UserDao {
          public int add(int a,int b);
      
          public String update(String id);
      }
      

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

      import com.spring.springday.dao.UserDao;
      
      public class UserDaoImpl implements UserDao {
          @Override
          public int add(int a, int b) {
              return a+b;
          }
      
          @Override
          public String update(String id) {
              return id;
          }
      }
      

      3)使用Proxy类创建接口代理对象

      import com.spring.springday.dao.UserDao;
      import com.spring.springday.dao.impl.UserDaoImpl;
      
      import java.lang.reflect.InvocationHandler;
      import java.lang.reflect.Method;
      import java.lang.reflect.Proxy;
      import java.util.Arrays;
      
      public class UserProxy {
          public static void main(String[] args) {
              Class[] interfaces = {UserDao.class};
              UserDaoImpl userDao = new UserDaoImpl();
      
              UserDao dao = (UserDao) Proxy.newProxyInstance(UserProxy.class.getClassLoader(),interfaces,
                      new UserDaoProxy(userDao) );
      
              int result = dao.add(1, 2);
              System.out.println("result:"+result);
          }
      }
      
      class UserDaoProxy implements InvocationHandler{
          private Object obj;
          public UserDaoProxy(Object obj){
              this.obj = obj;
          }
      
          @Override
          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
              System.out.println("方法执行之前..."+method.getName()+"传递的参数..."+ Arrays.toString(args));
              Object res = method.invoke(obj,args);
              System.out.println("方法执行之后..."+obj);
              return res;
          }
      }
      

      AOP(术语)

      1. 连接点

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

      2. 切入点

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

      3. 通知(增强)

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

        2)通知有多种类型

        ​ *前置通知

        ​ *后置通知

        ​ *环绕通知

        ​ *异常通知

        ​ *最终通知 finally

      4. 切面

        是动作

        把通知应用到切点过程

      AOP 操作(准备)

      1. Spring框架一般都是基于AspectJ实现AOP操作

        1)什么是AspectJ

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

      2. 基于AspectJ实现AOP操作

        1)基于xml配置文件实现

        2)基于注解方式实现

      3. 在项目工程里面引入AOP相关依赖

      4. 切入点表达式

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

        2)语法结构:

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

    AOP 操作(AspectJ注解)

    1. 创建类,在类里面定义方法

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

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

      import org.aspectj.lang.ProceedingJoinPoint;
      
      public class UserProxy {
      
          public void before(){
              System.out.println("before...");
          }
      
          public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
              System.out.println("环绕之前...");
              proceedingJoinPoint.proceed();
              System.out.println("环绕之后...");
          }
      }
      
      
    3. 进行通知配置

      1)在spring配置文件中,开启注解扫描

      <?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:context="http://www.springframework.org/schema/context"
             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/context http://www.springframework.org/schema/context/spring-context.xsd
                      http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
      ">
          <context:component-scan base-package="com.spring.springday.aop"></context:component-scan>
      
      </beans>
      

      2)使用注解创建User和UserProxy对象

      @Component
      public class User {
          public void add(){
              System.out.println("add...");
          }
      
      }
      

      Snipaste_2020-10-19_15-53-53

      3)在增强类上面添加注解@Aspect

      Snipaste_2020-10-19_15-54-48

      4)在spring配置文件中开启生成代理对象

      <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
      
    4. 配置不同类型的通知

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

        import org.aspectj.lang.ProceedingJoinPoint;
        import org.aspectj.lang.annotation.Around;
        import org.aspectj.lang.annotation.Aspect;
        import org.aspectj.lang.annotation.Before;
        import org.springframework.stereotype.Component;
        
        @Component
        @Aspect
        public class UserProxy {
            @Before(value = "execution(* com.spring.springday.aop.User.add(..))")
            public void before(){
                System.out.println("before...");
            }
        
            @Around(value = "execution(* com.spring.springday.aop.User.add(..))")
            public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
                System.out.println("环绕之前...");
                proceedingJoinPoint.proceed();
                System.out.println("环绕之后...");
            }
        }
        

      Snipaste_2020-10-19_16-01-40

    5. 公共切入点抽取

      @Pointcut(value = "execution(* com.spring.springday.aop.User.add(..))")
      public void point(){
      
      }
      
      @Before(value = "point()")
      public void before(){
          System.out.println("before...");
      }
      
    6. 有多个增强类对同一个方法进行增强,设置增强类优先级

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

      import org.aspectj.lang.annotation.Aspect;
      import org.aspectj.lang.annotation.Before;
      import org.springframework.core.annotation.Order;
      import org.springframework.stereotype.Component;
      
      @Component
      @Aspect
      @Order(1)
      public class ManagerProxy {
          @Before(value = "execution(* com.spring.springday.aop.User.add(..))")
          public void before(){
              System.out.println("before two...");
          }
      }
      
      @Before(value = "point()")
      @Order(2)
      public void before(){
          System.out.println("before...");
      }
      

    Snipaste_2020-10-19_16-41-26

    AOP操作(AspectJ配置文件)

    1. 创建两个类,增强类和被增强类

      public class Book {
          public void buy(){
              System.out.println("buy....");
          }
      }
      
      public class BookProxy {
          public void before(){
              System.out.println("before....");
          }
      }
      
    2. 在spring配置文件中创建两个类对象

      <!--配置两个类对象-->
      <bean id="book" class="com.spring.springday.aoptwo.Book"></bean>
      <bean id="bookProxy" class="com.spring.springday.aoptwo.BookProxy"></bean>
      
    3. 在spring配置文件中配置切入点

    <!--配置AOP增强-->
    <aop:config>
        <!--配置切点-->
        <aop:pointcut id="p" expression="execution(* com.spring.springday.aoptwo.Book.buy(..))"/>
        <!--配置切面-->
        <aop:aspect ref="bookProxy">
            <aop:before method="before" pointcut-ref="p"></aop:before>
        </aop:aspect>
    </aop:config>
    

    Snipaste_2020-10-19_17-00-25

  • 相关阅读:
    使用Oracle ODP.NET 11g的.NET程序发布方法
    Client使用c#和odp.net连接server oracle
    打造百度网盘备份利器:自动备份Linux VPS文件和多线程下载百度网盘资源
    安装软件:/lib/ld-linux.so.2: bad ELF interpreter解决
    ArcSDE数据库连接(直连、服务连)与GT_Geometry存
    AE的Annotation学习摘记
    Samba简单配置--匿名用户共享资料可读可写的实现
    Sublime Text 2 使用心得
    ArcGIS Server启动服务报:ERROR: Unable to start Xvfb on any port in the range 6600
    [DataContract] 和[DataMember]
  • 原文地址:https://www.cnblogs.com/coderD/p/13841241.html
Copyright © 2011-2022 走看看