反射与代理

概述

         反射机制是java中很重要的一环,是与io一样,属于java底层性原理,很多框架的开发的十分依赖反射(比如IOC).反射理解对类进行了''解剖''.

          代理与反射恰好相反,对类进行了包装,代理类的行为,在各类框架中应用十分广泛(如AOP,RPC).

 反射

           反射(Reflection)是Java 程序开发语言的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性。(反射)

           从基本定义中可以理出关键词:运行中(反射时机),自身(反射对象),内部属性(反射内容),以下仅对反射对象与内容作举例说明.(反射入门)

   class

package reflection;

@Deprecated
public class ReflectClass{
	
	public String name;
	
	/**get the default name
	 * @return
	 */
	public static String getDefaultName(String name){
		return name == null ? "hello world" : name;
	}
	
	private void getName(){
		System.out.println("private excute");
	}
}

   test

package reflection;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;

import org.junit.Test;

public class TestReflect {
	
	@Test
	/*
	 * jdk提供的反射相关类 java.lang.Class;//类 java.lang.reflect.Constructor;//构造器
	 * java.lang.reflect.Field;//属性 java.lang.reflect.Method;//方法
	 * java.lang.reflect.Modifier;//修饰符(public private 等)
	 * java.lang.annotation.Annotation;//注解
	 */
	public void testBasic() throws Exception {
		/*注:对abstract class ,class,interface 都是可以获取到相关declare信息的,但invoke等一些方法只针对实例而言的
		 * 此处仅以class为例(当class继承class或实现interface,反射的包括继承或实现部分)
		 * 
		 * */
		/* 获取类 ----获取反射对象 */
		Class<?> clazz;

		// 第一种方式(直接获取):
		// java中每个类型都有class属性.
		clazz = ReflectClass.class;

		/*
		 * //第二种方式(利用classLoader获取): clazz = Class.forName("ReflectClass");
		 * 
		 * //第三种方式(实例获取): ReflectClass r = new ReflectClass(); clazz =
		 * r.getClass();
		 */

		/* 反射内容 */

		/*
		 * 属性 private String name;
		 */
		Field[] fields = clazz.getDeclaredFields();
		System.out.println("reflect field start");
		for (Field field : fields) {
			System.out.println("name: " + field.getName());// 属性的名字
			System.out.println("modifier: " + Modifier.toString(field.getModifiers()));// 获得属性的修饰符,例如public,static等等
			System.out.println("type: " + field.getType().getSimpleName());// 属性的类型的名字
		}
		System.out.println("****************************");

		/*
		 * 构造器 public ReflectClass(){}
		 */
		Constructor<?>[] constructors = clazz.getDeclaredConstructors();
		System.out.println("reflect constructor start");
		for (Constructor<?> constructor : constructors) {
			System.out.println("name: " + constructor.getName());// 构造器的名字
			System.out.println("modifier: " + Modifier.toString(constructor.getModifiers()));// 获得构造器修饰符,例如public,static等等
			System.out.println("parameters: " + Arrays.toString(constructor.getParameterTypes()));// 构造器参数
		}
		System.out.println("****************************");

		/*
		 * 方法 public static String getDefaultName(String name)
		 */
		Method[] methods = clazz.getDeclaredMethods();
		System.out.println("reflect method start");
		for (Method method : methods) {
			System.out.println("name: " + method.getName());// 方法的名字
			System.out.println("modifier: " + Modifier.toString(method.getModifiers()));// 获得方法修饰符,例如public,static等等
			System.out.println("parameters: " + Arrays.toString(method.getParameterTypes()));// 方法参数
		}
		System.out.println("****************************");
		System.out.println("reflect annotation start");
		Annotation[] annotations = clazz.getDeclaredAnnotations();
		for (Annotation annotation : annotations) {
			System.out.println("name: " + annotation.toString());
		}

		System.out.println("****************************");
		System.out.println("invoke private start");
		/* 注意:对一些private 修饰,可以获取,但需要进行权限设置(暴力反射)才能执行,以method为例 */
		Method method = clazz.getDeclaredMethod("getName");
		System.out.println("name: " + method.getName());
		method.setAccessible(true);// 设置访问权限
		method.invoke(new ReflectClass());

		/*
		 * 打印结果 reflect field start name: name modifier: public type: String
		 ****************************
		 * reflect constructor start name: reflection.ReflectClass modifier:
		 * public parameters: []
		 ****************************
		 * reflect method start name: getName modifier: private parameters: []
		 * name: getDefaultName modifier: public static parameters: [class
		 * java.lang.String]
		 ****************************
		 * reflect annotation start name: @java.lang.Deprecated()
		 ****************************
		 * invoke private start name: getName private excute
		 */
		
	}

}

         反射获取类描述,类描述结合代理对象,便可与实现类的相关功能(rpc).

