定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
代理对象和目标对象通常会继承相同的接口,来保持行为的一致性。
区分动态代理和静态代理主要是从代理类的创建时序和类的确定性。
代理类在编译之前就已创建并明确,目标对象和代理对象会继承相同的接口以保持行为的一致性,而且代理对象对目标的增强是确定的。
下面一个简单例子来实现静态代理:
首先,定义一个用户操作的接口
public interface UserDao {
public void create();
public void delete();
public String get();
}
然后,实现一个目标对象类来继承改接口
public class UserDaoImpl implements UserDao {
@Override
public void create() {
System.out.println("UserDaoImpl: create");
}
@Override
public void delete() {
System.out.println("UserDaoImpl: delete");
}
@Override
public String get() {
System.out.println("UserDaoImpl: get");
return null;
}
}
然后,写一个静态代理类,同样的继承用户接口,此处添加属性UserDaoImpl ,并利用构造函数完成实例的传入。
public class UserDaoImplProxy implements UserDao{
private UserDaoImpl userDaoImpl;
public UserDaoImplProxy(UserDaoImpl userDaoImpl){
this.userDaoImpl = userDaoImpl;
}
@Override
public void create() {
System.out.println("UserDaoImplProxy: create");
userDaoImpl.create();
}
@Override
public void delete() {
System.out.println("UserDaoImplProxy: delete");
userDaoImpl.delete();
}
@Override
public String get() {
System.out.println("UserDaoImplProxy: get");
userDaoImpl.get();
return null;
}
}
最后在main函数中调用代理类
public class ScheduleApplication {
public static void main(String[] args) {
UserDaoImplProxy userDaoImplProxy = new UserDaoImplProxy(new UserDaoImpl());
userDaoImplProxy.create();
}
}
可以看到打印如下所示
UserDaoImplProxy: create
UserDaoImpl: create
这样实现的好处是整个代理类的功能是确定的,且一目了然,对于帮助读懂代理类功能是有帮助的。
但是,如果有太多的目标类需要被代理,那么这项工作就显得过于繁琐,可能维护起来的困难不次于直接改动目标类的实现。这时,就需要动态代理的功能了。
根据应用场景和实现方式的不同,动态代理又可以分为JDK动态代理和cglib动态代理,动态代理实现
JAVA反射机制 :是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
JDK动态代理 :是基于Java反射机制,在程序运行过程中,通过被代理的接口来动态生成代理类的字节码二进制流,并加载运行(java反射-对象方法的执行)的过程。因此,JDK的动态代理只适用于实现了接口的对象。
首先介绍下JDK动态代理的使用方法:
先创建目标接口和实现类,为了说明动态代理的特性,特意创建两个接口
//目标接口1
public interface TeamDao {
public void create();
}
//目标接口2
public interface UserDao {
public void create();
}
//目标实现类1
public class TeamDaoImpl implements TeamDao {
@Override
public void create() {
System.out.println("TeamDaoImpl: create");
}
}
//目标实现类2
public class UserDaoImpl implements UserDao {
@Override
public void create() {
System.out.println("UserDaoImpl: create");
}
}
定义动态代理增强类
public class DynamicProxy implements InvocationHandler {
private Object target;
public DynamicProxy(Object target){
this.target = target;
}
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
System.out.println("Dynamics run Begin");
Object result = method.invoke(target, objects);
System.out.println("Dynamics run End");
return result;
}
}
最后,编写客户端代码进行类的调用
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class ScheduleApplication {
public static void main(String[] args) {
//目标类的InvocationHandler设置
InvocationHandler userHandler = new DynamicProxy(new UserDaoImpl());
//创建实现了UserDao接口的代理类$Proxy0的实例
UserDao userDao = (UserDao) Proxy.newProxyInstance(
Client.class.getClassLoader(),new Class[]{UserDao.class},userHandler);
//代理类(即继承Proxy类)方法的调用,实际上执行的是其InvocationHandler的invoke方法
userDao.create();
//
InvocationHandler teamHandler = new DynamicProxy(new TeamDaoImpl());
//创建实现了TeamDao接口的代理类$Proxy1的实例
TeamDao teamDao = (TeamDao) Proxy.newProxyInstance(
Client.class.getClassLoader(),new Class[]{TeamDao.class}, teamHandler);
teamDao.create();
}
}
执行结果为:
Dynamics run Begin
UserDaoImpl: create
Dynamics run End
Dynamics run Begin
TeamDaoImpl: create
Dynamics run End
可以发现,代理类方法的调用执行的是InvocationHandler的invoke方法,那么第一个问题是:
为什么代理类的方法调用执行的是InvocationHandler的invoke方法?
我们首先看一下生成的代理类,此处需要将生成的class文件保存到本地,然后反编译得到其源码,其中,将JDK动态生成的class文件保存到本地的方法是在代码中添加
System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");
利用Idea的反编译插件Pug,得到代理类的源码是
package com.sun.proxy;
import com.example.zyq.schedule.ProxyDemo.UserDao;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy implements UserDao {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void create() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.example.zyq.schedule.ProxyDemo.UserDao").getMethod("create");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
我们暂且不去考虑$Proxy0.class是如何生成的,可以看到对该类create方法的调用,实际执行的就是调用的InvocationHandler(也就是此处DynamicProxy)实现类的invoke方法。
现在我们可以得到JDK动态代理的实现主要通过是java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口,其中:
CGLIB动态代理的原理:就是用Enhancer生成一个原有类的子类,并且设置好callback到proxy, 则原有类的每个方法调用都会转为调用实现了MethodInterceptor接口的proxy的intercept() 函数
定义CGLib的拦截类,继承MethodInterceptor接口并实现拦截(intercept)方法。
import java.lang.reflect.Method;
public class CGLibDynamicProxy implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("Before Cglib Dynamic");
Object result = methodProxy.invokeSuper(o, objects);
System.out.println("After Cglib Dynamic");
return result;
}
}
客户端调用函数:
public class CglibApplication {
public static void main(String[] args){
Enhancer enhancer = new Enhancer();
CGLibDynamicProxy cgLibDynamicProxy = new CGLibDynamicProxy();
enhancer.setSuperclass(UserDaoImpl.class);
enhancer.setCallback(cgLibDynamicProxy);
UserDaoImpl userDao = (UserDaoImpl)enhancer.create();
userDao.create();
}
}
执行结果为:
Before Cglib Dynamic
UserDaoImpl: create
After Cglib Dynamic
完成代理的调用。