一天天说jdk代理,到底是什么

133 阅读2分钟

通常jdk代理有两种,一种静态一种动态。

JDK静态代理

就是继承或者实现接口,编译期生成一份之后执行的class文件

public class Employee {  
    public void work() {  
        System.out.println("work");  
    }  
}

public class SuperEmployee extends Employee{  
  
    @Override  
    public void work() {  
        System.out.println("super======");  
        super.work();  
        System.out.println("super======");  
    }  
}

public class TestStaticProxy {  
    public static void main(String[] args) {  
        SuperEmployee superEmployee = new SuperEmployee();  
        superEmployee.work();  
    }  
}

静态代理,执行上,直接执行最终的代理对象。 讲到底就是重写。

JDK动态代理

先写个测试

public interface PersonTest {  
    void giveMoney();  
}

public class Student implements PersonTest {  
  
    private String name;  
  
    public Student(String name) {  
        this.name = name;  
    }  
  
    @Override  
    public void giveMoney() {  
        System.out.println(name + "上交班费50元");  
    }  
}

public class TestInvocationHandler<T> implements InvocationHandler {

	//invocationHandler持有的被代理对象
	T target;
		
	public TestInvocationHandler(T target) {
		
		this.target = target;

	}

	/**
	* proxy:代表动态代理对象
	* method:代表正在执行的方法
	* args:代表调用目标方法时传入的实参
	*/
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
	
		System.out.println("代理执行" +method.getName() + "方法");
		
		Object result = method.invoke(target, args);
		
		MonitorUtil.finish(method.getName());
		
		return result;
	
	}

}

public class ProxyTest {

	public static void main(String[] args) {
	
	//创建一个实例对象,这个对象是被代理的对象
	Person zhangsan = new Student("张三");
	
	//创建一个与代理对象相关联的InvocationHandler
	InvocationHandler testHandler = new TestInvocationHandler<Person>(zhangsan);
	
	//创建一个代理对象stuProxy来代理zhangsan,代理对象的每个执行方法都会替换执行Invocation中的invoke方法
	Person testProxy = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(),  new Class<?>[]{Person.class}, testHandler);
	
	//代理执行上交班费的方法
	testProxy.giveMoney();}

}

使用上,我们所实现TestInvocationHandler 需要将我们的目标类作为属性设置进来

对应所生成的class文件,使用jdk动态代理会生成新的class文件。

image.png

image.png

调用的最终对象就是是由这个class文件生成的对象。

我们看一下新的class文件内容


public final class $Proxy0 extends Proxy implements PersonTest {

	private static Method m1;  
	private static Method m2;  
	private static Method m3;  
	private static Method m0;

	static {  
		    try {  
		        m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));  
		        m2 = Class.forName("java.lang.Object").getMethod("toString");  
		        m3 = Class.forName("proxy.PersonTest").getMethod("giveMoney");  
		        m0 = Class.forName("java.lang.Object").getMethod("hashCode");  
		    } catch (NoSuchMethodException var2) {  
		        throw new NoSuchMethodError(var2.getMessage());  
		    } catch (ClassNotFoundException var3) {  
		        throw new NoClassDefFoundError(var3.getMessage());  
		    }  
		}
	public final void giveMoney() throws  {  
	    try {  
	        super.h.invoke(this, m3, (Object[])null);  
	    } catch (RuntimeException | Error var2) {  
	        throw var2;  
	    } catch (Throwable var3) {  
	        throw new UndeclaredThrowableException(var3);  
	    }  
	}

	
}


public class Proxy implements java.io.Serializable {
	protected InvocationHandler h;
}

image.png

结论

从所生成的代理类class文件,初始化的方法既继承了我们的Proxy类,又实现了我们需要增强的接口。在生成的代理class文件中,我们实现的giveMoeny方法,直接调用了我们所实现的InvocationHandler 的invoke方法,再到里面,通过反射,执行我们自己实现的giveMeney方法。 可以看出,动态代理对于静态代理而言,动态代理可以同一个加强方法应用在不同类上。