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动态代理
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
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、通过反射机制获取实例构造,并初始化代理类对象。