设计模式 —— Proxy 代理模式

简介

  • Proxy代理模式是一种结构型设计模式。通过代理模式可以实现程序之间的解耦,可以解决在直接访问对象时带来的程序之间耦合度增大的问题。
  • 按照代理的创建时期,代理类分为两种:
    • 静态代理:在编译期,手动创建代理类,而不是由编译器生成代理类。
    • 动态代理:在运行期,运用反射机制动态而生成代理类。
      • JDK代理基于接口接口
      • CGlib代理基于继承

静态代理

  • 优点
    • 静态代理可以将目标类和目标方法封装起来,有隐蔽的作用。
  • 缺点
    • 静态代理类只能为特定的接口服务。
    • 如想要为多个接口服务则需要建立很多个代理类。

目录结构

  • cn.water
    • main
      • java
        • IProducer.java(接口)
        • Producer.java(实现类)
        • ProxyProducer.java(代理类)
    • test
      • staticTest.java(测试类)

接口

IProducer.java

1
2
3
4
5
6
7
8
9
10
11
package cn.water.StaticProxy;

public interface IProducer {

/** 销售 */
void saleProduct(float money);

/** 售后 */
void afterService(float money);

}

实现类

Producer.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package cn.water.StaticProxy;

public class Producer implements IProducer {

/** 销售 */
public void saleProduct(float money) {
System.out.println("生产者:通过[销售],获得了"+money+"元");
}

/** 售后 */
public void afterService(float money) {
System.out.println("生产者:通过[售后],获得了"+money+"元");
}
}

代理类

ProxyProducer.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package cn.water.StaticProxy;

public class ProxyProducer implements IProducer {

private Producer producer = new Producer();

/** 销售 */
public void saleProduct(float money) {
System.out.println("消费者:消费了"+money+"元");
producer.saleProduct(money * 0.2f);
}

/** 售后 */
public void afterService(float money) {
System.out.println("消费者:消费了"+money+"元");
producer.afterService(2);
}
}

测试类

staticTest.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package cn.water.test;

import cn.water.StaticProxy.IProducer;
import cn.water.StaticProxy.Producer;
import cn.water.StaticProxy.ProxyProducer;
import org.junit.Test;

public class staticTest {

@Test
public void test(){

/** 成员变量 */
final Producer producer = new Producer();
/** 获取动态代理对象 */
IProducer proxy = new ProxyProducer() ;
/** 调用方法 */
/* 销售方法经过加强,增强的方法被调用 */
proxy.saleProduct(999.12f);
/* 销售方法经过加强,方法不被调用 */
proxy.afterService(99f);

}


}

动态代理(JDK)

  • JDK动态代理基于 Java的反射机制 实现。
    • 因为Java的反射机制基于接口,所以目标类一定要有接口。
  • 基于JDK技术动态代理类技术核心:Proxy类InvocationHandler接口。(java.lang.reflect)
    • Proxy类中定义了生成JDK动态代理类的方法 getProxyClass(ClassLoader loader,Class... interfaces),返回class实例代表一个class文件。生成的动态代理类继承Proxy类(重要特性) ,并实现公共接口。
    • InvocationHandler接口 是被动态代理类回调的接口,我们所有需要增加的处理逻辑都添加到 invoke方法里面。
  • 匿名内部类参数必须为final类型

目录结构

  • cn.water
    • IProducer.java(接口)
    • Producer.java(实现类)
  • test
    • staticTest.java(测试类)

接口

IProducer.java

1
2
3
4
5
6
7
8
9
10
11
package cn.water.DynamicProxy.jdk;

public interface IProducer {

/** 销售 */
void saleProduct(float money);

/** 售后 */
void afterService(float money);

}

实现类

Producer.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package cn.water.DynamicProxy.jdk;

public class Producer implements IProducer {

/** 销售 */
public void saleProduct(float money) {
System.out.println("生产者:通过[销售],获得了"+money+"元");
}

/** 售后 */
public void afterService(float money) {
System.out.println("生产者:通过[售后],获得了"+money+"元");
}
}

测试类

staticTest.java

  • Proxy.newProxyInstance方法
    • 加载器
    • 接口
    • InvocationHandler接口
      • invoke方法
        • method:代表方法
        • args:参数
  • 匿名内部类只能访问方法内修饰符为final的参数
    • 为了保持数据的一致性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package cn.water.test;

import cn.water.DynamicProxy.jdk.IProducer;
import cn.water.DynamicProxy.jdk.Producer;
import org.junit.Test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class jdkTest {

@Test
public void test(){
/** 1、成员变量 */
final Producer producer = new Producer();
/** 2、获取动态代理对象 */
IProducer proxy = (IProducer) Proxy.newProxyInstance(
/* 类加载器 */
producer.getClass().getClassLoader(),
/* 实现类的接口 */
producer.getClass().getInterfaces(),
/** 增强代码 */
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
/* 方法参数 */
Float money = (Float) args[0];
/* 方法名 */
if ("saleProduct".equals(method.getName())) {
/* 调用方法 */
System.out.println("消费者:消费了"+money+"元");
result = method.invoke(producer, money * 0.2f);
}
if ("afterService".equals(method.getName())) {
/* 调用方法 */
System.out.println("消费者:消费了"+money+"元");
result = method.invoke(producer, 5);
}
/* 返回 */
return result;
}
}
);
/** 3、调用方法 */
/* 销售方法经过加强,增强的方法被调用 */
proxy.saleProduct(999.12f);
/* 销售方法经过加强,方法不被调用 */
proxy.afterService(999.12f);
}

}

动态代理(cglib)

目录结构

  • cn.water
    • Producer.java(类)
  • test
    • staticTest.java(测试类)

实现类

Producer.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package cn.water.DynamicProxy.cglib;

import cn.water.DynamicProxy.jdk.IProducer;

public class Producer {

/** 销售 */
public void saleProduct(float money) {
System.out.println("生产者:通过[销售],获得了"+money+"元");
}

/** 售后 */
public void afterService(float money) {
System.out.println("生产者:通过[售后],获得了"+money+"元");
}
}

测试类

  • Enhancer.create方法
    • 字节码
    • MethodInterceptor接口
      • intercept方法
        • method:代表方法
        • args:参数

staticTest.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package cn.water.test;

import cn.water.DynamicProxy.cglib.Producer;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.junit.jupiter.api.Test;

import java.lang.reflect.Method;


public class cglibTest {

@Test
public void test() {
/** 1、成员变量 */
final Producer producer = new Producer();
/** 2、获取动态代理对象 */
Producer cglibProducer = (Producer) Enhancer.create(
/* 字节码 */
producer.getClass(),
/* CallBack子类 */
new MethodInterceptor() {
/** 增强代码 */
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object result = null;
/* 方法参数 */
Float money = (Float) args[0];
/* 方法名 */
if ("saleProduct".equals(method.getName())) {
/* 调用方法 */
System.out.println("消费者:消费了"+money+"元");
result = method.invoke(producer, money * 0.2f);
}
if ("afterService".equals(method.getName())) {
/* 调用方法 */
System.out.println("消费者:消费了"+money+"元");
result = method.invoke(producer, 5);
}
/* 返回 */
return result;
}
});
/** 3、调用方法 */
/* 销售方法经过加强,增强的方法被调用 */
cglibProducer.saleProduct(999.12f);
/* 销售方法经过加强,方法不被调用 */
cglibProducer.afterService(999.12f);
}

}
-------------本文结束-------------
Donate comment here