1、Java代理模式
1.1 静态代理
过程:
1) 定义一个接口:ITeacherDao
2) 目标对象 TeacherDAO 实现接口 ITeacherDAO
3) 使用静态代理方式,就需要在代理对象 TeacherDAOProxy 中也实现 ITeacherDAO
4) 调用的时候通过调用代理对象的方法来调用目标对象.
5) 特别提醒:代理对象与目标对象要实现相同的接口,然后通过调用相同的方法来调用目标对象的方法
public class Client {
public static void main(String[] args) {
//创建目标对象(被代理对象)
TeacherDao teacherDao = new TeacherDao();
//创建代理对象, 同时将被代理对象传递给代理对象
TeacherDaoProxy teacherDaoProxy = new TeacherDaoProxy(teacherDao);
//通过代理对象,调用到被代理对象的方法
//即:执行的是代理对象的方法,代理对象再去调用目标对象的方法
teacherDaoProxy.teach();
}
}
//接口
public interface ITeacherDao {
void teach(); // 授课的方法
}
//目标对象
public class TeacherDao implements ITeacherDao {
@Override public void teach() {
System.out.println(" 老师授课中。。。。。");
}
}
//代理对象,静态代理
public class TeacherDaoProxy implements ITeacherDao{
private ITeacherDao target; // 目标对象,通过接口来聚合
//构造器
public TeacherDaoProxy(ITeacherDao target) {
this.target = target; }
@Override public void teach() {
System.out.println("开始代理 完成某些操作。。。。。 ");
target.teach();
System.out.println("提交。。。。。");
} }
1.2 动态代理
动态代理又叫 jdk代理、接口代理,主要两个相关类:
- Proxy(java.lang.reflect包下的),主要负责管理和创建代理类的工作。
- InvocationHandler 接口,只拥有一个invoke方法,主要负责方法调用部分,是动态代理中我们需要实现的方法
1.2.1 主要功能介绍
1、动态生成代理对象
使用Proxy.newProxyInstance方法
newProxyInstance(ClassLoader loader,//目标对象的类加载器
Class<?>[] interfaces,//目标对象实现的接口
InvocationHandler h)//目标对象方法被调用时的处理器
通过这个方法 生成动态代理对象 $Proxy.class
//将生成的代理对象输出到文件中,否则就在内存中直接使用
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
2、InvocationHandler 接口
class TestHandler implements InvocationHandler{
@Override
public Object invoke(Object proxy,//生成的代理对象 $Proxy0
Method method, //想要调用目标对象中的方法
Object[] args) //方法的参数列表
throws Throwable {
return null;
}
}
1.2.2 代码实例
接口
public interface ITeacherDao {
void teach();
void sayHello(String name);
}
目标函数
public class TeacherDao implements ITeacherDao {
@Override
public void teach() {
System.out.println(" 老师授课中.... ");
}
@Override
public void sayHello(String name) {
System.out.println("hello " + name);
}
}
方法调用
public class Client {
public static void main(String[] args) {
TeacherDao teacherDao = new TeacherDao();
//生成动态代理对象
//System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
ITeacherDao m = (ITeacherDao)Proxy.newProxyInstance(
//被代理对象的类加载器
teacherDao.getClass().getClassLoader(),
//被代理对象实现的接口类型
new Class[]{ITeacherDao.class},
// 被代理对象方法被调用时候的处理器
new InvocationHandler() {
@Override// 生成的代理对象 调用被代理对象的方法 参数列表
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("method:" + method.getName() +" start...");
Object o = method.invoke(teacherDao,args);
System.out.println("method:" + method.getName() +" end!!...");
return o;
}
});
m.sayHello("小明");
}
}
1.2.3 动态代理过程
1、用Proxy.newProxyInstance 生成动态代理类 $Proxy0.class
2、调用被代理对象的方法 m.sayHello(“小明”);
进入$Proxy.sayHello()方法
public final void sayHello(String var1) throws {
try {
//h 目标对象方法被调用时的处理器 InvocationHandler
super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
实际上调用了InvocationHandler中的invoke()方法,最终调用目标对象中的方法
生成的动态代理对象
public final class $Proxy0 extends Proxy implements ITeacherDao {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m4;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void sayHello(String var1) throws {
try {
super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void teach() throws {
try {
super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("test.ITeacherDao").getMethod("sayHello", Class.forName("java.lang.String"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m4 = Class.forName("test.ITeacherDao").getMethod("teach");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
2、RPC原理
2.1 流程
一次完整的RPC调用流程(同步调用)如下:
1)服务消费方(client)调用以本地调用方式调用服务;
2)client stub接收到调用后负责将方法、参数等组装成能够进行网络传输的消息体;
3)client stub找到服务地址,并将消息发送到服务端;
4)server stub收到消息后进行解码;
5)server stub根据解码结果调用本地的服务;
6)本地服务执行并将结果返回给server stub;
7)server stub将返回结果打包成消息并发送至消费方;
8)client stub接收到消息,并进行解码;
9)服务消费方得到最终结果。
用到的知识有 动态代理,反射,序列化
2.2 代码
实体类、接口、方法
//实体类
public class User implements Serializable {
private static final long serialVersionUID = 1L;
int id;
String name;
public User(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
//接口
public interface IUserService {
User findUserById(int id);
}
//实现方法
public class IProductServiceImpl implements IProductService{
@Override
public Product findProductByName(String name) {
return new Product(1,name,1);
}
}
client端
public class Client {
public static void main(String[] args) {
//调用远程服务的接口
IUserService service = (IUserService)Stub.getStub(IUserService.class);
System.out.println(service.findUserById(13));
}
}
Stub
static Object getStub(Class clazz){
InvocationHandler h = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//调用服务端口
Socket socket = new Socket("127.0.0.1",8088);
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
String clazzName = clazz.getName();
String methodName = method.getName();
//将调用接口名、方法名、参数类型、参数写入
oos.writeUTF(clazzName);
oos.writeUTF(methodName);
oos.writeObject(method.getParameterTypes());
oos.writeObject(args);
oos.flush();
//接收服务端返回的结果,object读入
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
Object object =ois.readObject();
return object;
}
};
Object o = Proxy.newProxyInstance(IUserService.class.getClassLoader(), new Class[]{IUserService.class}, h);
return o;
}
server端
public class Server {
private static boolean running = true;
public static void main(String[] args) throws Exception {
ServerSocket server = new ServerSocket(8088);
while(running){
Socket client = server.accept();
process(client);
client.close();
}
server.close();
}
public static void process(Socket socket) throws Exception {
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
//将调用接口,方法,参数类型,参数解析出来
String clazzName = ois.readUTF();
String methodName = ois.readUTF();
Class[] parameterTypes = (Class[]) ois.readObject();
Object[] parameters = (Object[]) ois.readObject();
Class clazz = IUserServiceImpl.class;
//调用目标方法
Method method = clazz.getMethod(methodName, parameterTypes);
Object o = method.invoke(clazz.newInstance(), parameters);
oos.writeObject(o);
oos.flush();
}
}