JAVA源码解析(1)-java.beans.Beans、ObjectInputStreamWithLoader、BeansAppletContext、BeansAppletStu

此文章的java环境:1.8.0_131

本人出于学习阶段,如有不正请指正


方法剖析

getInstanceOf(Object bean, Class<?> targetType) 

来自API的解释:从给定 bean 中获得表示源对象的指定类型视图的对象。 

    public static Object getInstanceOf(Object bean, Class<?> targetType) {
        return bean;
    }

当前方法给出两个参数,直接返回第一个参数,产生了疑问,但是,在注释当中有这样一句话:

This method is provided in Beans 1.0 as a hook to allow the addition of more flexible bean behaviour in the future.
翻译则是,当前方法在1.0版本中的Beans中仅仅提供一个钩子,如果以后有了更灵活了特性了则允许添加。换句话说,这个方法以后如果有新特性了能用到,现在只是作为一个占位符写在这。


instantiate(ClassLoader cls, String beanName) 

instantiate(ClassLoader cls, String beanName, BeanContext beanContext) 

instantiate(ClassLoader cls, String beanName, BeanContext beanContext, AppletInitializer initializer) 
来自API的解释:实例化 bean。

前两个方法最终都是调用的第三个方法,没有的参数则是传入的null,下面来分析一下第三个实例化方法的流程

这三个方法都是实例化bean,在系统给出的注释当中,有这样一句话:

The bean is created based on a name relative to a class-loader.This name should be a dot-separated name such as "a.b.c".
意思是说,当前传入的bean的名称应该用“.”来分割,并且简历好的bean是基于传入的名字和类加载器来确定。

需要注意的是,这个bean的名字可以是类名或者是一个序列化对象的名字,寻找的顺序则是:序列化后的对象名->类名。

而且加载序列化后的对象名的时候会用beanName加上".ser"的后缀的形式去加载资源,在举例中给了这样一句话:

For example, given a beanName of "x.y", Beans.instantiate would first try to read a serialized object from the resource "x/y.ser" and if that failed it would try to load the class "x.y" and create an instance of that class.
也就是说,如果一个beanName是x.y,则会先去找x/y.ser,找不到则会去找x.y这个类

如果说一个类是 java.applet.Applet 的子类,则会进行特殊的初始化:首先,会提供一个默认的 AppletStub 和 AppletContext ,然后会执行这个小程序的"init"方法,但是如果这个bean已经反序列化了,则会跳过这一步。如果当前bean是Applet,那么应该是调用方去调用"start"方法,并且应该在这个小程序被添加到了一个可见的AWT容器之后再调用。

Applets通过 beans.instantiate来启动和内置启动的方式略有不同,前者没办法直接访问属性,需要通过get/set方法来访问,并且建议用JDK appletviewer和BDK BeanBox来进行测试。


下面是源码部分:

