首页 > 其他分享 >Spring Boot框架中的JDK动态代理实践及其应用场景

Spring Boot框架中的JDK动态代理实践及其应用场景

时间:2024-03-30 13:58:20浏览次数:18  
标签:JDK Spring Boot 代理 method IUserService import class

引言

在Java编程中,JDK动态代理是一种强大的设计模式,它允许我们在运行时动态地创建并实现代理类,从而对目标对象的行为进行增强或控制。这种机制主要由Java标准库java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口提供支持。在诸如Spring Boot这样的企业级开发框架中,JDK动态代理经常被用于实现诸如AOP(面向切面编程)、服务代理、事务管理等高级功能。

JDK动态代理产生的背景

JDK动态代理的设计初衷是为了适应那些在编译期间无法确定代理类需求的情况。在传统的静态代理模式下,我们需要为每一个具体的服务接口预先创建一个对应的代理类,当系统中存在大量接口时,这种方式会带来大量的重复代码和维护困难。而JDK动态代理通过在运行时根据接口动态生成代理类的方式,极大地简化了这一过程,使得开发者无需手动编写具体的代理类代码,只需关注代理逻辑本身。

为什么使用JDK动态代理

  1. 灵活性:由于代理类是在运行时生成的,因此可以根据不同的场景灵活地定制代理行为,无需提前预知所有可能的代理情况。
  2. 可扩展性:对于大型软件系统,尤其是组件化和模块化的应用,JDK动态代理能够方便地添加额外的功能,如日志记录、权限检查、性能监控等,而不需要修改原有业务代码。
  3. 轻量级解决方案:相比CGLIB等其他代理方式,JDK动态代理基于接口实现,如果目标对象已经实现了接口,那么JDK代理就成为了一个无侵入性的选择,因为它不涉及类层次结构的改变。

Spring Boot中的JDK动态代理实践

package com.example.demo.aspect;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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

/**
 * @author YangDi
 * @since 2024/3/20
 */
public class LoggingHandler implements InvocationHandler {

    private static final Logger log = LoggerFactory.getLogger(LoggingHandler.class);

    private Object object;

    public LoggingHandler(Object object) {
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        log.info("Before method:proxy:{},method:{},args:{}", proxy.getClass().getName(), method.getName(), args);
        Object result = method.invoke(object, args);
        log.info("After method:proxy:{},method:{},args:{}", proxy.getClass().getName(), method.getName(), args);
        return result;
    }
}
业务层代码
package com.example.demo.service;

/**
 * @author YangDi
 * @since 2024/3/20
 */
public interface IUserService {
    String getUserName();
}
package com.example.demo.service.impl;

import com.example.demo.service.IUserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

/**
 * @author YangDi
 * @since 2024/3/20
 */
@Service
public class UserServiceImpl implements IUserService {

    private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);


    @Override
    public String getUserName() {
        log.info("Execute a method to query the user name");
        return "YangDi";
    }
}
控制层代码
package com.example.demo.controller;

import com.example.demo.aspect.LoggingHandler;
import com.example.demo.service.IUserService;
import com.example.demo.utils.result.ResultEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.lang.reflect.Proxy;

/**
 * @author YangDi
 * @since 2024/3/20
 */
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private IUserService userService;

    @GetMapping("/getUserName")
    public ResultEntity<String> getUserName() {
        return ResultEntity.success(userService.getUserName());
    }

    @GetMapping("/loggingHandler/getUserName")
    public ResultEntity<String> getLoggingHandlerUserName() {
        IUserService userServiceProxy =(IUserService) Proxy.newProxyInstance(
                IUserService.class.getClassLoader(),
                new Class[]{IUserService.class},
                new LoggingHandler(userService));
        return ResultEntity.success(userServiceProxy.getUserName());
    }
}
知识点
IUserService userServiceProxy =(IUserService) Proxy.newProxyInstance(
                IUserService.class.getClassLoader(),
                new Class[]{IUserService.class},
                new LoggingHandler(userService));


IUserService.class.getClassLoader(): 第一个参数是目标类的类加载器,这里使用的是IUserService接口的类加载器,用于加载生成的代理类。
new Class[]{IUserService.class}: 第二个参数是一个Class数组,包含需要实现的所有接口。这里只有一个接口IUserService,所以传入的是{IUserService.class}
new LoggingHandler(userService): 第三个参数是InvocationHandler接口的实现类实例,当代理对象的方法被调用时,会调用这个InvocationHandler对象的invoke方法。这里的LoggingHandler是一个自定义的InvocationHandler实现,它内部持有真实的业务对象userService,在调用方法前后可以添加额外的处理逻辑

