您的位置:首页 > 编程语言 > Java开发

Java中的代理

2016-07-22 00:00 1036 查看

关于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();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: