- 为什么要用代理
- java中实现动态代理的两种方式
- JDK动态代理编码示例
- Cglib动态代理编码示例
- Cglib底层实现原理
为什么要用代理
代理的作用: 增强原有功能,职责分明:让擅长的人做对应的事情
现实场景: 某个人工作厉害薪资高,但是却没有时间处对象,这时候会考虑找媒婆或者中介所,为自己介绍相亲对象 (通过媒婆代理,让自己实现了找对象的需要)
编码场景: 当现有的类的功能满足不了新需求,但又不能改动以前的代码,这时候就可以考虑使用代理,通过代理类,扩展原有类的功能
阅读 spring AOP,mybatis Mapper 相关源码的时候涉及动态代理
java中实现动态代理的两种方式
- jdk动态代理: JDK 动态代理是基于拦截器和反射实现的,内部采用asm字节码技术动态生成真实对象对应接口的实现类
1 目标对象(被代理的对象)必须要实现业务接口
2 代理对象(代理类):必须实现 InvocationHandler 接口
3 使用 Proxy.newProxyInstance() 创建代理对象
- cglib动态代理: 对于没有实现接口的类,可以通过cglib实现动态代理
1 目标对象(被代理的对象) 只要不是被 final 修饰即可,不要求实现接口
2 代理对象(代理类):必须实现 MethodInterceptor 接口
3 使用 Enhancer.create()创建代理对象
方式 | jdk | cglib |
底层实现 | 生成业务接口实现类 | 生成目标类的子类 |
目标对象 | 必须实现业务接口 | 不能用final 修饰 |
代理对象 | 必须实现InvocationHandler 接口,执行的是代invoke()方法 | 必须实现MethodInterceptor接口 |
代理对象 创建方式 | Proxy.newProxyInstance() | Enhancer.create() |
JDK动态代理编码示例
- 代理模式涉及对象: 目标对象(真实用户),代理(中介)对象,代理创建类Proxy
//1 相亲业务接口
public interface FindLoveService {
/**
* 相亲
* @param target 相亲对象
*/
boolean findLove(RealUser target);
}
// 2 实现了相亲业务的真实对象
@NoArgsConstructor
@AllArgsConstructor
@Data
public class RealUser implements FindLoveService {
private int age;
private String name;
private String advantage;
private String require;
// 实现了相亲方法
public boolean findLove(RealUser target) {
System.out.println(this.name + "说: " + target.getName() + target.getAdvantage() + " 优点这么多,是我心目中的完美对象");
return true;
}
}
/**
* 3 媒婆代理类,实现了InvocationHandler
*/
public class MeiPoProxy implements InvocationHandler {
private RealUser realUser;
/**
* 媒婆通过构造器持有真实对象的引用
* @param realUser 真实对象(努力工作却没有时间相亲的用户)
*/
public MeiPoProxy(RealUser realUser) {
this.realUser = realUser;
}
/**
* @param proxy MeiPoProxy代理对象
* @param method 要调用真实对象的目标方法
* @param args 目标方法入参
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("媒婆帮忙物色好对象");
// 通过反射,调用真实对象的方法 method.invoke(真实对象)
Object rsult = method.invoke(realUser, args);
System.out.println("恭喜双方,没问题的话可以安排良辰吉日了 ");
return rsult;
}
}
public static void main(String[] args) {
RealUser boy = new RealUser(28, "Axing", "帅气小伙,有房有车", "勤俭持家,温柔大方");
//由JDK提供的工具类Proxy在运行时生成指定接口(FindLoveService)的代理实现类
Class[] interfaces = {FindLoveService.class};//RealUser.class.getInterfaces()
FindLoveService meiPoProxy = (FindLoveService) Proxy.newProxyInstance(JDKProxyTest.class.getClassLoader(), interfaces, new MeiPoProxy(boy));
RealUser girl = new RealUser(18, "kk", "肤白貌美,贴心棉袄", "善良,有责任心");
//因为meiPoProxy是实现InvocationHandler接口的代理类,最终的业务逻辑是在InvocationHandler实现类(MeiPoProxy)的invoke方法上,(在invoke方法上实现功能增强)
meiPoProxy.findLove(girl);
}
最终输出结果如下:
媒婆帮忙物色好对象
Axing说: kk肤白貌美,贴心棉袄 优点这么多,是我心目中的完美对象
恭喜双方,没问题的话可以安排良辰吉日了
- Proxy.newProxyInstance() 方法参数说明
/**
* @param loader 类加载器
* @param interfaces 目标对象接口,业务接口
* @param h 实现了 InvocationHandler接口的代理对象
*/
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
// 方法生成业务接口实现类预览
public final class $proxyxx extends Proxy implements FindLoveService{
public boolean findLove(RealUser target) {
// 执行InvocationHandler 代理实现类的invoke方法
return super.h.invock();
}
}
Cglib动态代理编码示例
- 代理模式涉及对象: 目标对象(真实用户),代理(中介)对象,代理创建类Proxy
// 1 真实对象 ,不要求实现接口
@NoArgsConstructor
@AllArgsConstructor
@Data
public class RealUser {
private int age;
private String name;
private String advantage;
private String require;
// 实现了相亲方法
public boolean findLove(RealUser target) {
System.out.println(this.name + "说: " + target.getName() + target.getAdvantage() + " 优点这么多,是我心目中的完美对象");
return true;
}
}
/**
* 代理对象(媒婆代理类) 要求实现 MethodInterceptor
*/
public class MeiPoCglibProxy implements MethodInterceptor {
private RealUser realUser;
/**
* 媒婆通过构造器持有真实对象的引用
*
* @param realUser 真实对象(努力工作却没有时间相亲的用户)
*/
public MeiPoProxy(RealUser realUser) {
this.realUser = realUser;
}
/**
* @param proxy MeiPoProxy代理对象 自己
* @param methodProxy 代理类执行的方法
* @param args 方法入参
* @throws Throwable
*/
// public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("媒婆帮忙物色好对象");
//调用真实对象的方法 method.invoke(真实对象)
Object rsult = methodProxy.invoke(realUser, args);
System.out.println("恭喜双方,没问题的话可以安排良辰吉日了 ");
return rsult;
}
}
public static void main(String[] args) {
//打印我们运行时生成的代理类的class文件,到指定路径
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "C:\\");
RealUser boy = new RealUser(28, "Axing", "帅气小伙,有房有车", "勤俭持家,温柔大方");
//创建代理对象(代理对象通过构造器持有了 目标对象的引用)
RealUser realUserProxy = (RealUser) Enhancer.create(RealUser.class, new MeiPoCglibProxy(boy));
RealUser girl = new RealUser(18, "kk", "肤白貌美,贴心棉袄", "善良,有责任心");
//因为meiPoProxy是实现MethodInterceptor接口的代理类,会先调用到代理类的intercept()方法
realUserProxy.findLove(girl);
}
- Enhancer.create() 创建代理实现类方法参数说明
//type: 目标类的类型, callback:代理类的类型
public static Object create(Class type, Callback callback) {
Enhancer e = new Enhancer();
e.setSuperclass(type);//设置父类 (将目标对象类型,作为代理类的父类)
e.setCallback(callback);
return e.create();
}
Cglib生成的动态代理,实现类预览
- 打印我们运行时生成的代理类的class文件,到指定路径 System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "C:\\");
//打印我们运行时生成的代理类的class文件,到指定路径
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "C:\\");
// 1 生成的代理类是RealUser的子类
// 实现net.sf.cglib.proxy.Factory的目的是提供一些创建代理对象实例的工厂方法,这些方法会比反射创建对象快【clazz.newInstance()】
public class RealUser$EnhancerByCglib$234234 extends RealUser implements Factory {
private static final Method CGLIB$findLove$2$Method;
private static final MethodProxy CGLIB$findLove$2$Proxy;
static void CGLIB$STATICHOOK1() {
Class var0 = Class.forName("cn.javabus.proxy.RealUser$EnhancerByCGLIB$cb212fe7");
Class var1;
Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
CGLIB$findLove$2$Proxy = MethodProxy.create(var1, var0, "(Lcn/javabus/proxy/RealUser;)Z", "findLove", "CGLIB$findLove$2");
}
final boolean CGLIB$findLove$2(RealUser var1) {
return super.findLove(var1);
}
public final boolean findLove(RealUser var1) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
//
Object var2 = var10000.intercept(this, CGLIB$findLove$2$Method, new Object[]{var1}, CGLIB$findLove$2$Proxy);
return var2 == null ? false : (Boolean) var2;
} else {
return super.findLove(var1);
}
}
执行流程分析
1 生成代理类 RealUser realUserProxy = (RealUser) Enhancer.create(RealUser.class, new MeiPoCglibProxy(boy));
2 然后调用代理对象的findLove()
3 然后通过反编译代理类,查看findLove方法,发现在findLove中会调用拦截器intercept()方法。
4 然后在拦截器方法中会通过MethodProxy调用invokeSuper方法。
1 cglib动态代理,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑
2 CGLib性能比JDK创建后的动态代理对象的性能高,但CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例对象,因无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。
3 同时,由于CGLib由于是采用动态创建子类的方法,对于final方法,无法进行代理。
更多参考cglib 底层实现 : CGLIB动态代理底层实现原理 - SegmentFault 思否
本文暂时没有评论,来添加一个吧(●'◡'●)