代理

         代理:为其他对象提供一种代理已控制对这个对象的访问.(代理)

         按照代理的创建的时期,代理分静态代理,动态代理

静态代理

         静态代理属于硬编码,在程序运行之前就代理类已经生成,静态代理更多的时候作为一种代理思想而存在.

         静态代理example

被代理对象

package proxy;

public class Student {
	public void study(){
		System.out.println("hello world");
	}
}

代理对象

package proxy;

public class StudentProxy {
	private  Student student;
	public StudentProxy (Student student) {
		this.student = student;
	}
	public void study(){
		if (student == null) {
			System.out.println("proxy fail");
		}
		student.study();
	}
}

访问

	public static void main(String[] args) {
		StudentProxy proxy = new StudentProxy(new Student());
		proxy.study();
	}

动态代理

        动态代理,在程序运行时,运用反射机制动态创建,相比静态代理,更为灵活,大多数框架底层使用就是动态代理.此处主要讲JDK动态代理与CGLIB代理

JDK动态代理

        JDK实现动态代理核心:Proxy代理工具类,InvocationHandler反射实现接口.

        JDK动态代理只对实现接口的类有效

增加一个接口

package proxy;

public interface Human{
   public void study();
}

接口实现

package proxy;

public class Student implements Human{
	public void study(){
		System.out.println("hello world");
	}
}

client

final Student stu =new Student();		
Human s = (Human)Proxy.newProxyInstance(Human.class.getClassLoader(), new Class[] {Human.class}, new InvocationHandler() {
			@Override
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				Object result;
				result = method.invoke(stu,args);
				return result;
			}
		});
		s.study();

     CGLIB代理

        JDK动态代理的类必须实现接口,对没有实现接口的类进行代理,使用CGLIB动态代理

        基本原理:运行时动态的生成一个被代理类的子类(通过ASM字节码处理框架实现),子类重写了被代理类中所有非final的方法。在子类中采用方法拦截的技术拦截所有父类非final方法的调用,顺势植入横切逻辑。
引入相关包

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.2.4</version>
</dependency>

目标类

package proxy;

public class CglibTest {
	public void doSomething(){
		System.out.println("hello");
	}
}

client

		/*Enhancer类是CGLib中的一个字节码增强器
		 * 设置父类CglibTest
		 * 设置方法拦截器(实现AOP)
		 * enhancer.create()动态生成CglibTest的子类
		 * */
        Enhancer enhancer =new Enhancer();  
        enhancer.setSuperclass(CglibTest.class);  
        
        //方法拦截器,执行子类方法前执行
        enhancer.setCallback(new MethodInterceptor() {
            /** 
             * 重写方法拦截在方法前和方法后加入业务 
             * Object obj为目标对象 
             * Method method为目标方法 
             * Object[] params 为参数, 
             * MethodProxy proxy CGlib方法代理对象 
             */  
			@Override
			public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
				Object result ;
				System.out.println("处理前");
				result=proxy.invokeSuper(obj, args);
				System.out.println("处理后");
				return result;
			}
		});  
        CglibTest cglibTest=(CglibTest)enhancer.create();  
        cglibTest.doSomething();

代理总结

  • 相对于动态代理,静态代理更被认可为一种思维模式,而动态代理使用反射机制动态创建代理对象
  • JDK动态代理(可以用静态的思维去理解),代理对象和目标对象实现了相同的接口,目标对象作为代理对象的一个属性,具体接口实现中,可以在调用目标对象相应方法前后加上其他的业务逻辑处理
  • CGLIB是生成一个目标对象的子类,覆盖目标对象的所有方法(不包括final方法),通过设置方法拦截器,在调用子类的方法时,进行拦截,实现AOP
  • JDK动态代理制能针对实现接口的类实行代理,CGLIBE针对类
  • 动态代理在AOP,RPC(rpc小案例)颇多,

参考:JDK动态代理   Cglib动态代理

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值