反射、类信息、动态代理、CGLIB动态代理原理与测试

阅读更多
package com.midea.common.classTest;

public class ClassModelTest {

	// 执行顺序大致分类:
	// 1.静态属性,静态方法声明,静态块。
	// 2.动态属性,普通方法声明,构造块。
	// 3.构造方法。
	// 当再次创建一个对象,不再执行静态部分,仅仅重复执行普通部分。
	// 一切都是先父类再子类(因为子类的static初始化可能会依赖于父类成员能否被正确初始化)

	// 类加载先初始静态变量,后是静态方法
	public static String name = "luoxn28";

	private String age;

	public String sex;

	// 类加载时会调用静态方法
	static {
		System.out.println("静态块");
	}

	public ClassModelTest() {
		System.out.println("构造方法");
	}

	public static String getName() {
		return name;
	}

	public void setName(String name) {
		ClassModelTest.name = name;
	}

	public String getAge() {
		return age;
	}

	public void setAge(String age) {
		this.age = age;
	}

	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	@Override
	public String toString() {
		return "ClassModelTest [name=" + name + ", age=" + age + ", sex=" + sex + "]";
	}

	public void sayHello(String value) {
		System.out.println("sayHello方法 value == " + value);
	}

}





package com.midea.common.classTest;

public interface Subject {
	public void rent();

	public void hello(String str);
}


package com.midea.common.classTest;

public class RealSubject implements Subject {
	@Override
	public void rent() {
		System.out.println("I want to rent my house");
	}

	@Override
	public void hello(String str) {
		System.out.println("hello: " + str);
	}
}



package com.midea.common.classTest;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;

public class DynamicProxy implements InvocationHandler {
	// 这个就是我们要代理的真实对象
	private Object subject;

	// 构造方法,给我们要代理的真实对象赋初值
	public DynamicProxy(Object subject) {
		this.subject = subject;
	}

	public DynamicProxy() {
		super();
		// TODO Auto-generated constructor stub
	}

	// 绑定委托对象,并返回代理类
	public Object bind(Object tar) {
		this.subject = tar;
		// 绑定该类实现的所有接口,取得代理类
		return Proxy.newProxyInstance(tar.getClass().getClassLoader(), tar.getClass().getInterfaces(), this);
	}

	@Override
	public Object invoke(Object object, Method method, Object[] args) throws Throwable {
		// 在代理真实对象前我们可以添加一些自己的操作
		System.out.println("before rent house");
		System.out.println("Method:" + method);

		// 当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
		method.invoke(subject, args);

		// 在代理真实对象后我们也可以添加一些自己的操作
		System.out.println("after rent house");

		return null;
	}
}




package com.midea.common.classTest;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Proxy;

import org.apache.commons.cli.GnuParser;
import org.yaml.snakeyaml.Yaml;

