这边的东西全部来自 https://itbaima.net/document
静态代理
代理模式简介
就好比我开了个大棚,里面栽种的西瓜,那么西瓜成熟了是不是得去卖掉赚钱,而我们的西瓜非常多,一个人肯定卖不过来,肯定就要去多找几个开水果摊的帮我们卖,这就是一种代理。实际上是由水果摊老板在帮我们卖瓜,我们只告诉老板卖多少钱,而至于怎么卖的是由水果摊老板决定的。
代码实现
卖瓜版
- 卖瓜行为
public interface Shopper {
//卖瓜行为
void saleWatermelon(String customer);
}
- 卖瓜行为的实现(被代理类)
然后需要实现一下卖瓜行为,也就是我们要告诉老板卖多少钱,这里就直接写成成功出售:
public class ShopperImpl implements Shopper{
//卖瓜行为的实现
@Override
public void saleWatermelon(String customer) {
System.out.println("成功出售西瓜给 ===> "+customer);
}
}
- 代理卖瓜行为(代理类)
最后老板代理后肯定要用自己的方式去出售这些西瓜,成交之后再按照我们告诉老板的价格进行出售:
public class ShopperProxy implements Shopper{
private final Shopper impl;
public ShopperProxy(Shopper impl){
this.impl = impl;
}
//代理卖瓜行为
@Override
public void saleWatermelon(String customer) {
//首先进行 代理商讨价还价行为
System.out.println(customer + ":哥们,这瓜多少钱一斤啊?");
System.out.println("老板:两块钱一斤。");
System.out.println(customer + ":你这瓜皮子是金子做的,还是瓜粒子是金子做的?");
System.out.println("老板:你瞅瞅现在哪有瓜啊,这都是大棚的瓜,你嫌贵我还嫌贵呢。");
System.out.println(customer + ":给我挑一个。");
impl.saleWatermelon(customer); //讨价还价成功,进行我们告诉代理商的卖瓜行为
}
}
- 测试
现在我们来试试看:
public class Main {
public static void main(String[] args) {
Shopper shopper = new ShopperProxy(new ShopperImpl());
shopper.saleWatermelon("小强");
}
}
这样的操作称为静态代理,也就是说我们需要提前知道接口的定义并进行实现才可以完成代理
简略版
public class pox {
public static void main(String[] args) {
F1 f1=new F3(new F2());
f1.f1("proxy");
//F3proxy
//F2proxy
System.out.println(f1.getClass());
// F3
}
}
interface F1{
void f1(String s);
}
//被代理类
class F2 implements F1{
@Override
public void f1(String s2) {
System.out.println("F2"+s2);
}
}
//代理类
class F3 implements F1{
private final F1 f2;
public F3(F1 f2){
this.f2=f2;
}
@Override
public void f1(String s3) {
System.out.println("F3"+s3);
f2.f1(s3);
}
}
动态代理
动态代理实现的要求
1. 接口的要求
- 基于接口:动态代理工作于接口层面。这意味着只能代理接口,而不是类。所有被代理的方法必须在一个或多个接口中定义。
2. 实现 InvocationHandler
- 创建
InvocationHandler
实现:这个接口是动态代理的核心。你需要提供一个InvocationHandler
的实现,在其中定义方法调用的处理逻辑。每次代理接口的方法被调用时,都会转发到这个处理器的invoke
方法。
3. 使用 Proxy
类生成代理对象
- 使用
Proxy.newProxyInstance
方法:这个方法用于在运行时动态创建代理类的实例。它需要三个参数:- ClassLoader:用来定义代理类的
类加载器
。 - Interfaces:代理类需要实现的
接口列表
。 - InvocationHandler:
你实现的调用处理器
。
- ClassLoader:用来定义代理类的
4. 代理实例的使用
- 作为接口实例使用:动态代理返回的对象是实现了指定接口的代理实例。你可以像使用实现了接口的普通实例一样使用这个代理实例。
5. 方法调用的处理
- 方法转发逻辑:
InvocationHandler
的invoke
方法是所有方法调用的中转站。你可以在这里实现方法调用前后的自定义逻辑,例如日志记录、权限检查、事务处理等。
代理类 (DynamicProxyHandler)的代码模板
class DynamicProxyHandler implements InvocationHandler {
private final Object target;
public DynamicProxyHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before method: " + method.getName());
Object invoke = method.invoke(target, args);
System.out.println("After method: " + method.getName());
return invoke;
}
}
接口和测试
1. 无返回值无参数的接口 (T1)
interface T1 {
void noRnoP();
}
1.1测试
@Test
public void t1() {
T1 t1 = (T1) Proxy.newProxyInstance(T1.class.getClassLoader(),
new Class[]{T1.class},
new DynamicProxyHandler(new T1() {
@Override
public void noRnoP() {
System.out.println("T1 is called");
}
}));
t1.noRnoP();
System.out.println(t1.getClass());
}
2. 无返回值有参数的接口 (T2)
interface T2 {
void noRhaveP(String s);
}
2.1 测试
@Test
public void t2() {
T2 t2 = (T2) Proxy.newProxyInstance(T2.class.getClassLoader(),
new Class[]{T2.class},
new DynamicProxyHandler(new T2() {
@Override
public void noRhaveP(String s) {
System.out.println("T2 is called param is" + s);
}
}));
t2.noRhaveP("T2");
System.out.println(t2.getClass());
}
3. 有返回值无参数的接口 (T3)
interface T3 {
String haveRnoP();
}
3.1 测试
@Test
public void t3() {
T3 t3 = (T3) Proxy.newProxyInstance(T3.class.getClassLoader(),
new Class[]{T3.class},
new DynamicProxyHandler(new T3() {
@Override
public String haveRnoP() {
System.out.println("T3 is called");
return "T3 is returned";
}
}));
String s = t3.haveRnoP();
System.out.println(s);
System.out.println(t3.getClass());
}
4. 有返回值有参数的接口 (T4)
interface T4 {
String haveRhaveP(String s);
}
4.1 测试
@Test
public void t4() {
T4 t4 = (T4) Proxy.newProxyInstance(T4.class.getClassLoader(),
new Class[]{T4.class},
new DynamicProxyHandler(new T4() {
@Override
public String haveRhaveP(String s) {
System.out.println("T4 is called param is" + s);
return "T4 is returned param is" + s;
}
}));
String s1 = t4.haveRhaveP("T4");
System.out.println(s1);
System.out.println(t4.getClass());
}