动态代理是在静态代理上的升华,如果读者对代理还不太了解或者静态代理不太明白,建议读者先了解一下相关知识,在此自荐两篇文,有兴趣的读者欢迎来翻翻:
1、回顾静态代理的缺点:
1.代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。这样就出现了大量的代码重复。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
2.代理对象只服务于一种类型的对象,如果要服务多类型的对象。势必要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了。
2、实现动态代理:
实现动态代理需要解决的问题:
- 问题 1 : 如何根据加载到内存中的代理类,动态的创建一个代理类及其对象。
- 问题 2 : 当通过代理类的对象调用方法时,如何动态的去调用被代理类中的同名方法。
解决1:通过Proxy.newProxyInstance()方法动态创建代理类。
/**
* 代理工厂,根据被代理的对象生产代理类
*/
class ProxyFactory{
// 调用此方法,返回一个代理类的对象,解决问题
public static Object getProxyInstance(Object obj) { // obj:被代理的对象
// 此处用于解决问题 2
MyInvocationHandler handler = new MyInvocationHandler();
handler.bind(obj);
//返回一个代理对象
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler);
}
}
解决2:通过 implements InvocationHandler:
class MyInvocationHandler implements InvocationHandler{
private Object obj; // 需要使用被代理类的对象进行赋值
public void bind(Object obj) {
this.obj = obj;
}
/**
* 当我们通过代理类的对象,调用方法 a 时,就会自动的调用如下的方法 invoke()
* 将被代理类要执行的方法 a 的功能就声明在 invoke 中
* @param o
* @param method
* @param objects
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/**
* method : 即为代理类对象调用的方法,此方法也就作为了被代理对象要调用的方法
* obj : 被代理的对象
*
* args : 参数
*/
Object returnValue = method.invoke(obj, args);
// 上述方法的返回值就作为当前类中的invoke()的返回值
return returnValue;
}
}
3、完整代码:
package com.pxl.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 动态代理
*/
interface Human{
String getBelief();
void ead(String food);
}
// 被代理类
class SuperMan implements Human{
@Override
public String getBelief() {
return "I believe I can fly!";
}
@Override
public void ead(String food) {
System.out.println("我喜欢吃" + food);
}
}
/**
* 要想实现动态代理,需要解决的问题?
* 问题 1 : 如何根据加载到内存中的代理类,动态的创建一个代理类及其对象。
* 问题 2 : 当通过代理类的对象调用方法时,如何动态的去调用被代理类中的同名方法。
*/
/**
* 代理工厂,根据被代理的对象生产代理类
*/
class ProxyFactory{
// 调用此方法,返回一个代理类的对象,解决问题
public static Object getProxyInstance(Object obj) { // obj:被代理的对象
MyInvocationHandler handler = new MyInvocationHandler();
handler.bind(obj);
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler);
}
}
class MyInvocationHandler implements InvocationHandler{
private Object obj; // 需要使用被代理类的对象进行赋值
public void bind(Object obj) {
this.obj = obj;
}
/**
* 当我们通过代理类的对象,调用方法 a 时,就会自动的调用如下的方法 invoke()
* 将被代理类要执行的方法 a 的功能就声明在 invoke 中
* @param o
* @param method
* @param objects
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/**
* method : 即为代理类对象调用的方法,此方法也就作为了被代理对象要调用的方法
* obj : 被代理的对象
*
* args : 参数
*/
Object returnValue = method.invoke(obj, args);
// 上述方法的返回值就作为当前类中的invoke()的返回值
return returnValue;
}
}
public class ProxyTest {
public static void main(String[] args) {
// proxyInstance : 代理类的对象
Human proxyInstance = (Human) ProxyFactory.getProxyInstance(new SuperMan());
// 当通过调用代理类对象调用方法时,会自动调用被代理类中的同名方法
String belief = proxyInstance.getBelief();
System.out.println(belief);
proxyInstance.ead("砂锅面!");
}
}