【Spring】代理模式——动态代理

1、基本概念

  • 动态代理允许我们在运行时根据指定的接口动态地创建代理对象,这个代理对象与目标对象实现了相同的接口,因此可以完全替代目标对象执行相同的操作。
  • 通过动态代理,我们可以在不修改目标对象代码的情况下,为目标对象添加额外的功能或逻辑。
  • JDK动态代理和CGLIB动态代理是Java中两种常见的动态代理实现方式,它们各自有不同的特点和适用场景。

2、原理

  • 动态代理的实现原理主要基于Java的反射机制。
  • 在运行时,动态代理会根据指定的接口创建一个代理类,并在代理类中重写接口中的所有方法。
  • 当代理对象调用接口方法时,实际执行的是代理类中的对应方法。
  • 在代理类中,我们可以通过反射机制调用目标对象的方法,并在执行前后添加自己的逻辑。

3、应用场景

  • 动态代理在Spring框架中得到了广泛应用,主要用于实现AOP(面向切面编程)功能。
  • AOP是一种编程范式,用于处理系统中散布于各个模块之间的交叉关注点问题,如事务管理、日志记录、安全控制等。
  • 通过动态代理,Spring可以在运行时为目标对象创建代理对象,并在代理对象中织入切面逻辑,从而实现对这些交叉关注点问题的统一处理。

4、常见实现方式

4.1  JDK动态代理

4.1.1简介

  • JDK动态代理是Java标准库提供的一种动态代理实现方式,它基于Java的反射机制。
  • JDK动态代理只能代理实现了接口的类,通过动态生成代理类来实现对目标对象的代理。
  • 在JDK动态代理中,代理类是由Java运行时环境动态生成的,每个代理类都会实现与被代理对象相同的接口。
  • 通过使用ProxyMethodInvocationHandler类库来完成动态代理
  • JDK动态代理的优点是简单易用,因为它是Java标准库的一部分,无需引入额外的依赖。

4.1.2代码示例

步骤1:先创建UserService接口

public interface UserService {
void save();
void delete();
}

步骤2:创建一个接口的实现类UserServiceImpl(目标类对象)

public class UserServiceImpl implements UserService {
@Override
public void save() {
System.out.println("主业务逻辑:增加用户管理");
}
@Override
public void delete() {
System.out.println("主业务逻辑:删除用户管理");
}
}

步骤3:创建动态代理(InvocationHandler接口的实现类)

public class MyInvocationHandler implements InvocationHandler {
private Object obj;
public MyInvocationHandler(Object obj){
this.obj=obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws
Throwable {
        System.out.println("开始监控系统...");
long t1 = System.currentTimeMillis();//当前时间
try {
Thread.sleep((int) (Math.random() * 2000));
} catch (InterruptedException e) {
e.printStackTrace();
}
Object o = method.invoke(obj, args);
long t2 = System.currentTimeMillis();//当前时间
System.out.println("结束监控系统...");
System.out.println("一共耗费了" + (t2 - t1) + "毫秒");
//加日志处理
System.out.println(LocalDate.now() + "访问系统");
return o;
}
}

步骤4:使用Proxy,创建代理对象

public class ProxyUtil {
public static Object getProxy(Object target, InvocationHandler handler)
{
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), handler);
}
}

步骤5:测试

public static void main(String[] args) {
UserService service= new UserServiceImpl();
UserService proxy = (UserService) ProxyUtil.getProxy(service,
new MyInvocationHandler(service));
proxy.save();
System.out.println("------------------------------------");
proxy.delete();
}
}

4.2  CGLIB动态代理

4.2.1简介

  • CGLIB(Code Generation Library)是一个强大的、高性能的代码生成库,它可以扩展Java类和实现Java接口。
  • 与JDK动态代理不同,CGLIB动态代理是通过继承目标类来创建代理对象的,因此它可以代理没有实现接口的类。
  • CGLIB动态代理底层使用ASM(一个Java字节码操控和分析框架)来操作字节码生成新的类,为对象引入间接级别,以控制对象的访问。
  • CGLIB动态代理的优点在于它可以代理没有实现接口的类,提供了更多的灵活性。
  • CGLIB动态代理不能对final类及final方法进行代理。

4.2.2代码示例

步骤1:创建目标类

public class AccountService {
public void save(){
System.out.println("保存账务管理业务");
}
public void pay(){
System.out.println("支持管理业务");
}
}

步骤2:编写增强类

public class MyInterceptor implements MethodInterceptor {
private Object obj;
public MyInterceptor(Object obj) {
this.obj = obj;
}
@Override
public Object intercept(Object o, Method method, Object[] objects,
MethodProxy methodProxy) throws Throwable {
System.out.println("进入系统");
Object invoke = method.invoke(obj, objects);
System.out.println(LocalDate.now());
return invoke;
}
}

步骤3:测试

public class Test {
public static void main(String[] args) {
AccountService service = new AccountService();
Enhancer enhancer = new Enhancer();
enhancer.setClassLoader(AccountService.class.getClassLoader());
enhancer.setSuperclass(AccountService.class);
enhancer.setCallback(new MyInterceptor(service));
AccountService accountService = (AccountService) enhancer.create();
accountService.save();
System.out.println("------------------------------");
accountService.pay();
}
}
  • 24
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring代理模式是指通过Spring框架提供的代理机制,在不修改原始对象源码的情况下,增强代码的功能。代理模式可以理解为一个中介,它给某个对象提供一个代理对象,并控制原始对象的引用,从而实现对原始对象的操作增强。在Spring中,代理模式主要用于实现AOP(面向切面编程)和IOC(控制反转)的功能。 静态代理是一种实现代理模式的方式。在静态代理中,代理对象和被代理对象之间存在强耦合关系,代理对象需要知道被代理对象的具体变量或方法才能进行调用。这种方式的适用性较弱,当需要代理多个对象时,需要创建多个代理对象,增加了工作量和维护成本。 与静态代理相比,JDK动态代理Spring中更常用的方式。JDK动态代理利用Java的反射机制,在运行时动态生成代理对象,无需提前编写代理类。通过代理对象,可以在原始对象的方法执行前后插入增强逻辑,实现切面功能。这种方式更灵活,可以代理多个对象,减少了代码的冗余。 总结来说,Spring代理模式是通过Spring框架提供的代理机制,实现在不修改源码的基础上增强代码的功能。代理模式可以是静态代理或JDK动态代理,其中JDK动态代理Spring中常用的方式。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [spring代理模式](https://blog.csdn.net/weixin_43723296/article/details/125666513)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [spring简介及代理模式](https://blog.csdn.net/dpf373521/article/details/98520401)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [Spring框架(五)—— Spring 框架代理模式](https://blog.csdn.net/baidu_27414099/article/details/104440425)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值