Java中的代理

关于Java中的代理

1. 代理模式

1.1 定义

代理(Proxy)模式标准定义:为其他对象提供一种代理以控制对这个对象的访问。

1.2 解释

代理模式可以理解找一个人做我的代理人,可以帮我代理一些事情,但是实际上他只是一个中间人,最后执行的人还是我

1.3 类图

代理模式类图

1.4 优缺点
  • 优点 : 1. 看起来很直观 2.编译期就已经初始化了,指定了调用顺序,效率高
  • 缺点 : 定义的代理类太多,维护困难
1.5 代码实现

Subject 类

public interface Subject {
    public void dosomething();
}

RealSubject 类

public class RealSubject implements Subject {
    @Override
    public void dosomething() {
        System.out.println("dosomething...");
    }
}

Proxy 类

public class proxy implements Subject{

    private Subject subject;

    public proxy(Subject subject){
        this.subject = subject;
    }

	@Override
    public void dosomething() {
        System.out.println("你好我是subject的代理....");
        subject.dosomething();
        System.out.println("你看着是我做的,其实是老板做的...");
    }
}

client 类

public class client {

    public static void main(String[] args) {
        proxy p = new proxy(new RealSubject());
        p.dosomething();
    }
}

2.静态代理

静态代理也就是上面的代理模式中实现的例子。但是静态代理必须要保证被代理对象已经实例化,才可以被代理

3.JDK 动态代理

3.1 定义

java动态代理机制以巧妙的方式实现了代理模式的设计理念。

3.2 解释
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        
}

每一个动态代理的类必须实现InvocationHandler,InvocationHandler类是每次调用代理的方法都会触发,并将 代理类,请求的方法,方法参数传入,可以通过反射去执行方法

3.1 优缺点
  • 优点:1.仅需要一个动态代理类 2.在运行期才会去调用,灵活方便
  • 缺点:运行期创建效率相对较低,可读性稍差
3.2 代码实现

Subject 类

public interface Subject {
    public void dosomething();
    public String sayHello(String username);
}

RealSubject类

public class RealSubject implements Subject {
    @Override
    public void dosomething() {
        System.out.println("dosomething...");
    }

    @Override
    public String sayHello(String username) {
        return "hello , " + username ;
    }
}

DynamicProxy类

/**
 * 1. 必须实现<code>InvocationHandler</code><br/>
 * 2. 在调用方式都会进入到<code>DynamicProxy</code>类中
 */
public class DynamicProxy implements InvocationHandler {
    
    private Object proxyObject;

    public DynamicProxy(Object proxyObject){
        this.proxyObject = proxyObject;
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return method.invoke(proxyObject,args);
    }
}

client调用

public class client {

    public static void main(String[] args) {
        Subject realSubject = new RealSubject();
        Subject subject =  (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(),realSubject.getClass().getInterfaces(),new DynamicProxy(realSubject));
        String result = subject.sayHello("shanyepifu");
        System.out.println(result);
        subject.dosomething();
    }
}

4. 通过动态代理和Socket简单实现RPC

服务端代码(暴露服务):

public class RPCExporter {
    public void export(Object inter, int port) throws ServiceUnBindException, PortllegalIIException, IOException,
            ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {

        // 判断服务是否注册
        if (inter == null) {
            throw new ServiceUnBindException("服务未绑定");
        }
        // 判断端口号是否合法
        if (!(Integer.MIN_VALUE < port && port < Integer.MAX_VALUE)) {
            throw new PortllegalIIException("端口号不合法");
        }
        // 在指定的端口上绑定Socket服务
        ServerSocket serverSocket = new ServerSocket(port);
        while (true) {
            // socket开始监听端口
            Socket socket = serverSocket.accept();
            // 获取对象输入、输出流
            ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
            ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
            // 读取传过来的方法信息
            String methodName = ois.readUTF();
            Class<?>[] parameterTypes = (Class<?>[]) ois.readObject();
            Object[] arguments = (Object[]) ois.readObject();
            // 通过反射执行方法
            Method method = inter.getClass().getMethod(methodName, parameterTypes);
            Object result = method.invoke(inter, arguments);
            // 将结果返回
            oos.writeObject(result);
            oos.flush();
            // 关闭流
            oos.close();
            ois.close();
            socket.close();
        }
    }
}

客户端代码(消费者):

public class RPCRefer {
    public <T> T refer(Class<T> targetInter, InetAddress inetAddress, int port) throws Exception {
        // 代理类实现
        T target = (T) Proxy.newProxyInstance(targetInter.getClassLoader(), new Class<?>[]{targetInter}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Socket socket = new Socket(inetAddress, port);
                ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
                oos.writeUTF(method.getName());
                oos.writeObject(method.getParameterTypes());
                oos.writeObject(args);
                ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
                Object result = ois.readObject();
                if (result instanceof Throwable) {
                    throw (Throwable) result;
                }
                return result;
            }
        });
        return target;
    }
}

完整代码已经托管到码云 : 点击查看

5. cglib动态代理

5.1 定义

CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。

5.2 cglib 和 jdk 动态代理的优缺点(摘录)

(1)Proxy 毕竟是通过反射实现的,必须在效率上付出代价:有实验数据表明,调用反射比一般的函数开销至少要大 10 倍。而且,从程序实现上可以看出,对 proxy class 的所有方法调用都要通过使用反射的 invoke 方法。因此,对于性能关键的应用,使用 proxy class 是需要精心考虑的,以避免反射成为整个应用的瓶颈。 (2)CGLib封装了asm,可以再运行期动态生成新的class。ASM 能够通过改造既有类,直接生成需要的代码。增强的代码是硬编码在新生成的类文件内部的,没有反射带来性能上的付出。同时,ASM 与 Proxy 编程不同,不需要为增强代码而新定义一个接口,生成的代码可以覆盖原来的类,或者是原始类的子类。 (3)CGLib在不同频次的调用性能会发生变化,体现为调用频次越高、性能越好。 (4)不同版本的JDK中JDK Proxy的性能也不尽相同,越高版本的JDK(JDK7及以上),性能提升越明显。

5.3 代码实现

Subject类

public interface Subject {
    public void dosomething();
}

RealSubject类

public class RealSubject implements Subject {
    @Override
    public void dosomething() {
        System.out.println("dosomething...");
    }
}

CglibProxy 类

public class CglibProxy implements MethodInterceptor {
    
    private Object target;

    private Enhancer enhancer = new Enhancer();

    public Object getInstance(Class target){
        // 设置从字节码创建的类
        enhancer.setSuperclass(target);
        enhancer.setCallback(this);
        // 创建字节码类
        return enhancer.create();
    }

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

client 类

public class client {
    public static void main(String[] args) {
        Subject cp = (Subject) new CglibProxy().getInstance(RealSubject.class);
        cp.dosomething();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值