首页 > 编程语言 >Java反射机制

Java反射机制

时间:2023-08-11 20:44:24浏览次数:35  
标签:反射 Java void Object 代理 class Person 机制 public

Java代理

代理模式:提高真实对象的封装性、拓展性,采用代理对象来代替对真实对象的访问,在不修改原目标对象的基础上,进行额外的功能操作。

Java代理分为静态代理和动态代理

静态代理

直接上代码比较好说明

首先我有一个Person的接口类, 定义苏醒和睡眠两种函数声明

// 接口提供函数声明,但不提供具体定义
public interface Person
{

    void wakeup();

    void sleep();
}

Student以Person为接口进行具体类实现

// 从Person接口进行二次开发
public class Student implements Person{

    public String name;

    // 构造函数
    public Student(){

    }

    public Student(String name){
        this.name = name;
    }

    @Override
    public void wakeup() {
        System.out.printf("%s wake up!\n" ,name);
    }

    @Override
    public void sleep() {
        System.out.printf("%s sleep!\n", name);
    }

}

再为Person设置代理类

public class PersonProxy implements Person {

    private Person person;

    public PersonProxy(Person person) {
        this.person = person;
    }

    @Override
    public void wakeup() {
        System.out.println("Good Morning!");
        person.wakeup();
    }

    @Override
    public void sleep() {
        System.out.println("Good Night!");
        person.sleep();
    }

}

main函数实现

public class Main {
    public static void main(String[] args)  throws Exception{
         Person student = new Student("icfh");
         PersonProxy studentProxy = new PersonProxy(student);

         studentProxy.wakeup();
         studentProxy.sleep();

    }
}

运行结果:

image-20230711210304172

上述一顿代码操作可能有点懵逼

但是对于同一个接口类而言, 需要为其实现一个特定的代理类, 此为静态代理的一个缺点

动态代理

1. JDK动态代理机制(反射代理)

  1. 定义一个接口及其实现类;
  2. 自定义 InvocationHandler 并重写invoke方法,在 invoke 方法中我们会调用原生方法(被代理类的方法)并自定义一些处理逻辑;
  3. 通过 Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) 方法创建代理对象

对于Person接口类的具体实现如上

JDK代理类

import java.lang.reflect.Method;

public class JdkProxy implements InvocationHandler {

    private Object bean;


    public JdkProxy(Object bean){
        this.bean = bean;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 运行时判断是哪个函数
        String methodName = method.getName();
        if(methodName.equals("wakeup")){
            // 代理类完成相应的代理工作,此部分为工作逻辑
            System.out.println("GoodMorning!");
        }else if(methodName.equals("sleep")){
            System.out.println("GoodNight!");
        }
       	// 再调用被代理的类的相应方法
        return method.invoke(bean, args);
    }
}

main函数

public class Main {

    public static void main(String[] args) throws Throwable{       
        // 代理类绑定需要代理的类实例
        JdkProxy proxy = new JdkProxy(new Student("icfh"));
        // 生成绑定对象实例
        Person student = (Person) Proxy.newProxyInstance(proxy.getClass().getClassLoader(), new Class[]{Person.class}, proxy);
        // 经过代理之后,调用原生方法时会先经过代理方法调用。然后在代理方法中再调用原生方法。
        student.wakeup();
        student.sleep();
    }

}

2. CGLIB动态代理机制(继承代理)

可以发现,使用JDK进行动态代理时,只能代理那些实现了接口的类。

CGLIBopen in new window(Code Generation Library)是一个基于ASM字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。

使用方法:

  1. 定义一个类
  2. 自定义实现MethodIntercepter接口类实现并重写intercept方法(原生方法调用时,intercept会拦截,有点像反射代理中的invoke)
  3. 通过Enhancer类的create()进行创建对象
  4. 在调用原生方法时会自动进入代理方法

原生类:

public class AliSmsService {

    public String send(String message){
        System.out.println("send message:"+ message);
        return message;
    }
}

实现MethodInterceptor接口类,然后重写intercept函数,完成代理

import java.lang.reflect.Method;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class DebugMethodInterceptor implements MethodInterceptor{
    @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;
    }

}

Main函数

import net.sf.cglib.proxy.Enhancer;

public class Main{
    public static void main(String[] args) throws Throwable{
        Enhancer enhancer = new Enhancer();
        enhancer.setClassLoader(AliSmsService.class.getClassLoader());
        enhancer.setSuperclass(AliSmsService.class);
        enhancer.setCallback(new DebugMethodInterceptor());
        AliSmsService a = (AliSmsService) enhancer.create();
        a.send("java");
    }
}

