JAVA代理与反射学习笔记(一)

本文通过实例演示了Java中如何使用代理模式与反射机制。通过创建接口Car及其实现类Jeep,配合自定义InvocationHandler,展示了不同方式生成代理类的过程,并验证了final方法无法被代理拦截的特点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这几天,为了工作,重新学习了一下InvocationHandler以及Proxy。JAVA的代理和反射在公司的框架搭建、service处理以及RPC调用等地方都能看到他们的身影。因而越发感觉必须要熟练掌握他们的原理和使用方法才行。废话不多说了,切入正题


做了一个简单的demo。Car是一个接口,Jeep是Car的实现类。

package bo;

public interface Car {

public abstract void carName();

}



package bo;

public class Jeep implements Car{

@Override
public void carName(){
System.out.println("Nice to Meet You, I'm Jeep");
}
}


自定义了一个InvocationHandler类,并重载了invoke方法,对使用该Handler生成的代理类$Proxy0在调用非final方法前注入了一句话。效果可以理解为类似AOP。


package handler;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.logging.Logger;

import bo.Car;

public class DetailInvocationHandler implements InvocationHandler{

private Car car;

public DetailInvocationHandler(Car car){
this.car = car;
}

Logger logger = Logger.getLogger(DetailInvocationHandler.class.getName());

@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {

/**
* 1、此时如果如下调用,则将栈溢出。
* 原因:可以看到proxy即为生成的代理类$Proxy0,当调用proxy的carName方法时,
* 等于调用了handler中的invoke方法,此时,就会陷入死循环导致最后栈溢出,
* 然而调用getClass方法并不会溢出,这是因为该方法时final的。
* 2、此处传入proxy的话可以对于annotation、name、method等参数进行监控
*
*/
System.out.println(proxy.getClass().getName()); // 不会溢出
// ((Car)proxy).carName(); // 会溢出

logger.info("Now Enter In InvocationHandler!");

method.invoke(car, args);
return null;
}


}


最后,分别采用三种方法进行代理类的生成,并在最后测试了final方法是否会被拦截。

package service.impl;

import handler.DetailInvocationHandler;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

import bo.Car;
import bo.Jeep;

import service.CarService;

class mockClass{

}

public class CarServiceImpl implements CarService{

@SuppressWarnings("unchecked")
public static void main(String[] args) throws Exception{

/**
* ClassLoader:
* 在调用用户定义的用JAVA实现的ClassLoader时,调用的是ExtClassLoader
* 在调用其他默认情况下的class(classpath下的)时,调用的是AppClassLoader
*
*/
System.out.println(Jeep.class.getClassLoader());
System.out.println(Car.class.getClassLoader());
System.out.println(mockClass.class.getClassLoader());



/**
* Proxy.newProxyInstance方法中,需要三个参数
* 一、ClassLoader,用以将生成的class加载入JVM中去执行
* 二、Interface,用以根据需要实现的接口去生成代理类(相当于子类)
* 三、InvocationHandler,用以对代理类的方法进行调度
*
*/
Car car = new Jeep();
InvocationHandler handler = new DetailInvocationHandler(car);

/**
* 1和2为两种获取interface的方法
*
*/
System.out.println("====================1==========================");
Car proxy = (Car)Proxy.newProxyInstance(mockClass.class.getClassLoader(),car.getClass().getInterfaces(), handler);
proxy.carName();
System.out.println("====================2==========================");
Car proxy2 = (Car)Proxy.newProxyInstance(Car.class.getClassLoader(),new Class[]{Car.class}, handler);
proxy2.carName();

/**
* Class.getConstructor用来声明特指一个代理类的构造函数(源代码中:Proxy(InvocationHandler h){this.h = h})
* Constructor.newInstance用来填入构造函数,并生成相应的代理类
*
*/
System.out.println("====================3==========================");
Class class1 = Proxy.getProxyClass(Car.class.getClassLoader(), car.getClass().getInterfaces());
Car proxy3 = (Car)class1.getConstructor(new Class[]{InvocationHandler.class}).newInstance(new Object[]{handler});
proxy3.carName();


/**
* final修饰符的方法不会被拦截!
*/
System.out.println("====================4==========================");
Car proxy4 = (Car)Proxy.newProxyInstance(Car.class.getClassLoader(),new Class[]{Car.class}, handler);
System.out.println(proxy4.getClass().getName());

}

}



详细的解释以及需要关注的一些地方都在注释中了,大部分在网上都能查得到。只是做了个demo将这些记忆点都记录了下来而已。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值