Java反射与代理(静态代理,动态代理(jdk动态代理和CGLIB动态代理))
反射与动态代理
反射
反射,即通过类对象class来操作数据。
获取类对象class
//全类名获取
Class clazz1 = Class.forName("com.example.reflection.Student");
//根据类+.class
Class clazz2 = Student.class;
//通过实例对象getClass方法
Student student = new Student("小明",1);
Class clazz3 = student.getClass();
//根据构造器获取
ClassLoader classLoader = clazz1.getClassLoader();
Class clazz4 = classLoader.loadClass("com.example.reflection.Student");
获取类的元素Field
getFiled - 根据名称获取公有的(public)类成员。
getDeclaredField - 根据名称获取已声明的类成员。但不能得到其父类的类成员。
getFields - 获取所有公有的(public)类成员。
getDeclaredFields - 获取所有已声明的类成员。
获取类的方法Method
getMethod - 返回类或接口的特定方法。其中第一个参数为方法名称,后面的参数为方法参数对应 Class 的对象(如参数是String类型就填String.class以此类推)。
getDeclaredMethod - 返回类或接口的特定声明方法。其中第一个参数为方法名称,后面的参数为方法参数对应 Class 的对象。
getMethods - 返回类或接口的所有 public 方法,包括其父类的 public 方法。
getDeclaredMethods - 返回类或接口声明的所有方法,包括 public、protected、默认(包)访问和 private 方法,但不包括继承的方法。
调用的话,使用method.invoke(参数)。
获取类的构造器Constructor
getConstructor - 返回类的特定 public 构造方法。参数为方法参数 对应 Class 的对象。
getDeclaredConstructor - 返回类的特定构造方法。参数为方法参数 对应 Class 的对象。
getConstructors - 返回类的所有 public 构造方法。
getDeclaredConstructors - 返回类的所有构造方法。
以上都是反射的入门,下面是反射的用处:代理。
静态代理
新建一个接口UserService
public interface UserService {
public void select();
public void update();
}
写一个实现类UserServiceImpl
public class UserServiceImpl implements UserService {
@Override
public void select() {
System.out.println("查询方法");
}
@Override
public void update() {
System.out.println("更新方法");
}
}
再写一个静态代理类
/**
* 静态代理
* 以某个实现类作为成员变量,对它的操作进行增强
* 缺点:
* 虽然静态代理实现简单,且不侵入原代码,但是,当场景稍微复杂一些的时候,静态代理的缺点也会暴露出来。
* 1.当需要代理多个类的时候,由于代理对象要实现与目标对象一致的接口,有两种方式:
* 1.1 只维护一个代理类,由这个代理类实现多个接口,但是这样就导致代理类过于庞大
* 1.2 新建多个代理类,每个目标对象对应一个代理类,但是这样会产生过多的代理类
* 2.当接口需要增加、删除、修改方法的时候,目标对象与代理类都要同时修改,不易维护。
*/
public class UserServiceProxy implements UserService{
//被代理的对象
private UserService target;
public UserServiceProxy(UserService target){
this.target = target;
}
@Override
public void select() {
preHandle();
target.select();
afterHandle();
}
@Override
public void update() {
preHandle();
target.update();
afterHandle();
}
private void preHandle(){
System.out.println("前置处理");
}
private void afterHandle(){
System.out.println("后置处理");
}
public static void main(String[] args) {
UserServiceImpl userService = new UserServiceImpl();
UserServiceProxy proxy = new UserServiceProxy(userService);
proxy.select();
proxy.update();
}
}
动态代理
代理类通过继承InvocationHandler接口,重写invoke方法。
使用的时候三个步骤:
- 先要弄一个接口实现类实例出来。
- 再弄个代理类实例。
- 通过Proxy.newInstance()方法弄个proxy出来。
/**
* jdk的动态代理
*/
public class UserServiceDynamicProxy implements InvocationHandler {
//被代理的对象,这个其实可以不写,只是习惯。
private Object target;
public UserServiceDynamicProxy(Object target){
this.target=target;
}
//proxy,代理对象本身,method 代理的方法,args 方法参数
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//前置处理
preHandle();
Object result = method.invoke(target,args);
//后置处理
afterHandle();
return result;
}
private void preHandle(){
System.out.println("前置处理");
}
private void afterHandle(){
System.out.println("后置处理");
}
public static void main(String[] args) {
//被代理对象
UserService target = new UserServiceImpl();
//代理对象实现类实例
UserServiceDynamicProxy handler = new UserServiceDynamicProxy(target);
UserService proxy = (UserService) Proxy.newProxyInstance(
UserService.class.getClassLoader(),//接口的类加载器
UserService.class.getInterfaces(),//实现的接口
handler// 代理对象实现类实例
);
//调用方法
proxy.select();
proxy.update();
}
}
以上是jdk的动态代理,原理是基于接口的反射,意味着类不继承接口就用不了jdk的动态代理,所以衍生出CGLIB代理,代理类通过继承接口实现类。
CGLIB动态代理
第一步:导依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
下面举个例子,Student类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private String name;
private Integer score;
public void work(){
System.out.println("作业还没写完");
}
}
CGLIB代理类,需要实现 MethodInterceptor接口
public class StudentProxy implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
preHandle();
Object res = methodProxy.invokeSuper(obj, args);
afterHandle();
return res;
}
private void preHandle()
{
System.out.println("作业借我抄下");
}
private void afterHandle()
{
System.out.println("写完再借我抄下");
}
public static void main(String[] args) {
//使用
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Student.class); //将代理类作为父类
enhancer.setCallback(new StudentProxy());
Student proxy = (Student) enhancer.create();
proxy.work();
}
}
使用CGLIB代理类:通过Enhancer类的setSuperclass方法和setCallback方法初始化后,create出来的就是代理类实例了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY