反射&代理

一 反射 是众多框架功能实现得核心机制,如:Spring中的注解MyBatis 中的Dao的方法到到XML中Sql的执行
Class对象获取的四种方式:
1 TargetObject.class 已知具体类
2 Class.forName("cn.con.TargetObject") 一直类的具体路径
3 instance.getClass() 已知对象的实例
4 ClassLoader.loadClass("cn.com.TargetObject") 使用类加载器通过类的路径获取,值得注意的是:类加载器获取的Class对象不会初始化,
也就是说初始化时一些列步骤和对象的静态代码块和静态对象都不会执行,思想类似于懒加载,推荐。

二 静态代理
1 使用较少不推荐,因为:静态代理需要手动增强代理对象中的每个方法,代理对象做修改,对应的代理类也需要手动修改,非常不灵活
2 静态代理的实现原理
1)创建一个接口和实现类
2)创建一个代理类也实现这个接口
3)在代理中中注入这个实现类,在代理类对应实现类的同名方法中调用实现类中的方法
3 在JVM 层面来说, 静态代理在编译时就将接口、实现类、代理类这些都变成了一个个实际的 class 文件

三 动态代理
1 相比于静态代理来说,动态代理更加灵活。我们不需要针对每个目标类都单独创建一个代理类,并且也不需要我们必须实现接口,
我们可以直接代理实现类( CGLIB 动态代理机制)。
2 从 JVM 角度来说,动态代理是在运行时动态生成类字节码,并加载到 JVM 中的。
3 Spring AOP、RPC 框架的实现都依赖了动态代理
4 就 Java 来说,动态代理的实现方式有很多种,比如 JDK 动态代理、CGLIB 动态代理
4.1 JDK 动态代理机制
4.1.1 jdk动态代理必须实现接口
4.1.2 原理:
1)创建一个类实现InvocationHandler接口,重写invoke方法,在invoke方法中添加增强的逻辑
2)动态生成代理对象,而不需要像静态代理中一样手动去写
Proxy.newProxyInstance(
target.getClass().getClassLoader(), // 目标类的类加载
target.getClass().getInterfaces(), // 代理需要实现的接口,可指定多个
new DebugInvocationHandler(target) // 代理对象对应的自定义 InvocationHandler
)
4.2 CGLIB 动态代理
4.2.1JDK 动态代理有一个最致命的问题是其只能代理实现了接口的类。为了解决这个问题,我们可以用 CGLIB 动态代理机制来避免。
4.2.2 CGLIB 通过继承方式实现代理
4.3.3 原理:
DebugMethodInterceptor implements MethodInterceptor,实现MethodInterceptor接口重写intercept方法,编写额外逻辑
public class CglibProxyFactory {
public static Object getProxy(Class<?> clazz) {
// 创建动态代理增强类
Enhancer enhancer = new Enhancer();
// 设置类加载器
enhancer.setClassLoader(clazz.getClassLoader());
// 设置被代理类
enhancer.setSuperclass(clazz);
// 设置方法拦截器
enhancer.setCallback(new DebugMethodInterceptor());
// 创建代理类
return enhancer.create();
}
}


四 总结
1 代理的好处:可以在不修改原有对象的基础上,提供额外的功能
2 静态代理是编译时生成代理类,动态代理是运行时生成
3 JDK 动态代理只能只能代理实现了接口的类或者直接代理接口,而 CGLIB 可以代理未实现任何接口的类
4 JDK动态代理是通过反射获取代理对象的类和方法,使用同一个接口的实现类做代理类,
而CGLIB是使用的拦截的方式获取代理对象的类和方法,使用的代理对象的子类作为代理类

上一篇:JDK 和 CGLib 实现动态代理和区别


下一篇:什么是aop?