深入理解Java动态代理机制:运行机制、代码分析与代理模式分类

基础:需要具备面向对象设计思想,多态的思想,反射的思想;

深入理解Java动态代理机制:运行机制、代码分析与代理模式分类

Java 动态代理机制出现了,这让 Java 开发人员无需手工编写代理类。他们只需简单地指定一组接口以及委托类对象,就能够动态地获得代理类。代理类会把所有的方法调用分派到委托对象上并进行反射执行。在这个分派执行的过程中,开发人员可以根据需要调整委托类对象及其功能。这是一个非常灵活且有弹性的代理框架。读者阅读本文后,会对 Java 动态代理机制有更深入的理解。首先,本文从 Java 动态代理的运行机制和特点开始,接着对其代码进行了分析,并且推演了动态生成类的内部实现。

代理模式的基本概念和分类

代理模式的作用是为其他对象提供一个代理,以实现对该对象的访问控制。代理对象起到中介的作用,它可以去除某些服务,或者添加额外的服务。引用他人的话来说就是:代理类负责为委托类预处理消息,对消息进行过滤并转发,同时还会在委托类执行消息后进行后续处理。

代理模式在开发中的应用场景

远程代理:为不同地理的对象提供局域网代表对象。

虚拟代理会根据需求对资源消耗很大的对象进行延迟处理,等到真正需要的时候才去创建。例如在网页中,会先显示文字,之后再显示图片。

保护代理的作用是控制不同用户的访问权限。例如:只有在客户注册成功之后,才能够进行增删改查等操作。

智能引用代理:提供对目标代理额外的服务。

代理模式的实现方式

使用继承和聚合实现动态代理,哪种更好呢!

public interface Moveable {
	public void move();
}
类 Car 实现了 Moveable 接口。
	@Override 
	  public void move() {
		try {
通过 new Random().nextint(1000) 来确定休眠时间,然后让线程进行休眠。
System.out 输出了“……行驶中……”。
		}
捕获(InterruptedException e)。
以下是改写后的句子:在处理异常的过程中,自动生成了一个捕获块。它用于捕获可能出现的异常情况,以确保程序的稳定性和可靠性。
			e.printStackTrace();
		}
	}
}
公共类 Car2 继承自 Car 类。
	@Override 
	  public void move() 
	  {
		//分离代码,增加业务逻辑 
系统当前时间的毫秒值被获取并赋值给了一个名为 startTime 的长整型变量,这个变量被初始化为一个较大的时间值。
“汽车开始行驶……”被 System.out 打印了出来。
		super.move();
System.currentTimeMillis() 的值被赋给了 long 类型的变量 endTime ,这个 endTime 是一个较长的时间值 。
	}
}

继承方式实现代理

Moveablecar2=newCar2();

car2.move();

聚合方式实现代理

Carcar=newCar();

Moveablem=newCar3(car);

m.move();

总结

使用继承方式存在不够灵活的情况。在功能叠加时,只能通过臃肿地扩展代理类来实现。

使用聚合的方式,代理之间可以相互传递,灵活的组合代理;

公共类 CarLogProxy 继承自 Car 类。
	@Override 
	  public void move() 
	  {
		//分离代码,增加业务逻辑 
		long startTime=System.currentTimeMillis();
		System.out.println("日志开始……");
		super.move();
		long endTime=System.currentTimeMillis();
		System.out.println("日志结束……");
	}
}
公共类 CarTimeProxy 实现了 Moveable 接口。
	public CarTimeProxy(Car car) 
	  {
		super();
		this.car=car;
	}
	private Carcar;
	@Override 
	  public void move() {
		//分离代码,增加业务逻辑 
		long startTime=System.currentTimeMillis();
		System.out.println("汽车开始行驶……");
		car.move();
		long endTime=System.currentTimeMillis();
		System.out.println("汽车结束行驶……时间:"+(endTime-startTime)+"ms");
	}
}
@Test: 
Car car =new Car();
创建一个 CarTimeProxy 实例 ctp,这个实例是通过传入一个 car 对象来创建的。
创建一个 CarLogProxy 实例,将 ctp 作为参数传递给它,然后将这个实例赋值给 clp,即 clp 等于新创建的 CarLogProxy 对象,该对象是基于 ctp 创建的。
clp.move();
//还可以通过接口相互传递代理实例 
创建了一个名为 CarLogProxy 的实例 clp1,这个实例是通过传入一个名为 car 的对象来创建的。
创建一个名为 CarTimeProxy 的对象 ctp1,该对象通过参数 clp1 进行初始化。
ctp1.move();

JDK动态代理和CGlib动态代理

JDK动态代理

代理实现

如果不同的对象要实现相同功能的代理类,应该如何处置?

此时可以尝试把它集成到同一个代理类里,也就是动态代理。动态代理能够实现对不同类以及不同方法的代理。

大致过程如下:

Java 的动态代理类处在 java.lang.reflect 包之中,通常主要会涉及到以下两个类:

InterfaceInvocationHandler 这个接口中仅仅定义了一个方法,该方法为 Publicobjectinvoke(Objectobj,Methodmethod,Object[]args) 。

obj:一般是指代理类

method:是被代理的方法

args为该方法的参数数组。

这个抽象的方法在代理类中动态实现。