public static Object instantiate(ClassLoader cls, String beanName, BeanContext beanContext, AppletInitializer initializer)
                        throws IOException, ClassNotFoundException {

        InputStream ins;
        ObjectInputStream oins = null;
        Object result = null;
        boolean serialized = false;
        IOException serex = null;

        // 如果classloder为null,那么会在System的classloder可用的时候进行替代
        // 系统类加载器上的调用将首先查找引导类加载器
        if (cls == null) {
            try {
                cls = ClassLoader.getSystemClassLoader();
            } catch (SecurityException ex) {
                // 出于系统安全,不允许加载classloder
            }
        }

        // 尝试寻找一个序列化对象
        final String serName = beanName.replace('.','/').concat(".ser");
	//尝试从当前类加载器和System的加载器去读取资源
        if (cls == null)
            ins =  ClassLoader.getSystemResourceAsStream(serName);
        else
            ins =  cls.getResourceAsStream(serName);
        if (ins != null) {
            try {
		//这个地方读取对象的输入流时调用的两个方法中,else分支中调用的ObjectInputStreamWithLoader是Beans的内部类,这个内部类实现了ObjectInputStream接口,其中新增了一个成员变量loader,用于存放当前对象的类加载器
                if (cls == null) {
                    oins = new ObjectInputStream(ins);
                } else {
                    oins = new ObjectInputStreamWithLoader(ins, cls);
                }
                //此处获取Object的方法将在IO篇的时候给出
		result = oins.readObject();
                serialized = true;
                oins.close();
            } catch (IOException ex) {
                ins.close();
                // 此处产生的异常是在读取对象的时候抛出,不对这个地方的异常做处理,但是后面可能会用到这个异常,所以先进行记录下来
                serex = ex;
            } catch (ClassNotFoundException ex) {
                //此处的异常由readObject抛出,对象获取不成功则直接抛出异常
		ins.close();
                throw ex;
            }
        }
	//ObjectInputStream有一个名为enableOverride的属性,如果为true,则oins.readObject()过程中会使result为null,也说明没有序列化后的对象,则尝试去初始化这个类
        if (result == null) {
          
            Class<?> cl;

            try {
                cl = ClassFinder.findClass(beanName, cls);//此处会调用ClassLoader去加载类对象,最终调用的是Class.forName,在调用之前会对beanName做初步检查
            } catch (ClassNotFoundException ex) {
                // 找不到类,在前面如果有一个被记录下来的异常,那么抛出它,否则重新抛出ClassNotFoundException。
                if (serex != null) {
                    throw serex;
                }
                throw ex;
            }
	    // 如果类没有被public所修饰,那么则会抛出异常
            if (!Modifier.isPublic(cl.getModifiers())) {
                throw new ClassNotFoundException("" + cl + " : no public access");
            }

            /*
             * 开始实例化对象
             */

            try {
                result = cl.newInstance();
            } catch (Exception ex) {
               throw new ClassNotFoundException("" + cl + " : " + ex, ex);
            }
        }

        if (result != null) {

            // 如果这个类是applet,则初始化


            AppletStub stub = null;

            if (result instanceof Applet) {
                Applet  applet      = (Applet) result;
		//如果当前参数中,applet的初始化参数不存在,那么就需要当成applet来处理
                boolean needDummies = initializer == null;

                if (needDummies) {

                    // 此处寻找资源名称的规则与前面赘述的x.y的查找规则一致

                    final String resourceName;

                    if (serialized) {
                        // 实例化后的Bean
                        resourceName = beanName.replace('.','/').concat(".ser");
                    } else {
                        // 普通的类
                        resourceName = beanName.replace('.','/').concat(".class");
                    }

                    URL objectUrl = null;
                    URL codeBase  = null;
                    URL docBase   = null;

                    // 开始获取资源
                    if (cls == null) {
                        objectUrl = ClassLoader.getSystemResource(resourceName);
                    } else
                        objectUrl = cls.getResource(resourceName);

                    // 如果资源名称是 "a/b/c.class" 那么我们会设置对象URL是 "file://bert/classes/a/b/c.class" ,代码路径是 "file://bert/classes/"
             // 上下文路径是 "file://bert/classes/a/b/"

                    if (objectUrl != null) {
                        String s = objectUrl.toExternalForm(); // 转换URL
			//开始查找资源
                        if (s.endsWith(resourceName)) {
                            int ix   = s.length() - resourceName.length();
                            codeBase = new URL(s.substring(0,ix));
                            docBase  = codeBase;

                            ix = s.lastIndexOf('/');

                            if (ix >= 0) {
                                docBase = new URL(s.substring(0,ix+1));
                            }
                        }
                    }

                    //设置一个默认的 context 和 stub,默认的上下文则是一个匿名类BeansAppletContext和一个匿名类BeansAppletStub
                    BeansAppletContext context = new BeansAppletContext(applet);

                    stub = (AppletStub)new BeansAppletStub(applet, context, codeBase, docBase);
                    applet.setStub(stub);
                } else {
		    //如果不是applet,则直接初始化
                    initializer.initialize(applet, beanContext);
                }

                // 如果存在一个BeanContext,那么在可能的情况下将其加入(有关BeanContext会单独赘述)

                if (beanContext != null) {
                    unsafeBeanContextAdd(beanContext, result);
                }

                //如果当前已经反序列化,那么代表已经初始化了,否则还需要进行初始化操作 

                if (!serialized) {
                    // 如果是applet则需要设置初始化大小
                    applet.setSize(100,100);
                    applet.init();
                }

                if (needDummies) {
                  ((BeansAppletStub)stub).active = true;
                } else initializer.activate(applet);

            } else if (beanContext != null) unsafeBeanContextAdd(beanContext, result);
        }

        return result;
    }



