spring aop 笔记

AOP

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

aop 想添加功能 但是不修改源代码 在主干功能里添加新功能

aop ( 底层原理 )

AOP 的底层 使用 动态代理

  1. 有两种情况的动态代理
    1. 有接口的情况 使用 JDK动态代理
    2. 没有接口的情况 使用CGLIB动态代理

aop jdk动态代理

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

    public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException
    
    1. 方法中含有三个参数
      1. 第一个 类加载器
      2. 第二个 增强方法所在的类 这个类实现的接口 支持多个接口
      3. 第三个 实现这个接口 InvocationHandler 创建代理对象
  2. jdk 动态代理代码

    1. 创建接口 定义方法

      package com.zh.demo1;
      
      public interface UserDao {
          public int add(int a,int b);
          public String update(String id);
      }
      
    2. 创建接口的实现类 实现方法

      package com.zh.demo1;
      
      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类创建接口代理对象

      1. 创建一个类 创建main方法
      2. 实现Proxy中newProxyInstance 方法 方法含有三个参数 上边写了 第一个参数是类的加载器 为JDKProxy.class.getClassLoader() 第二个参数为增强方法所在的类 举例为userdao 第三个参数一个接口用来创建代理对象 两种方法 1 匿名内部类 直接new 2 创建一个新的类实现此接口 我采用的为此方法
      package com.zh.demo1;
      
      import java.lang.reflect.InvocationHandler;
      import java.lang.reflect.Method;
      import java.lang.reflect.Proxy;
      import java.util.Arrays;
      
      public class JDKProxy {
          private Object object;
          public static void main(String[] args) {
              //创建接口实现类的代理对象
              Class[] interfaces={UserDao.class};
              UserDaoImpl userDao=new UserDaoImpl();
              UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
              int add=dao.add(1,2);
              System.out.println(add);
          }
      }
      //创建代理对象代码
      class UserDaoProxy implements InvocationHandler{
          //1 把创建的是 谁的代理对象 把谁传递过来
          //通过有参构造进行传递
          private Object object;
          public UserDaoProxy(Object object){
              this.object=object;
          }
          //增强的逻辑
          @Override
          //第一个参数 代理对象 第二个值 表示当前的方法  第三个 表示方法的参数
          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
              //方法之前
              //method.getName()执行的方法名字
              System.out.println("方法之前执行"+method.getName()+":传递的参数====="+ Arrays.toString(args));
      
              //被增强的方法
              //下面表示执行当前方法
              Object a=method.invoke(object,args);
              //方法之后
              System.out.println("方法之后执行      "+object);
              return a;
          }
      }
      

aop 术语

  1. 连接点 类里的哪些方法可以被增强 这些方法被称为连接点
  2. 切入点 实际被真正增强的方法 被称为切入点
  3. 通知(增强)
    1. 实际增强的逻辑的部分称为通知
    2. 通知有多种类型
      1. 前置通知 @before
      2. 后置通知 @afterReturning
      3. 环绕通知 @around
      4. 异常通知 @afterThrowing
      5. 最终通知 @after
  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. 语法结构 :execution([权限修饰符] [返回类型] [方法名称] ([参数列表]))
    3. 举例1 execution(* con.zh.demo1.Book.add(…)) *表示所有的修饰符
    4. 举例2 对类里的所有方法进行增强 execution(* com.zh.demo.Book.*(…))
    5. 举例3 对包中的所有类 类里的所有方法进行增强execution(* com.zh.* . *(…))

aop操作(基于AspectJ注解方式)

  1. 创建一个类 在类中定义方法,实现对类的方法增强

  2. 创建一个增强类,编写增强的逻辑

    1. 在增强类中创建方法 让不同的方法代表不同的通知类型
  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.zh"></context:component-scan>
      
    2. 使用注解创建user和userproxy两个对象

      //被增强的类
      @Component
      public class User {
          public void add(){
              System.out.println("add.............");
          }
      }
      //增强的类
      @Component
      @Aspect//生成代理对象
      public class UserProxy {
          //前置通知
          public void before(){
              System.out.println("before.........");
      
          }
      }
      
    3. 在增强的类上添加一个注解 @aspect

      //增强的类
      @Component
      @Aspect//生成代理对象
      public class UserProxy {
          //前置通知
          public void before(){
              System.out.println("before.........");
      
          }
      }
      
    4. 在spring配置文件中 开启生成代理对象`

      <!--    开启aspectJ生成代理对象-->
          <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
      </beans>
      
    5. 配置不同类型的通知

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

        //前置通知
        //before 注解表示作为前置通知
        @Before(value = "execution(* com.zh.demo2.User.add())")
        public void before(){
            System.out.println("before.........");
        }
        
        //环绕通知 在add之间 和之后都执行
        @Around(value = "execution(* com.zh.demo2.User.add())")
        public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
            System.out.println("环绕之前");
            //执行被增强的方法
            proceedingJoinPoint.proceed();
            System.out.println("环绕之后");
        }
        
        

        before 前置通知 afterthrowing 异常通知 产生异常 才会执行after 最终通知 有异常也执行

    6. 对公共切入点抽取

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

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

        //增强的类
        @Component
        @Aspect//生成代理对象
        @Order(3)
        public class UserProxy {}
        
        ========================================================
        @Component
        @Aspect
        @Order(1)
        public class PersonProxy {
            @Before(value = "execution(* com.zh.demo2.User.add())")
            public void before(){
                System.out.println("person  before.........");
        
            }
        }
        

aop操作(AspectJ配置文件方式)

  1. 创建两个类 增强类和被增强类 创建方法

  2. 在spring配置文件中创建两个类对象

    	创建对象
        <bean id="book" class="com.zh.demo3.Book"></bean>
        <bean id="bookProxy" class="com.zh.demo3.BookProxy"/>
    
  3. 在spring配置文件中配置切入点

    <!--    配置aop增强 -->
        <aop:config>
    <!--        切入点-->
            <aop:pointcut id="zh" expression="execution(* com.zh.demo3.Book.buy())"/>
    <!--        配置切面   表示把增强的方法应用到切入点的过程-->
            <aop:aspect ref="bookProxy">
    <!--            配置 增强作用在具体的方法上   method 增强的方法   pointcut-ref作用在哪个切入点-->
                <aop:before method="before" pointcut-ref="zh"/>
            </aop:aspect>
        </aop:config>
    

完全注解(简单了解)

创建一个配置类 不需要创建xml配置文件

package com.zh.demo3;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@ComponentScan(basePackages = {"com.zh.demo3"})//替代配置文件中 开启组件扫描
@EnableAspectJAutoProxy(proxyTargetClass = true)//替代配置文件中 开启aspect生成代理对象
public class ConfigAop {
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值