Java代理机制及动态代理和CGLIB代理详解

1.代理模式

    代理模式(Proxy)为其他对象提供一种代理以控制对这个对象的访问。可以通过代理加入一些如事务、权限、日志、监控报警等操作。


    应用场景:比如某个实现类有多个接口,只想暴露其中一两个,则可使用代理,再比如方法增强,在方法的执行前后增加一些事务、日志、监控等,甚至可以不执行被代理的方法,再如远程调用,通过Proxy.newProxyInstance代理一个该接口对应的InvocationHandler对象,然后在InvocationHandler的invoke方法内封装通讯细节就可以了,如最经典的当然是Java标准库的RMI,其它比如hessian,webservice框架中的远程调用,实现原理相似。

2.静态代理

    如果不同接口的某些类想使用代理模式来实现相同的功能 ,静态代理需要实现多个代理类,动态代理只需要实现一个代理类。  且当接口方法越来越来,静态代理均需要实现接口方法,不便于维护扩展。

public interface Subject {
	void request();
}
public class RealSubject implements Subject{

	@Override
	public void request() {
		System.out.println("这是一次real请求");
	}

}
/**
 * 
 * 静态代理类
 *
 */
public class StaticProxy implements Subject{
	
	private RealSubject realSubject = null;
	
	public StaticProxy(RealSubject realSubject) {
		this.realSubject = realSubject;
	}
	
	@Override
	public void request() {
		System.out.println("StaticProxy request bgein");
		//调用委托代理类的实际实现方法
		realSubject.request();
		System.out.println("StaticProxy request end");
	}
	
}
public class ProxyTest {
	public static void main(String[] args) {
		StaticProxy staticProxy = new StaticProxy(new RealSubject());
		staticProxy.request();
	}
}
运行结果:

StaticProxy request bgein
这是一次real请求
StaticProxy request end