isDesignTime() 

来自API的解释:测试是否正处于设计模式。

此处的API主要是用于获取当前在Applet是否处于设计模式,一般的class不会用到这个方法


setDesignTime(boolean isDesignTime) 
来自API的解释: 用于设置是否处于设计模式。

注意,如果有安全管理器,则会调用其checkPropertiesAccess方法,并很可能会抛出Security Exception


isGuiAvailable() 

来自API的解释:确定 bean 是否可以假定某个 GUI 是可用的。

这通常在windowing环境中返回true,并且通常在服务器环境中或者应用程序作为批处理作业的一部分运行时返回false。


setGuiAvailable(boolean isGuiAvailable) 
来自API的解释:用于设置是否正运行在可进行 GUI 交互的环境中,与设置设计模式的方法一样,如果有安全管理器,则会调用其checkPropertiesAccess方法,并很可能会抛出Security Exception

isInstanceOf(Object bean, Class<?> targetType) 
来自API的解释:检查是否可以将 bean 视为给定目标类型。 

此处直接调用Introspector.isSubclass()方法,用于判断bean的class是否是目标类型的子类


有一点要注意的,上面有两处获取SecurityManager是通过System.getSecurityManager();来获取


spring-beans-5.3.10.release.jar是Spring框架的一个核心模块之一。Spring框架是一个开源的Java应用程序开发框架,用于简化企业级应用程序的开发。spring-beans模块提供了容器和配置文件等机制,用于管理和组织JavaBean对象。 在Spring框架中,JavaBean是一种符合特定规范的类,它用于封装数据和提供业务逻辑。Spring框架的思想是通过将应用程序的配置信息和业务逻辑与具体实现解耦,从而提高应用程序的可维护性和可测试性。 spring-beans模块的主要功能包括: 1. 容器:spring-beans模块提供了一个容器,用于管理和组织JavaBean对象。容器负责创建、销毁和管理对象的生命周期,并提供依赖注入等功能,使得对象之间的协作更加灵活和可配置。 2. 配置文件:spring-beans模块支持使用XML、注解或Java代码等方式来配置应用程序的各个组件,包括JavaBean的定义、依赖关系的声明以及其他配置信息。配置文件使得应用程序的配置更加直观和可维护。 3. 依赖注入:spring-beans模块通过依赖注入的方式,将对象之间的依赖关系从代码中分离出来,并由容器进行管理。这使得对象之间的耦合度降低,同时也提高了代码的可测试性和可重用性。 4. AOP(面向切面编程):spring-beans模块支持AOP,可以通过配置文件或注解的方式来声明横切逻辑,并将其应用到目标对象的方法上。AOP可以实现事务管理、日志记录、性能监控等功能,提高应用程序的扩展性和可维护性。 5. 事件机制:spring-beans模块提供了一个事件机制,用于在对象之间传递消息。应用程序中的某个事件发生时,容器会将该事件通知给所有注册了对应监听器的对象。事件机制可以实现解耦和、松散耦合的软件设计。 总之,spring-beans-5.3.10.release.jar是Spring框架的一个核心模块,提供了容器、配置文件、依赖注入、AOP和事件机制等功能,用于简化企业级Java应用程序的开发。它的存在使得应用程序的开发更加简单、灵活和可维护。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值