在Spring中的相关介绍 https://blog.csdn.net/m0_37989980/article/details/104593905
具体什么是静态代理、动态代理这里不赘述, 可以参考上面 !
一、静态代理/**
* Description: 传统静态代理的举例
*
* 特点: 代理类和被代理类在编译期间, 就确定下来了
*
* @author zygui
* @date Created on 2020/6/18 15:12
*/
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("Nike工厂生产一批运动服");
}
}
public class StaticProxyTest {
public static void main(String[] args) {
// 创建被代理对象
ClothFactory nike = new NikeClothFactory();
// 创建代理类对象
ClothFactory proxy = new ProxyClothFactory(nike);
// 代理类执行的工作,实际是被代理类干的事情
proxy.produceCloth();
}
}
总结:
代理类
和被代理类
(委托类/真实类) 实现同一个接口, 代理类中包含被代理类
, 当调用代理类执行相应的操作方法时, 执行的是被代理类(真实类)中的方法;
代理类在运行前就已经和被代理类的关系就确定了;
二、动态代理想要实现动态代理, 需要解决的问题?
- 问题一: 如何根据加载到内存中被代理类, 动态的创建一个代理类及其对象
- 问题二: 当通过代理类的对象调用方法时, 如何动态的去调用被代理类中的同名方法
/**
* Description: 动态代理的举例
*
* 代理类和被代理类要实现同一接口!
*
* @author zygui
* @date Created on 2020/6/18 15:39
*/
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);
}
}
/*
想要实现动态代理, 需要解决的问题?
问题一: 如何根据加载到内存中被代理类, 动态的创建一个代理类及其对象
问题二: 当通过代理类的对象调用方法时, 如何动态的去调用被代理类中的同名方法
*/
// 生产代理类的工厂
class ProxyFactory {
/**
* 调用此方法,通过传递过来的被代理类对象, 返回一个该被代理类对象的代理对象; 解决问题一
*
* @param obj 被代理类的对象
* @return
*/
public static Object getProxyInstance(Object obj) {
/*
// 用来创建代理类的方法
public static Object newProxyInstance(
ClassLoader loader, // 和被代理类使用同一加载器
Class[] interfaces, // 因为代理类和被代理类要实现同一接口, 这里获取被代理类所实现的接口, 供创建出来的代理类也实现这些接口
InvocationHandler h // 解决上面的问题二: 会去找下面的Invoke方法
)
也就是说, 创建的代理类对象去调用a方法时, 被代理类就会去handler里面调用invoke方法
*/
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(), 在invoke方法中的参数Method就是代理类对象调用的方法对象
// 将被代理类要执行的方法a的功能就声明在invoke()中了
@Override
/*
参数:
Object proxy : 代理类对象
Method method : 代理类调用的那个方法,这里就是该方法
Object[] args : 代理类调用的那个方法中的参数
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// method: 即为 代理类对象调用的方法, 此方法也就作为了 被代理类对象 要调用的方法
// 下面的invoke方法中的 参数1: 调用该方法的对象(这里就是被代理类的对象), 参数2: 是调用该方法的参数
Object retrunValue = method.invoke(obj, args);
return retrunValue;
}
}
public class DynamicProxyTest {
public static void main(String[] args) {
// 被代理类对象
SuperMan superMan = new SuperMan();
// proxyInstance代理类对象(此时是superMan的代理对象)
Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);
// 通过代理类对象调用下面的方法, 就动态调用了被代理类中的同名方法
String belief = proxyInstance.getBelief();
System.out.println(belief);
proxyInstance.eat("四川麻辣烫");
}
}
此时通过调用代理类中的方法, 就动态的调用的是被代理类中的同名方法了!
总结:
- 创建一个生产
代理类
的一个工厂类,public static Object getProxyInstance(Object obj) {
, obj就是被代理对象, 根据被代理对象创建一个其代理类; 通过Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler);
方法来创建代理类; - 上面参数3对象, 需要实现
InvocationHandler
, 重写invoke
方法, 该方法中的参数就已经是代理类对象, 已经代理类调用的方法, 方法参数
; method.invoke(obj, args);
此时通过反射, 将被代理类的对象传递过来, 已经参数
, 实现 调用代理类的方法, 实际是调用被代理类的方法