Java基础06-反射和代理

  • 反射
  • 反射可以在运行时分析类以及执行类中方法的能力。可以通过反射,获取任意一个类的所有属性和方法,还可以操作属性或执行调用这些方法。
  • 使用场景:动态代理;注解使用;AOP等
  • 代理
  • 概念
    使用代理对象来代替对真实对象的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。比如:在目标对象的某个方法执行前增加一些自定义的功能。分为静态代理和动态代理两种实现。
  • 静态代理
    JVM层面理解,在编译期,就将接口、实现类、代理类等,实现为一个个的.class文件。需要对每个目标类都单独实现一个代理类。AspectJ。
    • 实现步骤:
      • 定义一个接口及其实现类;
      • 创建一个代理类,同样实现该接口;
      • 将目标对象注入进代理类,然后在代理类的对应方法调用目标类中的对应方法。(本质是通过代理类屏蔽对目标对象的访问,并且可以在目标方法执行前后扩展功能)
  • 动态代理
    • 从JVM角度来说,动态代理是在运行期,动态生成类字节码,并加载到JVM中。
    • 不需要针对每个目标类都单独创建一个代理类,且不需要必须实现接口,就可以直接代理实现类(CGLIB 动态代理机制);
    • JDK 动态代理
      • JDK动态代理主要涉及java.lang.reflect包下的两个类:Proxy和InvocationHandler。其中InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑 ,并通过反射机制调用目标类的代码,动态地横切逻辑和业务逻辑编织在一起。
      • 只提供了基于接口的动态代理,不支持类的代理。只能代理实现了接口的类。
        • 动态生成的代理类,已经继承了Proxy类,所以不能再继承其他类。
        • 创建动态代理对象: Proxy.newProxyInstance(xx1,xx2,xx3); 方法获取某个类的代理对象。
        • 必须实现InvocationHandler 接口来自定义处理逻辑,当动态代理对象调用一个方法时,其方法的调用会被转发到实现InvocationHandler 接口类的 invoke 方法来调用。动态地将横切逻辑和业务编织在一起。
        • 实现步骤
          • 定义一个接口及其实现类;
          • 自定义类并实现 InvacationHandler 接口,并重写 invoke 方法。在 invoke 方法中,调用原生方法(被代理类的方法),并自定义一些处理逻辑;
          • 通过Proxy.newProxyInstance() 方法创建代理对象。
public final class $Proxy0 extends Proxy implements Interface{      
    public $Proxy0(InvocationHandler paramInvocationHandler) {             
        super(paramInvocationHandler);
    }
// 该方法为被代理接口的业务方法,代理类都会自动生成相应的方法,里面去执行invocationHandler 的invoke方法。     
    public final void sayHello(String paramString){
          try {
              this.h.invoke(this, m3, new Object[] { paramString });             
              return;         
          } catch (Error|RuntimeException localError) {             
              throw localError;         
          }
          catch (Throwable localThrowable) {             
              throw new UndeclaredThrowableException(localThrowable);         
          }     
      } 
   }

/**
 - 
 - @param loader 类加载器,用户加载代理对象
 - @param interfaces 被代理类实现的一些接口
 - @param h 实现了 InvocationHander 接口的对象
**/
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException {
}

public interface InvocationHandler {
/**
 * 当使用代理对象调用方法时,实际会调用该方法
 *
 * @param proxy 动态生成的代理类
 * @param method 与代理类对象调用的方法相对应
 * @param args 当前method 方法的参数
 */
 public Object invoke(Object proxy, Method method, Object[] args);
 }
CGLIB (Code Generation library)动态代理
    CGLIB是一个基于ASM的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。
    CGLIB 是通过继承的方法实现的动态代理。在运行时动态的生成一个继承目标对象的代理类(子类对象),并重写覆盖其中特定方法并添加增强代理,然后创建代理对象实例。
    MethodInterceptor 接口和 Enhancer 类是核心
    	实现步骤
    	自定义一个类;
    	自定义类并实现 MethodInterceptor 接口并重写 intercept 方法,intercept 用于拦截增强被代理类的方法,和JDK 动态代理中的invoke方法类似。
public interface MethodInterceptor extends Callback {

     /**
      * 拦截被代理类中的方法
      * @parama obj 被代理的对象(需要增强的对象)
      * @param method 被拦截的方法
      * @param args 方法入参
      * @param proxy 用于调用原始的方法
     **/
     public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable;
     }

public class DebugMethodInterceptor implements MethodInterceptor { 
     /**     
      * @param o        被代理的对象(需要增强的对象)     
      * @param method   被拦截的方法(需要增强的方法)     
      * @param args     方法入参
      * @param methodProxy 用于调用原始方法
      */
     @Override
     public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
         //调用方法之前,我们可以添加自己的操作        
         System.out.println("before method " + method.getName());
         Object object = methodProxy.invokeSuper(o, args);
         //调用方法之后,我们同样可以添加自己的操作        
         System.out.println("after method " + method.getName());        return object;    
     }
 }
通过Enhancer 类的 create() 创建代理类。
 public static Object getProxy(class<?> clazz) {
     // 创建动态代理增强类
     Enhancer enhancer = new Enhancer();
     // 设置类加载器
     enhancer.setClassLoader(clazz.getClassLoader())
     // 设置被代理类
     enhancer.setSuperclass(clazz);
     // 设置方法拦截器
     enhancer.setCallback(new DebugMethodInterceptor);
     // 创建代理类
     enhancer.create();
 }
  • JDK和CGLIB动态代理区别
    • JDK动态代理是基于接口的代理,必须要有接口;
    • CGLIB动态代理是通过字节码底层继承要代理类来实现。因为被final修饰的类无法进行代理;
    • 如果被代理的对象是实现类,Spring默认使用JDK动态代理来完成;如果被代理的对象不是实现类,Spring会强制使用CGLIB来实现动态代理。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值