标签:JDK,Spring,Boot,代理,method,IUserService,import,class
From: https://blog.csdn.net/gg_996633543/article/details/137171958

相关文章

  • spring boot 配置文件值注入
        利用配置文件将属性注入到bean程序里面去,下面是各个情况的总结:    首先我先新建一个bean(beans.User类)来完成演示:packageorg.example.springbootdemo.beans;importlombok.Data;importorg.springframework.boot.context.properties.ConfigurationPro......
  • SpringCloud下的微服务应用技术(结尾篇)
    六.Feign远程调用6.1替代RestTemplateRestTemplate调用问题:代码可读性差,参数复杂且URL难维护。Feign是一个声明式的HTTP客户端,官方地址:GitHub-OpenFeign/feign:Feignmakeswritingjavahttpclientseasier它可以解决上述提到的问题。STEP1:首先,在orderservice中引......
  • yii2 配置bootstrap使用
    yii2配置bootstrap使用配置config/web.php添加people<?php...$config=[...'bootstrap'=>['log','people'],...'components'=>['people'=>['class'......
  • Spring 一文彻底搞定循环依赖
    Spring解读循环依赖一.前言Spring是怎么解决循环依赖问题第一级缓存存放的是完全初始化完成的可以直接使用的对象,第二级缓存存放的是经过后置处理器处理(即代理过)的对象,第三级缓存村放的是刚实例化好没有经过后置处理器处理(即没有被代理过)的对象。二.什么是循环依赖......
  • Spring Cloud中从0-1实现高效的API接口,快来简单有效的方式来构建API接口
    目录1.添加POM依赖2.构建目录结构3.构建文件4.实现API接口4.1.MyBatis4.1.1.控制层(Controller)4.1.2.服务接口层(ServiceInterface)4.1.3.服务层(ServiceImplementation)4.1.4.实体类(Entity)4.1.5.数据访问层(Mapper) 4.1.6.JUnit单元测试Controller层测......
  • SpringBoot + Activiti 工作流搭建与实现(附文档+源码)
      前言activiti工作流引擎项目,企业erp、oa、hr、crm等企事业办公系统轻松落地,一套完整并且实际运用在多套项目中的案例,满足日常业务流程审批需求。一、项目形式springboot+vue+activiti集成了activiti在线编辑器,流行的前后端分离部署开发模式,快速开发平台,可插拔工作流服务......
  • 基于Java+Springboot框架自习室教室座位预约系统设计与实现
     博主介绍:黄菊华老师《Vue.js入门与商城开发实战》《微信小程序商城开发》图书作者,CSDN博客专家,在线教育专家,CSDN钻石讲师;专注大学生毕业设计教育和辅导。所有项目都配有从入门到精通的基础知识视频课程,学习后应对毕业设计答辩。项目配有对应开发文档、开题报告、任务书、P......
  • 如何使用spring状态机
    让我们通过一个具体的例子来深入了解Spring状态机的使用。这个例子将模拟一个简单的订单处理流程,其中订单有三个状态:待支付(`NEW`)、已支付(`PAID`)、已完成(`COMPLETED`)。订单状态的转换通过两个事件触发:支付(`PAY`)和完成订单(`COMPLETE`)。步骤1:添加依赖首先,确保你的项目中包含......
  • 【Kingbase8数据库】springboot jpa集成Kingbase8各种报错
    AccesstoDialectResolutionInfocannotbenullwhen‘hibernate.dialect’notset去了stackoverflow:java-SpringBootJPA-AccesstoDialectResolutionInfocannotbenullwhen‘hibernate.dialect’notset-StackOverflow不是PostgreSQL,那就换成mysql的嘛:spr......
  • Springboot+vue的高校科研信息管理系统(有报告)。Javaee项目,springboot vue前后端分离项
    演示视频:Springboot+vue的高校科研信息管理系统(有报告)。Javaee项目,springbootvue前后端分离项目。项目介绍:采用M(model)V(view)C(controller)三层体系结构,通过Spring+SpringBoot+Mybatis+Vue+Maven来实现。MySQL数据库作为系统数据储存平台,实现了基于B/S结构的Web系......