`
huangyongxing310
  • 浏览: 483683 次
  • 性别: Icon_minigender_1
  • 来自: 广州
文章分类
社区版块
存档分类
最新评论

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

    博客分类:
  • Java
 
阅读更多
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动态代理类似

	}
}











分享到:
评论

相关推荐

    动态代理cglibjar包和源码

    如果目标类是final的,或者包含final方法,CGLIB则无法生成子类,这时它会退化到使用基于方法的代理,即通过动态生成实现所有接口的代理类来实现。 2. **CGLIB使用**: - 首先,你需要在项目中引入CGLIB的jar包。...

    cglib动态生成java类

    CGLib,全称为Code Generation Library,是一个强大的高性能的代码生成库,它在运行期扩展Java类与实现Java接口。在Java编程中,我们有时需要在运行时动态地创建或修改类,CGLib就是为此目的而设计的。它广泛应用于...

    输出JDK和CGLib动态代理产生的class文件.zip

    2. CGLib代理项目: - src/main/java:包含目标类 - target/classes:编译后的class文件,包括目标类的class文件,以及由CGLib生成的子类class文件 - 测试代码:展示如何使用Enhancer创建代理对象并调用方法 这...

    CGlib动态代理类所需的jar包

    CGlib的工作原理是基于Java的反射API和ASM库,它可以生成新的子类来实现动态代理。当一个类没有实现接口时,CGlib会创建该类的子类并在子类中添加方法拦截器。这种方法比使用Java的标准动态代理(java.lang.reflect....

    cglib_2.2.2 动态代理jar包(包含asm_3.3.1)

    总的来说,CGLIB_2.2.2与ASM_3.3.1的结合使用,为Java开发者提供了一种高效且灵活的动态代理实现方式,极大地扩展了Java代码的能力。在实际开发中,尤其是在需要进行面向切面编程或需要高性能代理的情况下,CGLIB是...

    cglib__jar包.zip

    - 相比Java动态代理,CGLIB更适合处理没有接口的类,而JDK动态代理则需要目标对象实现至少一个接口。 - 与AspectJ相比,CGLIB的AOP实现较为简单,但AspectJ提供了更全面的切面定义和编译时织入,而CGLIB则主要在...

    cglib-nodep-2.1_3.jar

    CGlib动态代理的原理是,它利用Java的反射API和ASM库(一个轻量级的字节码操作和分析框架),在运行时动态地生成一个子类,这个子类继承自目标类,并且覆盖了所有非final的方法。当调用这些方法时,CGlib会通过`...

    cglib2.2jar包

    2. **配置**:在Spring框架中,如果需要使用CGLIB进行AOP代理,需要在配置文件中启用CGLIB代理,例如在XML配置中添加 `<aop:aspectj-autoproxy/>` 或者在Java配置中使用 `@EnableAspectJAutoProxy(proxyTargetClass ...

    强势分享cglib-src-2.2

    2. **性能**:在处理大量代理对象时,CGLib通常比Java动态代理更快,因为它使用的是字节码技术,而Java动态代理需要反射。 3. **灵活性**:CGLib可以修改类的行为,甚至包括私有方法,而Java动态代理只能处理接口...

    第6讲 动态代理是基于什么原理1

    【动态代理原理】 动态代理是Java中用于在运行时创建代理对象的一种机制,它允许我们在程序执行过程中动态地创建代理类并实现特定接口,从而在调用目标方法之前或之后添加额外的功能。动态代理通常用于实现如AOP...

    cglibjar包

    CGLib的工作原理是:当程序调用一个被CGLib代理的方法时,CGLIB会生成一个新的子类,并在这个子类中覆盖原方法。这个新的子类会在运行时被加载,然后通过子类的方法来调用原方法,这样就可以在方法调用前后插入...

    cglib-3.2.4.jar

    五、CGlib与Java反射动态代理的对比 虽然Java自带的反射API提供了简单的动态代理实现,但仅限于实现了接口的类。对于没有接口的类,CGlib提供了一种更灵活的解决方案。然而,CGlib的性能通常稍逊于Java反射API,...

    Java动态代理资源包

    CGLIB通过生成子类并在子类中拦截方法调用来实现代理,这与Java的反射API不同,反射API是通过在运行时动态修改类的实例来实现代理的。 **CGLIB工作原理:** 1. **子类生成**:CGLIB通过ASM库在运行时动态生成目标类...

    cglib.jar免费下载

    在Java中,当你需要在运行时动态扩展一个类或者创建一个类的代理时,CGLIB就是一个非常有用的工具。它通过ASM库来操作字节码,创建新类或接口的实例。在SSH(Struts + Spring + Hibernate)集成框架中,CGLIB被用作...

    cglib 源代码分析(原创)

    CGlib是Java开发中的一个非常重要的库,它是一个强大的、高性能的代码生成库,主要用于扩展Java类和实现动态代理。这篇原创文章“CGlib源代码分析”旨在深入探讨CGlib的工作原理和内部机制,帮助开发者更好地理解和...

    cglib jar包

    ### CGLIB动态代理原理 CGLIB通过字节码技术生成代理类。当目标类没有实现接口时,CGLIB会生成一个目标类的子类,并在子类中对方法进行拦截,这样就能在不修改原有代码的情况下,插入额外的功能。CGLIB使用ASM库(在...

    cglib(个人文章测试可用包)

    2. **动态代理**:CGLib可以用来创建动态代理,当需要在运行时为某个类增加额外行为时,可以利用它生成该类的子类并覆盖特定方法。 3. **性能优化**:在某些情况下,CGLib可以用于代码优化,例如,通过动态生成的...

    cglib.jar源码

    然而,CGLIB代理也有其限制,比如它不能代理final类和final方法,以及无法处理带有动态类型的方法。 总的来说,CGLIB是一个强大的字节码操作工具,对于理解和实现Spring AOP以及深入学习Java字节码技术具有重要意义...

    spring源码编译时缺少的类cglib,objenesis,castor

    CGLIB通过字节码技术生成代理类,它可以提供比Java反射API更高的性能。 2. **Objenesis** Objenesis是一个快速、无侵入性的Java实例化工具,主要用于测试场景。在Spring中,Objenesis用于在没有构造函数或者构造...

    cglib-2.2.2 (含其他包)

    CGLIB(Code Generation Library)是一个强大的高性能的代码生成库,它在运行期扩展Java类与实现Java接口。CGLIB是许多开源项目的基础,比如Spring框架,它被广泛用于AOP(面向切面编程)代理的实现。CGLIB 2.2.2 是...

Global site tag (gtag.js) - Google Analytics