14

代理模式 Java 实现

 3 years ago
source link: https://suiyia.github.io/2019/12/04/%E4%BB%A3%E7%90%86%E6%A8%A1%E5%BC%8F%E4%BB%A5%E5%8F%8A-Spring-%E4%B8%AD%E7%9A%84%E4%BB%A3%E7%90%86%E5%AE%9E%E7%8E%B0/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

代理模式 Java 实现

2019-12-04 设计模式 53 评论 字数统计: 893(字) 阅读时长: 3(分)
  • 什么是代理模式
  • JDK 自带的动态代理
  • CGLIB 动态代理

意图:为其他对象提供一种代理,以控制对这个对象的访问。

例子:买火车票不一定要在火车站,去网上各个代理商那里也可以

代码思路:实体类 A 实现了接口 IA,而实体类 A 很复杂,那么使用实体类 B 去实现接口 IA,通过实体类 B 调用实体类 A 去满足功能。

注意事项:

1、和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。

2、和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。

upload successful

静态代理其实就是在程序运行之前,提前写好被代理方法的代理类,编译后运行。

下面代理模式实现需要写很多代码,不建议使用。

// 接口 A
public interface IServiceA {
void sayHello(String str);
}

// ServiceAImpl 实现接口 A
public class ServiceAImpl implements IServiceA {

@Override
public void sayHello(String str) {
System.out.println(str);
}
}

// 代理对象 ServiceProxyAImpl 也实现接口 A,并且构造函数必须传入接口 A 的实例
public class ServiceProxyAImpl implements IServiceA {
private IServiceA iServiceA;
public ServiceProxyAImpl(IServiceA iServiceA) {
this.iServiceA = iServiceA;
}
@Override
public void sayHello(String str) {
iServiceA.sayHello(str+ " is proxy ");
}
}

// 进行测试
public class Main {
public static void main(String[] args) {
IServiceA realA = new ServiceAImpl();
       // 传入真实对象
       IServiceA proxyA = new ServiceProxyAImpl(realA);
realA.sayHello("realA");
       // 代理对象的调用
       proxyA.sayHello("proxyA");
}
}

程序输出 :
ServiceAImpl sayrealA
ServiceAImpl sayproxyA is proxy

通过反射机制,在运行时生成代理类

JDK 动态代理

被代理的类需要是接口实现,如果被代理的类没有实现接口,就不能使用 JDK 动态代理

  1. java.lang.reflect.Proxy:生成动态代理类和对象;
  2. java.lang.reflect.InvocationHandler:通过 invoke 方法实现对真实角色的代理访问。
// 接口 A
public interface IServiceA {
void sayHello(String str);
}

// ServiceAImpl 实现接口 A
public class ServiceAImpl implements IServiceA {
@Override
public void sayHello(String str) {
System.out.println(str);
}
}

public class ProxyHandler implements InvocationHandler {
private IServiceA serviceA;
public ProxyHandler(IServiceA serviceA) {
this.serviceA = serviceA;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(serviceA, args);
}
}

public class MainProxy {
public static void main(String[] args) {
  // 真实对象
       IServiceA serviceA = new ServiceAImpl();
       // 通过 Proxy 得到代理对象
       IServiceA proxyServiceA = (IServiceA) Proxy
.newProxyInstance(serviceA.getClass().getClassLoader(), serviceA.getClass().getInterfaces(),
new ProxyHandler(serviceA));
serviceA.sayHello("serviceA");
proxyServiceA.sayHello("proxy serviceA");
}
}

程序输出:
serviceA
proxy serviceA

CGLIB 动态代理

通过改变字节码,对需要被代理的类,生成他的子类,子类去覆盖被代理类的方法,其中 private、final 修饰的方法不会被重写。

  1. 首先实现 MethodInterceptor,方法调用会被转发到该类的 intercept() 方法。
  2. 通过 Enhancer 来指定要代理的目标对象、实际处理代理逻辑的对象,最终通过调用 create() 方法得到代理对象
// 接口 A
public interface IServiceA {
void sayHello(String str);
}

// ServiceAImpl 实现接口 A
public class ServiceAImpl implements IServiceA {
@Override
public void sayHello(String str) {
System.out.println(str);
}
}

public class MyMethodInterceptor implements MethodInterceptor {

public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
return methodProxy.invokeSuper(o,objects);
}
}

public class CGLIBMain {

public static void main(String[] args) {
IServiceA serviceA = new ServiceAImpl();
serviceA.sayHello("serviceA");

Enhancer enhancer = new Enhancer(); // 字节码增强
       enhancer.setSuperclass(ServiceAImpl.class); // 设置父类
       enhancer.setCallback(new MyMethodInterceptor()); // 设置回调方法
       IServiceA proxyA = (IServiceA) enhancer.create();
proxyA.sayHello("proxyA");
}
}

程序输出:
serviceA
proxyA

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK