动态代理

2022-09-14 20:33:28 浏览数 (1)

1、动态代理概述

代理:本来应该自己做的事情,却请了别人来做,被请的人就是代理对象。 举例:春季回家买票让人代买,租房找中介 动态代理:在程序运行过程中产生的这个对象 如何让程序在运行过程中帮我们动态地产生这个对象呢?可以通过Java的反射实现。

为什么要用动态代理

​ 动态代理的目的是在不更改原有对象(目标对象)的基础上实现功能代码的增强

2、动态代理的种类

(1) JDK动态代理

(2)CGLIB动态代理

3、JDK动态代理

3.1、概述

JDK的动态代理是JDK自带的动态代理技术,所以使用JDK动态代理的时候不需要额外引入第三方的jar包!

JDK动态代理是对对象本身进行代理的一种技术!他是通过java.lang.reflect包下提供的一个Proxy类的newProxyInstance方法和一个InvocationHandler接口来实现动态代理对象的!

但JDK提供的代理只能针对实现接口的对象做代理!如果要对没有接口实现的类做代理的话就要用cglib了。

3.2、实现步骤

需求:给钢铁侠添加火箭助推器

1、创建接口(火箭助推器接口)

代码语言:javascript复制
public interface Rocket {
	public void takeOff();
}

2、创建目标对象钢铁侠并实现火箭助推器接口

代码语言:javascript复制
public class IronMan implements Rocket {

	@Override
	public void takeOff() {
		System.out.println("i can fly!!!");
	}

}

3、创建动态代理启用控制类,该类功能是对方法功能进行增强,该类实现InvocationHandler接口

代码语言:javascript复制
 class MyInvocationHandler implements InvocationHandler{
	
	//目标对象
	Object obj;
	
	public MyInvocationHandler(Object obj) {
		super();
		this.obj = obj;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		System.out.println("火箭助推器被增强了");//增强的功能代码
		Object rst = method.invoke(obj, args);//执行目标对象方法
		return rst;
	}
	
}

4、创建目标对象,并通过Proxy代理类的newProxyInstance方法为其生成代理对象

代码语言:javascript复制
public static void main(String[] args) {
		IronMan ir = new IronMan();//创建目标对象
		InvocationHandler h = new MyInvocationHandler(ir);//将目标对象传入控制器中等待被代理
		//生成代理对象
		Rocket proxy = (Rocket) Proxy.newProxyInstance(ir.getClass().getClassLoader(), ir.getClass().getInterfaces(), h );
		proxy.takeOff();
	}

4、CGLIB动态代理

4.1、概述

cglib:code generator library,代码生成库,他可以动态的生成字节码对象,可以凭空创建一个字节码对象。

4.2、CGLIB原理

jdk代理是对类的对象进行代理,而CGLIB代理是通过创建一个目标对象的子类的形式进行代理,也就是CGLIB在类的字节码阶段,就已经把增强的代码织入进去了,之后再用增强的字节码对象创建该类的子类对象,从而实现了动态代理,达到代码增强的目的!

所需Jar包

  • asm-2.2.3.jar
  • asm-commons-2.2.3.jar
  • asm-util-2.2.3.jar
  • cglib-nodep-2.1_3.jar

4.3、CGLIB动态代理实现步骤

1、生成一个字节码对象 ----> 该对象就是CGLIB凭空造出的字节码对象

2、设置字节码对象的父类 —> 该父类就是要增强的目标对象

3、通过生成的子类去增程父类方方法—>在重写的过程中调用父类的原方法(回调)

4、通过这个生成的字节码对象创建增强对象 --> 再去调用方法,该方法就被增强了

4.4、CGLIB代码增强演示

1、导包

2、创建目标对象(无序实现接口)

代码语言:javascript复制
//目标对象(要增强的类)
public class SuperMan {
	public void fly(){
		System.out.println("i can fly!!!");
	}
}

3、创建用于回调增强的方法类

代码语言:javascript复制
public class MyCallback implements MethodInterceptor {

	/*
	 * target:目标对象
	 * method:目标对象中的方法
	 * args:方法的实参列表
	 * met:代理对象中的方法(子类中的方法)
	 * 
	 * */
	@Override
	public Object intercept(Object target, Method method, Object[] args,
			MethodProxy met) throws Throwable {
		System.out.println("火箭助推器");
		return met.invokeSuper(target, args);//子类中的方法执行
	}

}

4、创建子类字节码对象,设置回调,实现增强

代码语言:javascript复制
public static void main(String[] args) {
		Enhancer en = new Enhancer();//凭空创建字节码对象
		en.setSuperclass(SuperMan.class);//设置该字节码对象的父类是SuperMan
		Callback cb = new MyCallback();//创建用于增强的回调对象
		
		en.setCallback(cb);//设置子类字节码对象的回调方法
		
		SuperMan sm = (SuperMan) en.create();//创建代理对象
		sm.fly();//调用代理对象中代理的方法,该方法以被增强
		
	}

运行结果

0 人点赞