3.动态代理

   java.lang.reflect.Proxy + java.lang.reflect.InvocationHandler(jdk动态代理,基于接口实现)
      java.lang.reflect.Proxy:提供用于创建动态代理类及实例的静态方法:newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 
      返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。
       java.lang.reflect.InvocationHandler:提供代理实例调用被代理类实现的接口的方法:invoke(Object proxy, Method method, Object[] args) 
       在代理实例上处理方法调用并返回结果。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyHandler implements InvocationHandler{
	
	private Object target;
	
	public ProxyHandler(Object target) {
		super();
		this.target = target;
	}
	
	public Object getProxy()  throws Throwable{
		//Proxy.newProxyInstance  返回代理类实例
		return Proxy.newProxyInstance(this.target.getClass().getClassLoader(), this.target.getClass().getInterfaces(), this);
	}
	
	/**
	 * 复写invoke方法,此处调用被代理类的接口实现
	 * @param proxy   在其上调用方法的代理实例
	 * @param method  对应于在代理实例上调用的接口方法的 Method 实例
	 * @param args    包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为 null。
	 * @param args    基本类型的参数被包装在适当基本包装器类(如 java.lang.Integer 或 java.lang.Boolean)的实例中
	 * @return
	 * @throws Throwable
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object object = null;
		System.out.println("ProxyHandler begin");
		object = method.invoke(target, args);
		System.out.println("ProxyHandler end");
		return object;
	}

}
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import com.lls.proxy.ProxyHandler;
import com.lls.service.Subject;
import com.lls.service.impl.RealSubject;

public class HandlerTest {
	public static void main(String[] args) {
		Subject subject = new RealSubject();
		ProxyHandler proxyHandler = new ProxyHandler(subject);
		try {
			Subject subjectProxy = (Subject) proxyHandler.getProxy();
			
			//证明subject是Proxy的实例并实现了Subject接口  
	        System.out.println(subjectProxy instanceof Proxy);    
	        //subjectProxy的Class类是$Proxy0并继承了Proxy,实现了subjectProxy接口  
	        System.out.println("subjectProxy的Class类是:"+subjectProxy.getClass().toString());  
	        System.out.print("subjectProxy中的属性有:");  
	        Field[] field=subjectProxy.getClass().getDeclaredFields();  
	        for(Field f:field){  
	            System.out.print(f.getName()+", ");  
	        }  
	        System.out.print("\n"+"subjectProxy中的方法有:");  
	        Method[] method=subjectProxy.getClass().getDeclaredMethods();  
	        for(Method m:method){  
	            System.out.print(m.getName()+", ");  
	        }  
	        System.out.println("\n"+"subjectProxy的父类是:"+subjectProxy.getClass().getSuperclass());  
	        System.out.println("subjectProxy实现的接口是:");  
	        Class<?>[] interfaces=subjectProxy.getClass().getInterfaces();  
	        for(Class<?> i:interfaces){  
	            System.out.print(i.getName()+", ");  
	        }  
	        System.out.println("\n"+"运行结果为:");  
			subjectProxy.request();
		} catch (Throwable e) {
			e.printStackTrace();
		}

	}
}
运行结果:

true
subjectProxy的Class类是:class com.sun.proxy.$Proxy0
subjectProxy中的属性有:m1, m3, m0, m2, 
subjectProxy中的方法有:equals, toString, hashCode, request, 
subjectProxy的父类是:class java.lang.reflect.Proxy
subjectProxy实现的接口是:
com.lls.service.Subject, 
运行结果为:
ProxyHandler begin
这是一次real请求
ProxyHandler end
生成的代理类: public   final   class  $Proxy0  extends  Proxy  implements  Subject
其中request的定义如下:

public final void request() {  
        try {  
            super.h.invoke(this, m3, null);  
            return;  
        } catch (Error e) {  
        } catch (Throwable throwable) {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  
public $Proxy0(InvocationHandler invocationhandler) {  
        super(invocationhandler);  //调用的是Proxy中的构造方法
    }  



故subjectProxy.request()调用的是代理类的request方法,

进而调用父类Proxy中的h的invoke()方法.即InvocationHandler.invoke()。

且$Proxy0代理类中所有方法最终都是父类Proxy中的h的invoke()方法.即InvocationHandler.invoke(),

然后通过Merthod.invoke方法 反射执行。

CDLIB动态代理

cglib是针对类来实现代理的,利用ASM动态生成目标类的子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类或方法进行代理。
import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class CglibProxy implements MethodInterceptor {
	
	private Enhancer enhancer = new Enhancer();
	
	public Object getProxy(Class clazz) {
	        enhancer.setSuperclass(clazz);  
	        enhancer.setCallback(this); 
	        return enhancer.create();// 返回代理对象,返回的对象其实就是一个封装了“实现类”的代理类,是实现类的实例。
	}

	@Override
	public Object intercept(Object paramObject, Method paramMethod, Object[] paramArrayOfObject,MethodProxy paramMethodProxy) throws Throwable {
		System.out.println("CglibProxy intercept before:" + paramMethodProxy.getSuperName());
		System.out.println(paramMethod.getName());
		Object object = paramMethodProxy.invokeSuper(paramObject, paramArrayOfObject);
		System.out.println("CglibProxy intercept end:" + paramMethodProxy.getSuperName());
		return object;
	}

}
public class CglibTest {
	public static void main(String[] args) {
		 	CglibProxy cglibProxy = new CglibProxy();  
		  
	        RealSubject rs = (RealSubject)cglibProxy.getProxy(RealSubject.class); 
	        
	        rs.request();
	}
}
运行结果:
CglibProxy intercept before:CGLIB$request$0
request
这是一次real请求
CglibProxy intercept end:CGLIB$request$0

jdk和cglib动态代理实现的区别
1、jdk动态代理生成的代理类和委托类实现了相同的接口;
2、cglib动态代理中生成的字节码更加复杂,生成的代理类是委托类的子类,且不能处理被final关键字修饰的方法;
3、jdk采用反射机制调用委托类的方法,cglib采用类似索引的方式直接调用委托类方法;
4、通过反射机制获得动态代理类的构建函数,从而创建动态代理类实例。如RealSubject经过proxy.newProxyInstance生成的代理对象的类名$Proxy0。
   而cglib是利用ASM生成java字节码从而动态的产生代理对象。

spring AOP 代理选择:
1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP 
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP 
3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

强制使用cglib
<aop:aspectj-autoproxy proxy-target-class="true"/>

代理对象的生成过程由Enhancer类实现,大概步骤如下:
1、生成代理类Class的二进制字节码;
2、通过Class.forName加载二进制字节码,生成Class对象;
3、通过反射机制获取实例构造,并初始化代理类对象。



  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值