当前位置: 首页 > article >正文

后端:Spring AOP原理--动态代理

文章目录

    • 1. Spring AOP底层原理
    • 2. 代理模式
    • 3. 静态代理
    • 4. 动态代理
      • 4.1 jdk 实现动态代理
      • 4.2 cglib 实现动态代理
      • 4.3 jdk、cglib动态代理两者的区别

1. Spring AOP底层原理

  • 创建容器 new applicationContext();
  • Spring把所有的Bean进行创建,进行依赖注入;
  • ioc.getBean(UserService.class)此时获取得到Bean并不是原本的UserService类,而是通过动态代理生成一个代理类,这个代理类继承自UserService类。

在这里插入图片描述

2. 代理模式

代理模式是一种比较好的设计模式;

  • 使用代理对象来增强目标对象(target object),这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能;
  • 将核心业务代码和非核心的公共代码分离解耦,提高代码的可维护性,让被代理类专注业务降低代码复杂度。
    • 被代理类专注业务;
    • 代理类非核心的公共代码;

通常使用代理实现比如拦截器、事务控制,还有测试框架 mock、用户鉴权、日志、全局异常处理等。

3. 静态代理

代理类:

package com.lize.demo.aop.static1;

public class CeoProxy extends Ceo{
    @Override
    public void meeting(String name) {
        if(name.equals("张三")){
            super.meeting(name);
        }else{
            System.out.println("登记:"+name);
        }
    }
}

被代理类:

package com.lize.demo.aop.static1;

public class Ceo {
    public void meeting(String name){
        System.out.println("接见客户:"+name);
    }
}

测试:

package com.lize.demo.aop.static1;


import org.junit.jupiter.api.Test;
public class TestProxy {
    @Test
    public void test(){
        Ceo ceo = new CeoProxy();
        ceo.meeting("张三");
        ceo.meeting("李四");
    }
}

运行结果:
在这里插入图片描述

使用静态代理的弊端:一个代理类只能代理一个类型。

4. 动态代理

4.1 jdk 实现动态代理

jdk自带的,不需要额外导入其他依赖;
Proxy类中使用频率最高的方法是:newProxyInstance(),Proxy这个方法主要用来生成一个代理对象。

public static Object newProxyInstance(ClassLoader loader,
	Class<?>[] interfaces,
	InvocationHandler h
)

三个参数分别表示的意思是:

  • loader:类加载器,用于加载代理对象,传入被代理类的类加载器;
  • interfaces:被代理类实现的一些接口;被代理的类需要实现接口;
  • h:实现了InvocationHandler接口的对象;
package com.lize.demo.aop.autoProxy;

public interface IUserService {
    void add();
}
package com.lize.demo.aop.autoProxy;

// 被代理的类
public class UserService implements IUserService{
    @Override
    public void add() {
        System.out.println("增加。。。");
    }
}
package com.lize.demo.aop.autoProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class MyHandler implements InvocationHandler {

    private Object target;

    public MyHandler(Object target){
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println("前置通知");
        // args 传递过来的参数
        Object res = method.invoke(target, args);

        System.out.println("后置通知");

        return res;
    }

}
package com.lize.demo.aop.autoProxy;


import org.junit.jupiter.api.Test;

import java.lang.reflect.Proxy;

public class TestProxy {

    @Test
    public void test(){

        IUserService userService = (IUserService) Proxy.newProxyInstance(
                UserService.class.getClassLoader(),
                UserService.class.getInterfaces(),
                new MyHandler(new UserService())
        );
        userService.add();
        System.out.println(userService.getClass());
    }
}

运行结果:
在这里插入图片描述

4.2 cglib 实现动态代理

package com.lize.demo.aop.autoProxy2;
// 被代理的类
public class UserService {

    public void add() {

        System.out.println("增加。。。");
    }
}
package com.lize.demo.aop.autoProxy2;


import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

// 做增强处理
public class MyCallback implements MethodInterceptor {

    private Object target;

    public MyCallback(Object target) {

        this.target = target;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy proxy) throws Throwable {

        System.out.println("前置通知");

        Object res = proxy.invoke(target, args);

        System.out.println("后置通知");

        return res;
    }
}

package com.lize.demo.aop.autoProxy2;


import org.junit.jupiter.api.Test;
import org.springframework.cglib.proxy.Enhancer;

public class TestProxy {

    @Test
    public void test(){
        Enhancer enhancer = new Enhancer();
        // 设置被代理的类
        enhancer.setSuperclass(UserService.class);
        enhancer.setCallback(new MyCallback(new UserService()));
        UserService userService = (UserService) enhancer.create();
        // 代理的类
        userService.add();
        System.out.println(userService.getClass());
    }
}

在这里插入图片描述

4.3 jdk、cglib动态代理两者的区别

  • jdk动态代理只能代理实现了接口的类;而cglib可以代理未实现任何接口的类;
  • cglib动态代理是通过生成一个被代理类的子类来拦截被代理类的方法调用,因此不能代理声明为finnal类型的类和方法;
  • 在Spring中默认使用jdk动态代理,判断目标类是否实现了接口,如果实现了接口使用jdk动态代理,否则使用cglib;在Spring Boot中默认使用的是cglib动态代理。

在Spring中,如果想修改动态代理方式,可以通过注解的方式进行修改。

@EnableAspectJAutoProxy(proxyTargetClass = true) // cglib
@EnableAspectJAutoProxy(proxyTargetClass = false) // jdk

在Spring Boot中,如果想修改动态代理方式,可以通过在配置文件application.properties中添加配置即可。

spring.aop.proxy-target-class=false

http://www.kler.cn/a/395502.html

相关文章:

  • SSE与WebSocket与MQTT
  • 为什么海外服务器IP会被封
  • CSS的综合应用例子(网页制作)
  • STM32 51单片机设计半导体制冷片温控设计
  • 探索MoviePy:Python视频编辑的瑞士军刀
  • LaTeX之四:如何兼容中文(上手中文简历和中文论文)、在win/mac上安装新字体。
  • 联邦学习的未来:深入剖析FedAvg算法与数据不均衡的解决之道
  • 游戏引擎学习第九天
  • Javascript高级—搜索算法
  • Kafka节点服役和退役
  • 单片机_day4_串口通信
  • H.265流媒体播放器EasyPlayer.js播放器出现加载视频等待画面时长过长的原因排查
  • C03S05-PLinux网络之自动装机
  • Java项目:校园宿舍管理系统(优质版)(Springboot3+Maven+Mybatis Plus+Vue3+ Element Plus+Mysql)
  • DevOps工程技术价值流:加速业务价值流的落地实践与深度赋能
  • docker-hub 无法访问,使用windows魔法拉取docker images再上传到linux docker环境中
  • 动态规划29:673. 最长递增子序列的个数
  • python如何实现多态
  • 博客摘录「 pyqt 为新建子线程传参以及子线程返回数据到主线程」2023年12月7日
  • SkyWalking-安装
  • 权限相关知识
  • python os.path.basename(获取路径中的文件名部分) 详解
  • python爬虫初体验(五)—— 边学边玩小游戏
  • 字节青训营 数字魔法的加一操作
  • 自定义call方法和apply方法
  • element plus的表格内容自动滚动