先通过一段代码回顾一下静态代理:
/**
* 静态代理举例
*/
//接口
interface ClothFactory{
void produceCloth(); //生产服装
}
//代理类
class ProxyClothFactory implements ClothFactory{
private ClothFactory factory; //用被代理类对象进行实例化
public ProxyClothFactory(ClothFactory factory) {
this.factory=factory;
}
@Override
public void produceCloth() {
System.out.println("代理工厂做一些准备工作");
factory.produceCloth();
System.out.println("代理工厂做一些后续收尾工作");
}
}
//被代理类
class NikeClothFactory implements ClothFactory{
@Override
public void produceCloth() {
System.out.println("耐克工厂生产一批运动服装");
}
}
//测试
public class StaticProxyTest {
public static void main(String[] args) {
NikeClothFactory nike = new NikeClothFactory();
ProxyClothFactory proxyClothFactory = new ProxyClothFactory(nike);
proxyClothFactory.produceCloth();
}
}
运行:
静态代理之所以为静态,是因为在编译期间代理类和被代理类都已经确定了下来。
静态代理中一个被代理类对应一个代理类,存在代码量大且不宜维护等缺点,因此引入动态代理。
动态代理举例:
package com.atguigu.java;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 动态代理的举例
*/
interface Human{
String getBelief();
void eat(String food);
}
//被代理类
class SuperMan implements Human{
@Override
public String getBelief() {
return "I believe I can fly.";
}
@Override
public void eat(String food) {
System.out.println("我喜欢吃"+food);
}
}
/* 要想实现动态代理,需要解决两个问题:
问题一:如何根据加载到内存中的被代理类,动态创建一个代理类及其对象
问题二:当通过代理类的对象调用方法a时,如何动态地去调用被代理类中的同名方法a
*/
//写一个生产代理类的工厂
class ProxyFactory{
//调用此方法返回一个代理类的对象,解决问题一
public static Object getProxyInstance(Object obj){ //传入的obj是被代理类的对象,根据此对象 动态地 造一个代理类对象,此方法返回值类型Object可转为某一个具体代理类的类型
MyInvocationHandler handler = new MyInvocationHandler(); //作为参数3
handler.bind(obj); //此处相当于赋值
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler);
//参数1:表示被代理类对象obj是哪个类的加载器加载的,代理类对象也用此加载器加载
//参数2:表示被代理类对象obj实现了哪些接口,代理类对象也实现这些接口
//参数3:是InvocationHandler(是接口)类型,传入此参数解决问题二
}
}
//InvocationHandler是一个接口,需要我们自定义一个此接口实现类
class MyInvocationHandler implements InvocationHandler{
private Object obj; //声明为Object,但需要使用被代理类对象赋值
public void bind(Object obj){ //绑定方法赋值(相当于一个set方法)
this.obj=obj;
}
//当通过代理类对象调用方法时,就会自动地调用如下的invoke方法。所以将 被代理类 要执行的功能(方法)声明在invoke方法中。
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//参数1 proxy其实是就是上面返回的代理类对象;
//参数2 method是代理类调用的那个方法,此方法也就作为被代理类对象要调用的方法
//参数3 args是同名的方法的参数
Object returnValue=method.invoke(obj,args); //obj是 被代理类的对象
//上述方法的返回值就作为当前类中invoke()方法的返回值
return returnValue;
}
}
public class ProxyTest {
public static void main(String[] args) {
//先造一个被代理类的对象
SuperMan superMan = new SuperMan();
//看superMan实现了什么接口,造一个实现这些接口的代理类,所以不能用superMan类型接收,可以使用 他们共同的Human接口类型接收
Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan); //获取代理类对象
String belief = proxyInstance.getBelief();
System.out.println(belief); //I believe I can fly.
proxyInstance.eat("四川麻辣烫"); //我喜欢吃四川麻辣烫
System.out.println("****************");
//动态代理:不通过自定义代理类,通过被代理类和接口动态创建一个代理类
NikeClothFactory nikeClothFactory = new NikeClothFactory(); // 创建一个被代理类
ClothFactory proxyClothFactory= (ClothFactory) ProxyFactory.getProxyInstance(nikeClothFactory); //强转为接口类型
proxyClothFactory.produceCloth(); //耐克工厂生产一批运动服装
}
}
静态代理的代理类是直接写好的;动态代理没有在编译时显式定义代理类,而是在运行时根据传进来的被代理类对象是谁,动态方式创建代理类。