1. 什么是代理模式
代理模式:为其他对象提供一种代理以控制对这个对象的访问。
2. 代理的作用
代理作用:
- 使目标对象和调用者解耦
- 可以对目标对象进行功能加强扩展
代理模式的作用场景:
- 当调用者不适合直接调用目标对象的时候,可以使用代理对象简介访问目标对象
- 当目标对象调用时需要做一些额外的扩展功能,但是直接修改代码不适合,可以使用代理对象对目标对象调用的方法进行加强。
代理模式分为静态代理和动态代理。
3. 静态代理
静态代理:在编译的时候就确定了代理类和目标类之间的关系,代理类在编译之前就存在。
静态代理的实现思路:
新建一个接口,让目标类和代理类同时实现接口中的方法,在代理类中增加一个对目标类的引用,代理类在实现接口方法的过程中调用目标类的引用调用其接口实现,同时在其调用的前后进行一些功能的扩展。
静态代理的代码实例:
-
目标接口类Consumer
public interface Consumer { void rent(); }
-
目标类User
public class User implements Consumer { public User() { } public void rent() { System.out.println("用户付款,签订租房合同"); } }
-
代理类UserProxy
public class UserProxy implements Consumer { private Consumer consumer; public UserProxy(Consumer consumer) { this.consumer = consumer; } public void rent() { System.out.println("房屋中介开始找房子"); System.out.println("房屋中介打电话通知用户"); this.consumer.rent(); System.out.println("成功租到房子!!"); } }
-
测试类StaticProxyTest
public class StaticProxyTest { public StaticProxyTest() { } public static void main(String[] args) { UserProxy userProxy = new UserProxy(new User()); userProxy.rent(); } }
静态代理的总结:
- 特点:
- 代理类在编译之前就已经确定
- 代理类服务于一种类型的目标类
- 代理类和目标类都要实现相同的接口
- 优点:比较简单实现,适用于功能固定的场景
- 缺点:代码不易于管理、很容易造成代码的冗余、不够灵活和代码维护
4. 动态代理
动态代理:在程序运行的时候创建代理类。
动态代理分为两种:
-
jdk动态代理(基于接口的代理)
-
cglib动态代理(基于类的代理)
1. jdk动态代理
jdk动态代理是基于接口的动态代理,jdk动态代理的实现主要是依赖于两个类:InvocationHandler和Proxy,其中InvocationHandler类的解释:
/** * {@code InvocationHandler} is the interface implemented by * the <i>invocation handler</i> of a proxy instance. *该接口是被代理实例实现的一个调用处理程序。 * <p>Each proxy instance has an associated invocation handler. * When a method is invoked on a proxy instance, the method * invocation is encoded and dispatched to the {@code invoke} * method of its invocation handler. 每个代理实例都有一个于其关联的调用处理,当代理实例的方法调用的时候,该方法的调用会被编码并且分配到调用处理器。 */ public interface InvocationHandler { /** * Processes a method invocation on a proxy instance and returns * the result. This method will be invoked on an invocation handler * when a method is invoked on a proxy instance that it is * associated with.该方法会在一个代理实例上调用并且返回结果。当invocationHandler所关联的代理实例调用方法的时候这 * 个方法会在调用处理器上被调用 * proxy:代理实例对象 method:调用的目标对象的方法对象 args:目标方法的传参对象 */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
proxy类的解释:
/** * {@code Proxy} provides static methods for creating dynamic proxy * classes and instances, and it is also the superclass of all * dynamic proxy classes created by those methods. 提供创建动态代理类和实例的静态方法,同时该类是所有通过这些静态方法创建的动态代理类的超类 */ public class Proxy implements java.io.Serializable { /** loader:类加载器,定义由哪个类加载器加载对应的代理类 interfaces:接口数组,代理对象将要实现的接口,我们提供这些接口,代理类会实现这些接口中的方法,我们可以通过代理类调用这些方法 h:调用处理类,表明当前的代理对象关联的调用处理器是哪一个,最后在代理类调用其接口实现方法的时候,会调用该调用处理器的方法完成接口的扩展。 */ @CallerSensitive public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException {} }
jdk代理的实现思路:
新建一个接口,目标类实现该接口,创建一个InvocationHandler的实现类,完成对该接口方法的扩展,使用时候用Proxy的静态方法newProxyInstance创建一个代理实例,调用接口方法。
jdk动态代理的代码实例:
-
目标接口类Consumer
public interface Consumer { public void rent(); }
-
目标类User
public class User implements Consumer { @Override public void rent() { System.out.println("用户付款,签订租房合同"); } }
-
InvocationHandler的实现类UserProxy
public class UserProxy implements InvocationHandler { private Object target; public UserProxy(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("房屋中介开始找房子"); System.out.println("房屋中介打电话通知用户"); Object invoke = method.invoke(target, args); System.out.println("成功租到房子!!"); return invoke; } }
-
测试类JdkProxyTest
public class JdkProxyTest { public static void main(String[] args) { UserProxy userProxy = new UserProxy(new User()); Consumer consumer = (Consumer) Proxy.newProxyInstance(userProxy.getClass().getClassLoader(), new Class[]{Consumer.class}, userProxy); consumer.rent(); } }
-
cglib动态代理
cglib动态代理私基于类的动态代理。cglib是通过动态生成一个子类去覆盖目标类中的非final方法,并且设置号callback,则原有的每个方法调用就会转变成调用用户定义的拦截方法intercept。
cglib中的相关类MethodInterceptor和Enhancer:
/** var1:代理对象 var2:代理方法 var3:传参 var4:代理父类方法 */ 调用目标方法的任意非final方法都会调用该方法 public interface MethodInterceptor extends Callback { Object intercept(Object var1, Method var2, Object[] var3, MethodProxy var4) throws Throwable; }
Enhancer类的解释:
/**The dynamically * generated subclasses override the non-final methods of the superclass and * have hooks which callback to user-defined interceptor * implementations. 动态生成子类覆盖父类的非final方法,通过钩子回调到用户自定义的拦截实现 */ public class Enhancer extends AbstractClassGenerator { // 创建一个新类 public Object create() {} }
cglib代理的实现思路:
新建一个MethodInterceptor的实现类,调用Enhancer传入目标类类型和MethodInterceptor的实现类创建代理类。
cglib代理的代码实现:
-
目标类User
public class User { public void rent1() { System.out.println("用户付款,签订租房合同1"); } }
-
MethodInterceptor的实现类CglibUserInterceptor
public class CglibUserInterceptor implements MethodInterceptor { public Object getProxy(Class t) { Enhancer enhancer = new Enhancer(); // 目标类的class enhancer.setSuperclass(t); // 设置代理类的回调 enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("房屋中介开始找房子"); System.out.println("房屋中介打电话通知用户"); Object invoke = methodProxy.invokeSuper(o, objects); System.out.println("成功租到房子!!"); return invoke; } }
-
测试类CglibTest
public class CglibTest { public static void main(String[] args) { CglibUserInterceptor cglibUserInterceptor = new CglibUserInterceptor(); User proxy = (User)cglibUserInterceptor.getProxy(User.class); proxy.rent1(); } }
jdk代理和cglib代理的区别:
- jdk使用于实现接口的类,cglib通过继承来实现,该类应该为非final类型,方法是非final和private的
- jdk和cglib都是在运行时生成代理类的字节码,但是jdk是直接写字节码,cglib是使用asm生成字节码,更加复杂,生成代理对象jdk效率比cglib要快
- jdk调用代理方法是通过反射,但是cglib是通过FastClass机制直接调用方法,cglib执行效率较高
-
-
5. 静态代理和动态代理的区别
静态代理在编译时就已经实现,编译完成后代理类是一个实际的class文件。
动态代理是在运行时动态生成的,即编译完成后没有实际的class文件,而是在运行时动态生成类字节码,并且加载到JVM中。
6. 总结
java代理推荐使用动态代理,jdk动态代理基于反射,只能对实现接口的目标类生成代理,cglib动态代理基于继承,对于非final修饰的类生成代理。如果目标对象创建比较频繁,推荐使用jdk代理,jdk创建代理比较快,如果目标对象创建比较少,但是调用比较多,推荐使用cglib代理,cglib代理的代理方法执行效率高。