public class ClassTest {
	public static void main(String args[]) throws ClassNotFoundException, InstantiationException,
			IllegalAccessException, IntrospectionException, IllegalArgumentException, InvocationTargetException {

		// =============================Class.forName
		Class clazz = Class.forName("com.midea.common.classTest.ClassModelTest"); // 要求JVM查找并加载指定的类,返回的是一个类(类信息)

		System.out.println("clazz == " + clazz.getName()); // clazz ==
															// com.midea.common.classTest.ClassModelTest

		// newInstance(),用于以类实例化一个实例
		// ClassModelTest classModelTest =
		// (ClassModelTest)Class.forName("com.midea.common.classTest.ClassModelTest").newInstance();与
		// ClassModelTest classModelTest = new ClassModelTest() 是一样的效果
		// newInstance()主要是为了考虑到软件的可伸缩、可扩展和可重用等软件设计思想,如按配置文件实现对象的实例化等,生成对象只能调用无参的构造函数,而使用
		// new关键字生成对象没有这个限制

		ClassModelTest classModelTest = (ClassModelTest) Class.forName("com.midea.common.classTest.ClassModelTest")
				.newInstance();

		// getName():获得类的完整名字。
		// getFields():获得类的public类型的属性。
		// getDeclaredFields():获得类的所有属性。包括private 声明的和继承类
		// getMethods():获得类的public类型的方法。
		// getDeclaredMethods():获得类的所有方法。包括private 声明的和继承类
		// getMethod(String name, Class[]
		// parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes
		// 参数指定方法的参数类型。
		// getConstructors():获得类的public类型的构造方法。
		// getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes
		// 参数指定构造方法的参数类型。
		// newInstance():通过类的不带参数的构造方法创建这个类的一个对象。

		// https://www.jianshu.com/p/5b90a4e70783(如何实现一个简单的RPC)

		// =============================反射
		// RTTI,编译器在编译时打开和检查.class文件
		// 反射,运行时打开和检查.class文件
		System.out.println("ClassModelTest == " + classModelTest.toString());
		// Class clazz = classModelTest.getClass();

		Field[] fields = clazz.getDeclaredFields(); // 成员变量,获取类中所有的属性(public、protected、default、private),但不包括继承的属性,返回
													// Field 对象的一个数组
		// Class.getFields(): 获取类中public类型的属性,返回一个包含某些 Field 对象的数组,该数组包含此 Class
		// 对象所表示的类或接口的所有可访问公共字段
		// getDeclaredFields():
		// 获取类中所有的属性(public、protected、default、private),但不包括继承的属性,返回 Field
		// 对象的一个数组
		// getField(String name): 获取类特定的方法,name参数指定了属性的名称
		// getDeclaredField(String name): 获取类特定的方法,name参数指定了属性的名称

		for (Field field : fields) {
			System.out.println("field =========================== ");
			System.out.println("field == " + field.toString());
			System.out.println("getType == " + field.getType());// 返回这个变量的类型
			System.out.println("getGenericType == " + field.getGenericType().getTypeName());// 如果当前属性有签名属性类型就返回,否则就返回
			// Field.getType()
			System.out.println("isEnumConstant == " + field.isEnumConstant());// 判断这个属性是否是枚举类

			System.out.println("getName == " + field.getName());// 获取属性的名字

			// -----------返回指定对象obj上此 Field 表示的字段的值,public的才可以用这个方法
			// System.out.println("get == " + field.get(classModelTest));
			//
			// -----------将指定对象变量上此 Field 对象表示的字段设置为指定的新值,public的才可以用这个方法
			// field.set(classModelTest, "fieldTest");
			// System.out.println("classModelTest == " +
			// classModelTest.toString());

			// -----------该类为属性描述符类。使用PropertyDescriptor获取实体类中私有属性的值,并给私有属性赋值
			PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), clazz);
			// 获得用于写入属性值的方法
			Method method = propertyDescriptor.getWriteMethod();
			// 运行这个方法写入属性值
			method.invoke(classModelTest, "fieldWriteTest");
			System.out.println("classModelTest == " + classModelTest.toString());

			// 获得用于读取属性值的方法
			Method methodRead = propertyDescriptor.getReadMethod();
			Object readValue = methodRead.invoke(classModelTest);

			System.out.println("readValue == " + readValue.toString());

			// Introspector类: 可以将的类信息进行封装
			// BeanInfo beanInfo = Introspector.getBeanInfo(clazz);
			// PropertyDescriptor[] proDescrtptors =
			// beanInfo.getPropertyDescriptors();

		}
		// -----------
		Method[] methods = clazz.getMethods();

		for (Method method : methods) {
			System.out.println("method =========================== ");
			System.out.println("method == " + method.toString());

			System.out.println("getName == " + method.getName());

			Parameter[] parameters = method.getParameters();
			for (Parameter parameter : parameters) {
				System.out.println("parameter =========================== ");
				System.out.println("getName == " + parameter.getName());
				System.out.println("getName == " + parameter.getType());
			}

			System.out.println("getReturnType == " + method.getReturnType());

		}

		// -----------动态代理
		// https://www.cnblogs.com/xiaoxiao7/p/6057724.html(AOP与JAVA动态代理)
		// https://blog.csdn.net/lovejj1994/article/details/78080124(动态代理实现原理)
		// 动态代理实现原理:就是按接口生成了一个新类,新类里的方法都经过改写调用InvocationHandler里的invoke
		// 在运行期,目标类加载后,为接口动态生成代理类,将切面织入到代理类中

		// 要代理的真实对象
		Subject realSubject = new RealSubject();

		InvocationHandler invocationHandler = new DynamicProxy(realSubject);

		// 加载生成代理类
		Subject subject = (Subject) Proxy.newProxyInstance(invocationHandler.getClass().getClassLoader(),
				realSubject.getClass().getInterfaces(), invocationHandler);

		// 调用代理的方法
		subject.rent();// 实际都是调用invocationHandler里的invoke
		subject.hello("world");

		// -----------------
		System.out.println("=============================");
		DynamicProxy dynamicProxy = new DynamicProxy();

		Subject sub = (Subject) dynamicProxy.bind(realSubject);

		subject.rent();
		subject.hello("world2");

		// -----------CGLIB动态代理
		// https://www.cnblogs.com/cruze/p/3865180.html(cglib 动态代理原理分析)
		// 动态代理实现原理:通过生成子类,改写子类的方法中调用MethodInterceptor中的intercept来实现的,跟JDK动态代理类似

	}
}











你可能感兴趣的:(反射、类信息、动态代理、CGLIB动态代理原理与测试)