(2)Proxy:该类即为动态代理类

创建一个代理实例,使用指定的类加载器、接口数组和调用处理器。具体来说,通过调用 statixObject 的 newProxyInstance 方法,传入类加载器、接口数组以及调用处理器,从而创建出一个代理对象,该代理对象可以在调用目标对象的方法时进行拦截和处理。

返回一个甙类的实例,返回后的代理类能够当作被代理类来使用,并且可以使用被代理类在接口中声明过的方法。

实现实例:

@ TimeHandler 
公共类 TimeHandler 实现了 InvocationHandler 接口。
构造函数 TimeHandler 接收一个对象参数 target 。
		super();
		this.target = target;
	}
	private Objecttarget;
	
	@Override 
该方法接收三个参数,分别是代理对象 proxy、方法 method 以及参数数组 args,然后返回一个 Object 对象。
	    throws Throwable {
		long startTime=System.currentTimeMillis();
		System.out.println("汽车开始行驶……");
		method.invoke(target);
		long endTime=System.currentTimeMillis();
		System.out.println("汽车结束行驶……时间:"+(endTime-startTime)+"ms");
		return null;
	}
}

@被代理类的接口
public interface Moveable {
  public void move();
}
@被代理的类

public class Car implements Moveable{
	@Override 
	  public void move() {
		try {
			Thread.sleep(new Random().nextint(1000));
			System.out.println("……行驶中……");
		}
捕获到(InterruptedException 异常 e)。
			// TODO Auto-generated catch block 
			e.printStackTrace();
		}
	}
}

@测试

public class Test { 
   
公共静态 void 主函数(字符串数组参数){
   Car car=new Car(); 
创建一个 InvocationHandler 实例 h,该实例是通过将 car 作为参数传递给 TimeHandler 类来创建的。
   Classcls=car.getClass(); 
    
创建一个可移动的对象 m,m 等于通过 (Moveable)Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), h) 创建的代理实例。
   m.move(); 
  } 
} 

&&测试结果

梳理总结

所为的DynamicProxy是这样一种class:

在运行时会生成一个 class,这个 class 要去实现一组 interface。当使用动态代理类的时候,就必须要实现 InvocationHandler 接口。

JDK动态代理的一般步骤

创建一个类,这个类要实现接口 InvocationHandler。并且这个类必须要实现 invoke()这个方法。

2.创建被代理的类以及接口

3.调用Proxy的静态方法,创建一个代理类

创建一个代理实例,需要指定类加载器(ClassLoader)、接口数组(Class[])以及调用处理器(InvocationHandler)。通过 newProxyInstance 方法来实现这一操作,该方法接收这三个参数,分别用于确定代理实例的相关特性和行为。

4.通过代理调用方法

CGlib动态代理的实现

代理实现

@引入cglib-node-2.2.jar包

@CglibProxy 拦截类实现了接口 MethodInterceptor,并且对 intercept 拦截方法进行了重写。

公共类 CglibProxy 实现了 MethodInterceptor 接口。
创建了一个名为 Enhancer 的对象,并将其赋值给 private 修饰的变量 enhancer 。
要获取类 cl 的代理对象。
	  {
		//设置创建子类的类 
		enhancer.setSuperclass(cl);
		enhancer.setCallback(this);
		return enhancer.create();
	}
	
	@Override 
公共的对象拦截(对象 obj,方法 m,对象数组 args,方法代理 proxy)并抛出异常 Throwable
	{
		System.out.println("日志开始……");
		//代理类调用父类的方法 
		proxy.invokeSuper(obj, args);
		System.out.println("日志结束……");
		return null;
	}
}

@被代理类Train

public class Train { 
  public void move() 
  { 
System 输出了“火车行驶中……”。
  } 
} 

@测试类

public class Test { 
   
  public static void main(String[] args) { 
创建了一个 CglibProxy 的实例,名为 proxy 。
通过 proxy 获取 Train 类的代理对象,将其赋值给变量 t,t 为 Train 类型的对象。
   t.move(); 
  } 
} 

##测试结果:

梳理总结

使用CglibProxy实现动态代理的一般步骤

创建一个类,让这个类去实现接口 MethodInterceptor ,接着对 intercept 方法进行重写。

2、创建被代理类

3、调用代理类自定义的方法,得到一个代理实例

4、通过代理实例调用被代理类的需要执行的方法

比较总结

JDK动态代理

1、只能代理实现了接口的类

2、没有实现接口的类不能实现JDK的动态代理

CGlib动态代理

1、针对类来实现代理

对执行目标类创建一个子类,利用方法拦截技术来拦截所有父类方法的调用。

模拟代理产生步骤

思路:

通过 Proxy 的 newProxyInstance 这个方式能够返回代理对象。

你可能想看:
« 上一篇
下一篇 »

相关推荐

java中什么是冒泡,冒泡算法

2026年09月06日

27阅读

java中冒号,java双冒号

2026年09月06日

26阅读

java中的->,java中的是什么意思

2026年09月06日

24阅读

java中的super用法,Java中super的说明

2026年09月06日

28阅读

java中反射的应用,java中反射的应用场景

2026年09月06日

26阅读

java中开关的定义,Java关键字有哪些

2026年09月06日

26阅读