java常用的代理模式
代理模式是对目标对象提供的另一种访问形式,即通过代理对象访问目标对象,这样就可以在不修改目标对象的情况下来扩展目标对象的功能
常用的代理分为静态,动态
静态:程序员创建,在程序运行前已被编译成.class文件
动态:JDK动态代理,Cglib代理,在程序运行期间通过反射生成代理类
1:静态代理
静态代理需要定义接口或者父类,代理对象和目标对象同时实现或者继承
1 | package com.java.proxy; |
1 | package com.java.proxy; |
1 | package com.java.proxy; |
1 | public static void main(String[] args) { |
优点:在不修改目标类(UserServiceImpl)的情况下扩展目标类
缺点:每个代理类要实现与目标类相同的接口,代码重复太多,如果接口修改,目标类和代理类都要修改,代码入侵性较大
2:动态代理–JDK动态代理
JDK动态代理不需要实现接口,通过我们指定目标类或者代理对象的接口类型JDK动态创建代理对象
主要类:java.lang.reflect.Proxyh中的newProxyInstance()方法
java.lang.reflect.InvocationHandler 实现接口
Proxy.newProxyInstance():
1 | /** |
在上个例子基础上创建动态代理,目标类还是(UserServiceImpl),这里通过一个动态代理工厂来创建代理类
1 | package com.java.proxy; |
1 | public static void main(String[] args) { |
Proxy.newProxyInstance()源码中,主要代码如下:
Class<?> cl = getProxyClass0(loader, intfs);
1 | private static Class<?> getProxyClass0(ClassLoader loader, |
//获取代理类参数为InvocationHandler的构造函数
final Constructor<?> cons = cl.getConstructor(constructorParams)
//生成代理类,并返回
return cons.newInstance(new Object[]{h})
大致步骤为:1根据传入的interfaces动态生成代理类,它实现interfaces接口
2用ClassLoader把上步生成的代理类加载到jvm中
3调用InvocationHandler构造函数把代理类实例化
总结:代理对象不需要实现接口,但是目标对象一定要实现接口
3:动态代理–Cglib代理
上边两种代理方式都是通过实现与目标类相同的接口来生成代理对象,但有种情况我们只有类,没有接口,这个时候就可以使用以目标对象子类的方式类实现代理,这种方法就叫做Cglib代理。
Cglib代理也叫子类代理,通过动态构建一个子类,继承目标类来实现扩展目标类
java运行顺序:.java文件 --> 编译成.class文件 --> classloader加载实例化成具体的类
Cglib包的底层是通过使用字节码处理框架ASM来转换字节码(.class文件)并生成新的代理类。(spring AOP)
1 | package com.java.proxy; |
1 | package com.java.proxy; |
1 | public static void main(String[] args) { |
总结:
- cglib代理的对象不能实现,
- 需要引入cglib的jar文件,但是Spring的核心包中已经包括了Cglib功能,所以直接引入spring-core的jar包即可
- 代理类不能为finl
- 目标对象不能为static或者final,那么就不会被拦截,即不会执行目标对象额外的业务方法。
Spring AOP 如果代理类实现接口,就采用JDK动态代理,如果没有实现接口,用Cglib代理