反射
反射是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性和方法。
关于反射的几个类
Field类:代表的是反射中所获取到的对象属性
Constructor类:代表反射中获取到的类的构造函数
Method类:代表反射中获取到的类的方法
Class类:类对象
反射的用法示例
student类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private String name;
private int age;
}
反射测试类
public class ReflectionTest {
@Test
public void test1() throws Exception{
Student c = new Student("张三", 22);
final Class<?> clazz = Class.forName("com.Student");
//获取类的public属性如果属性不为public则不能够获取
final Field[] fields = clazz.getFields();
for (Field field : fields) {
System.out.println(field.getName());
}
System.out.println("----------------------所有属性----------------------");
//获取类的所有属性包括private修饰的属性
final Field[] declaredFields = clazz.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField.getName());
}
System.out.println("----------------------所有方法----------------------");
//获取类的所有方法包括private修饰的方法
final Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod.getName());
}
System.out.println("----------------------获取对象属性具体的值----------------------");
final Field age = clazz.getDeclaredField("age");
//当将这个属性设为true时才能够对对象的属性进行操作
age.setAccessible(true);
System.out.println(c);
age.set(c,1111);
System.out.println(c);
System.out.println(age.get(c));
//通过构造方法构造对象
final Object o = clazz.newInstance();
System.out.println(o);
//获取构造方法
final Constructor<?>[] constructors = clazz.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor.toString());
}
}
}
jdk动态代理
代理模式
head first设计模式中对代理模式的定义:代理模式为另一个对象提供一个替身或占位符以控制对这个对象的访问。
静态代理
//租房接口
public interface RentAble {
void rent();
}
//房东类
public class Landlord implements RentAble{
@Override
public void rent() {
System.out.println("出租房屋!!!");
}
}
//中介类
public class Intermediary implements RentAble{
private RentAble rentAble;
public Intermediary(RentAble rentAble) {
this.rentAble = rentAble;
}
@Override
public void rent() {
System.out.println("带人看房!!!");
rentAble.rent();
}
}
在这个例子中我们调用接口时只需调用中介类的租房方法就可以完成租房了,这也就是静态代理。
动态代理
动态代理其实就是将上面例子中的中介类在程序运行时由jvm根据反射等机制动态生成即可,代理类和委托类的关系是在程序运行时才确定。
public static void main(String[] args) {
RentAble landlord=new Landlord();
RentAble rentAble = (RentAble) Proxy.newProxyInstance(Landlord.class.getClassLoader(), new Class[]{RentAble.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("带人看房!!!");
Object invoke = method.invoke(landlord,args);
return invoke;
}
});
rentAble.rent();
}
RPC
RPC(Remote Procedure Call)远程过程调用协议
rpc其实也是基于动态代理实现的,我们可以通过网络将我们需要调用的接口、方法名、方法参数等信息发送到另一台计算机上,另一台计算机根据我们发送的信息,来调用他本地的方法然后将返回参数再传给我们。
客户端需要的代码
客户端获取代理对象
public class Stub {
/**
* 获取代理对象
* @param clazz 需要获取的接口
* @return
*/
public static Object getService(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", 4396);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
//将接口名称、方法名、方法参数类型、方法参数列表发送到远程
objectOutputStream.writeUTF(clazz.getName());
objectOutputStream.writeUTF(method.getName());
objectOutputStream.writeObject(method.getParameterTypes());
objectOutputStream.writeObject(args);
//接收返回值
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
Object o = objectInputStream.readObject();
//关闭流
objectOutputStream.close();
socket.close();
return o;
}
};
return Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, h);
}
}
客户端需要调用的接口
public interface Service {
/**
* 获取学生对象
* @param id 学生id
* @return
*/
Student queryStudentById(long id);
}
实体类
public class Student implements Serializable {
private static final long serialVersionUID = 1L;
//学生id
private long id;
//学生年龄
private int age;
//学生姓名
private String name;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
客户端主函数
public class Client {
public static void main(String[] args) {
Service service = (Service) Stub.getService(Service.class);
Student student = service.queryStudentById(123);
System.out.println(JSON.toJSONString(student));
}
}
服务端需要的代码
//服务端
public class Server {
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(4396);
while (true) {
handle(serverSocket.accept());
}
}
/**
* 处理请求方法
* @param socket 连接socket
* @throws Exception
*/
public static void handle(Socket socket) throws Exception {
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
//获取参数
String clazzName = objectInputStream.readUTF();
String methodName = objectInputStream.readUTF();
Class[] paramTypes = (Class[]) objectInputStream.readObject();
Object[] args = (Object[]) objectInputStream.readObject();
//通过spi获取service实现类
Class<?> aClass = Class.forName(clazzName);
ServiceLoader<?> serviceLoader = ServiceLoader.load(aClass);
Object studentService = null;
for (Object service : serviceLoader) {
studentService = service;
}
if (studentService == null) {
System.out.println("服务未找到");
return;
}
//获取需要调用的方法
Method method = studentService.getClass().getMethod(methodName, paramTypes);
Object invoke = method.invoke(studentService, args);
//发送返回值
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject(invoke);
//关闭流
objectInputStream.close();
objectOutputStream.close();
}
}
被调用的接口
接口
public interface Service {
/**
* 获取学生对象
* @param id 学生id
* @return
*/
Student queryStudentById(long id);
}
接口实现
public class StudentService implements Service{
@Override
public Student queryStudentById(long id) {
Student student = new Student();
student.setId(4396);
student.setAge(27);
student.setName("张三");
return student;
}
}
实体类
public class Student implements Serializable {
private static final long serialVersionUID = 1L;
//学生id
private long id;
//学生年龄
private int age;
//学生姓名
private String name;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
SPI配置文件
com.example.demo.rpc.StudentService