静态代理和动态代理的比较

  • 静态代理:
  1. 需要实现接口类
  2. 代理类中需要实现接口类中要进行代理的每个方法

image-20230712120002309

  • 基于反射的动态代理
  1. 仍旧需要实现接口类
  2. 需要重写invoke方法,所有需要代理的原生方法都会在invoke方法中被拓展调用
  • 基于继承的动态代理
  1. 可以代理未实现任何接口的类
  2. 代理类需要实现MethodInterceptor接口,重写拦截器intercept

参考链接

  1. https://segmentfault.com/a/1190000040680716

  2. https://javaguide.cn/java/basis/proxy.html

标签:反射,Java,void,Object,代理,class,Person,机制,public
From: https://www.cnblogs.com/icfh/p/17623902.html

相关文章

  • java之手搓简单ORM框架--SQL的INSERT
    1.手搓简单SQL增删改查框架-插入1.1创建简单类,并使用泛型类,这里可能使用到之间写的三篇知识的内容,如果不了解的小伙伴可以去java高级之泛型java高级之映射java高级之反射当然,前提是必须要把数据库相关连接弄好,这里会专门出一篇java之jdbc现在直接手搓框架开始叭!1.2准备工......
  • 绝了!学编程的还有不知道的吗?这个Java开发工具免费了!
    智能开发正在迅速走红!随着ChatGPT的广泛应用,智能开发越来越受到关注。然而,实际上,在数年前开始尝试智能开发的探索。自从2014年ForresterResearch提出"低代码"的概念以来,低代码平台的发展非常迅速。除了OutSystems和Mendix等低代码厂商之外,微软、谷歌等大型公司也纷纷开始着手低代......
  • JavaWeb之Servlet入门版教务系统(三)
    本次要分享的内容是之前教务系统中系统管理模块下的权限列表功能,包括对权限信息进行增删改查以及对不同的角色身份进行的不同权限分配(重点讲解)。首先还是需要使用mysql数据库准备一张权限表,建表语句如下:DROPTABLEIFEXISTS`sys_permission`;CREATETABLE`sys_permission`(......
  • ATM系统-Java
    Account.javapackageATMSystem;publicclassAccount{privateStringuserName;privateStringcardId;privatecharsex;privateStringpassWord;privatedoublemoney;privatedoublelimit;publicAccount(StringuserName,Str......
  • java使用hutool把服务器图片链接转为base64编码
    需求是把服务器的图片链接或者网上的图片链接地址转为base64位编码方便前端操作建议使用方法一base64编码转为图片在线网址https://imgtobase64.d777.com/方法一:使用hutool的HttpResponse方法1.1引入依赖<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artif......
  • MySQL全文索引的分词机制介绍
    什么是全文查询的“分词机制”?分词机制,也常称为“分词”或“词条化”(Tokenization),是将一段连续的文本切分成若干独立的词汇或词条的过程。在很多文本处理和信息检索的任务中,分词是首要且关键的步骤。分词机制的重要性主要体现在以下几个方面:信息检索:搜索引擎......
  • Java 集合
    Java集合也叫作容器,就是专门用来存放对象的;也就是说,没有办法存放基础数据类型int,必须要存放包装类Integer。Java集合主要是由两大接口派生而来:一个是Collecton接口,主要用于存放单一元素;另一个是Map接口,主要用于存放键值对。对于Collection接口,下面又有三个主要的子接......
  • Android FrameWork——Binder机制详解
    1.前面我曾经发表过一篇blog介绍了aidl实现机制(aidl实现机制浅析),不过那只是停留在java表层,并遗留了一个问题,那就是BinderProxy.transact该方法本地化实现,同时我指出了它的具体代码位置:\frameworks\base\core\jni\android_util_Binder.cpp->staticjbooleanandroid_os_BinderPr......
  • JSON for java入门总结
    一、JSON介绍JSON(JavaScriptObjectNotation),类似于XML,是一种数据交换格式,比如JAVA产生了一个数据想要给JavaScript,则除了利用XML外,还可以利用JSON;JSON相比XML的优势是表达起来很简单;官网:http://www.json.org/JSON是AJAX中的X(就是可以取代XML);     ------出自JSON创......
  • 深入分析 Java I/O 的工作机制
                                  深入分析JavaI/O的工作机制I/O问题是任何编程语言都无法回避的问题,可以说I/O问题是整个人机交互的核心问题,因为I/O是机器获取和交换信息的主要渠道。在当今这个数据大爆炸时代,I/O问题尤其突出,很容易成为一......