Java核心技术之反射以及动态代理

反射机制是Java语言提供的一种基础功能,赋予程序在运行时自省的能力。通过反射我们可以直接操作类或者对象,比如说获取某个对象的类定义,获取类声明的属性和方法,调用方法或者构造对象,甚至可以运行时修改类定义。

动态代理是一种方便运行时动态构建代理,动态处理代理方法调用的机制,很多场景都是利用类似机制做到的,比如说用来包装RPC调用,面向切面的编程(AOP)。

实现动态代理的方式很多,比如说JDK自身提供的动态代理,就是主要利用了上面提到的反射机制。还要其他实现方式,比如利用传说中更高性能的字节码操作机制,类似ASM,cglib等。

一. 反射机制及其演进

反射提供AccessibleObject.setAccessible(boolean flag)。它的子类也大都重写的这个方法,它可以在运行时,修改成员访问限制。
但是,在Java9中,因为Jigsaw项目新增的模块化系统,出于强封装性的考虑,对反射访问进行了限制。Jigsaw引入了所谓的Open的概念,只有当被反射操作的模块和指定的包对反射调用者模块Open,才能使用setAccessible;否则,被认为是不合法操作。如果我们的实体类是定义在模块里面,我们需要在模块描述符中明确声明:

module MyEntities {
    // Open for reflection
    opens com.mycorp to java.persistence;
}

动态代理,首先是一个代理机制。如果属性设计模式中的代理模式,我们会知道,代理可以看作是对调用目标的一个包装,这样我们对目标代码的调用不是直接发生的,而是通过代理完成。其实很多动态代理场景,我认为也可以看作是装饰器模式的应用。

通过代理可以让调用者与实现者之间解耦。比如进行RPC调用,框架内部的寻址,序列化,反序列化等,对于调用者往往是没有太大意义的,通过代理,可以提供更加友善的界面。

public class MyDynamicProxy {     
	public static  void main (String[] args) {  
	    	HelloImpl hello = new HelloImpl();
	    	MyInvocationHandler handler = new MyInvocationHandler(hello);         
	    	// 构造代码实例         
	    	Hello proxyHello = (Hello) 		Proxy.newProxyInstance(HelloImpl.class.getClassLoader(), HelloImpl.class.getInterfaces(), handler);        
	    	 // 调用代理方法        
	    	 proxyHello.sayHello();     
	    	 }
	 }
interface Hello {     
	void sayHello();
} 
class HelloImpl implements  Hello {     
	@Override     
	public void sayHello() {         
		System.out.println("Hello World");     
	} 
}  
class MyInvocationHandler implements InvocationHandler {     
	private Object target;     
	public MyInvocationHandler(Object target) {         
		this.target = target;     
	}     
	@Override     
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {         
		System.out.println("Invoking sayHello");
		Object result = method.invoke(target, args);         
		return result;     
	} 
} 

如果被调用者没有实现接口,而我们还是希望利用动态代理机制,那么可以使用cglib方式。

public class Dao {     	
	public void update() {         		
		System.out.println("PeopleDao.update()");     	}     	
	public void select() {     	    
		System.out.println("PeopleDao.select()");     	} 
} 
public class DaoProxy implements MethodInterceptor {  
  	@Override     
	public Object intercept(Object object, Method method, Object[] objects, MethodProxy proxy) throws Throwable {         
	System.out.println("Before Method Invoke");      
	proxy.invokeSuper(object, objects);         
	System.out.println("After Method Invoke");         
	return object;     
	}     
public class CglibTest {     
	@Test
   		public void testCglib() {
       	DaoProxy daoProxy = new DaoProxy();
       
       	Enhancer enhancer = new Enhancer();
       	enhancer.setSuperclass(Dao.class);
       	enhancer.setCallback(daoProxy);
        
        Dao dao = (Dao)enhancer.create();
        dao.update();
        dao.select();
    }
    
}
}

JDK Proxy优势:

  • 最小化依赖关系,减少依赖意味着简化开发和维护,JDK本身的支持,可能比cglib更加可靠。
  • 平滑进行JDK版本升级
  • 代码实现简单

基于cglib框架的优势:

  • 不需要实现接口
  • 只操作我们关心的类,而不必为其他相关类增加工作量。
  • 高性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值