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

引言

在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,在调用方法前后可以添加额外的处理逻辑

  • 18
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值