GVKun编程网logo

简单的Spring,将ClasspathApplicationContext用于独立的应用程序,如何重用?(spring中的classpath)

19

在本文中,您将会了解到关于简单的Spring,将ClasspathApplicationContext用于独立的应用程序,如何重用?的新资讯,同时我们还将为您解释spring中的classpath的相

在本文中,您将会了解到关于简单的Spring,将ClasspathApplicationContext用于独立的应用程序,如何重用?的新资讯,同时我们还将为您解释spring中的classpath的相关在本文中,我们将带你探索简单的Spring,将ClasspathApplicationContext用于独立的应用程序,如何重用?的奥秘,分析spring中的classpath的特点,并给出一些关于ClassPathXMLApplicationContext 上下文加载过程、ClassPathXmlApplicationContext 加载 spring 配置文件、ClassPathXMLApplicationContext上下文加载过程、ClassPathXmlApplicationContext类的实用技巧。

本文目录一览:

简单的Spring,将ClasspathApplicationContext用于独立的应用程序,如何重用?(spring中的classpath)

简单的Spring,将ClasspathApplicationContext用于独立的应用程序,如何重用?(spring中的classpath)

如果我有一个独立的主应用程序。说20堂课。它们都可能随时需要与spring配置(ApplicationContext)定义的bean接口。我将在主应用程序入口点引导类路径应用程序上下文。但是,如何重用已经实例化的bean?

例如,将ClasspathApplicationContext设置为单例似乎是一种不好的方法,但这就是这个主意。

我以为我已经看到了GlobalContextLocator或类似的东西,但是没有看到如何使用它的示例。

答案1

小编典典

有很多方法可以做到这一点。最好的参考在这里:

http://static.springframework.org/spring/docs/2.5.x/reference/beans.html#context-
introduction

您需要查看的特定类是SingletonBeanFactoryLocator和ContextSingletonBeanFactoryLocator。

如果使用SingletonBeanFactoryLocator,则可以使用以下内容查找bean:

BeanFactoryLocator bfl = SingletonBeanFactoryLocator.getInstance();BeanFactoryReference bf = bfl.useBeanFactory("com.mycompany.myapp");MyClass zed = bf.getFactory().getBean("mybean");

Javadocs中对此有很好的详细解释:

http://static.springframework.org/spring/docs/2.5.x/api/org/springframework/beans/factory/access/SingletonBeanFactoryLocator.html

另外,为了清楚起见,请确保配置文件位于应用程序的类路径中,否则查找将失败。

ClassPathXMLApplicationContext 上下文加载过程

ClassPathXMLApplicationContext 上下文加载过程

今天看了一下《spring 技术内幕》,看了下 spring IOC 容器的加载过程,但是里面的代码很杂,就自己用源码的测试用例 debug 了一下看了下过程

测试用例

    @Test
    public void testSingleConfigLocation() throws IOException {
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(FQ_SIMPLE_CONTEXT);
        assertTrue(ctx.containsBean("someMessageSource"));
        LazyBean bean = ctx.getBean(LazyBean.class);
        Environment environment =ctx.getEnvironment();
        String[] profiles =environment.getDefaultProfiles();
        for(String s :profiles){
            System.out.println(s);
        }
        CollectionBean bean2 = (CollectionBean) ctx.getBean("collection");
        SingletonBean bean3 = ctx.getBean(SingletonBean.class);
        SingletonBean bean4 = ctx.getBean(SingletonBean.class);
        if (bean != null) {
            System.out.println(bean.getTestFiled());
        }
        if (bean2 != null) {
            System.out.println(bean2.getList());
        }
        if (bean3 != null) {
            bean3.process();
        }
        if (bean4 != null) {
            bean4.process();
        }
        System.out.println(ctx.getBeanDefinitionCount());
        /*
         * System.out.println(ctx.getBean("lazyBean"));
         * System.out.println(ctx.getBean("lazyBean"));
         */
        ctx.close();
    }

加载过程

  • 首先会调用父类 AbstractApplicationContext 的静态初始化块
static {
        // Eagerly load the ContextClosedEvent class to avoid weird classloader issues
        // on application shutdown in WebLogic 8.1. (Reported by Dustin Woods.)
        ContextClosedEvent.class.getName();
    }

大概就是说为了避免一些奇怪的问题会首先发布一个 ContextClosedEvent 事件,然后按照正常的初始化依次初始化父类。

  • 调用构造方法中的 refresh 方法,这个方法也是上下文初始化的开始
public ClassPathXmlApplicationContext(
            String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
            throws BeansException {

        super(parent);
        setConfigLocations(configLocations);
        if (refresh) {
            refresh();
        }
    }
  • refresh 方法会调用 AbstractRefreshableApplicationContext 中的 refreshBeanFactory 方法创建一个 DefaultListableBeanFactory 实例,作为上下文的容器
protected final void refreshBeanFactory() throws BeansException {
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());
            customizeBeanFactory(beanFactory);
            loadBeanDefinitions(beanFactory);
            synchronized (this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }
  • 创建了容器之后就要从 xml 文件中加载和注册 bean 的定义,上面的 loadBeanDefinition 方法在 AbstractXmlApplicationContext 中的实现会被调用
    @Override
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        // Create a new XmlBeanDefinitionReader for the given BeanFactory.
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

        // Configure the bean definition reader with this context''s
        // resource loading environment.
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

        // Allow a subclass to provide custom initialization of the reader,
        // then proceed with actually loading the bean definitions.
        initBeanDefinitionReader(beanDefinitionReader);
        loadBeanDefinitions(beanDefinitionReader);
    }

    /**
     * Initialize the bean definition reader used for loading the bean
     * definitions of this context. Default implementation is empty.
     * <p>Can be overridden in subclasses, e.g. for turning off XML validation
     * or using a different XmlBeanDefinitionParser implementation.
     * @param reader the bean definition reader used by this context
     * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader#setDocumentReaderClass
     */
    protected void initBeanDefinitionReader(XmlBeanDefinitionReader reader) {
        reader.setValidating(this.validating);
    }

    /**
     * Load the bean definitions with the given XmlBeanDefinitionReader.
     * <p>The lifecycle of the bean factory is handled by the {@link #refreshBeanFactory}
     * method; hence this method is just supposed to load and/or register bean definitions.
     * @param reader the XmlBeanDefinitionReader to use
     * @throws BeansException in case of bean registration errors
     * @throws IOException if the required XML document isn''t found
     * @see #refreshBeanFactory
     * @see #getConfigLocations
     * @see #getResources
     * @see #getResourcePatternResolver
     */
    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
        Resource[] configResources = getConfigResources();
        if (configResources != null) {
            reader.loadBeanDefinitions(configResources);
        }
        String[] configLocations = getConfigLocations();
        if (configLocations != null) {
            reader.loadBeanDefinitions(configLocations);
        }
    }
  • 这两个方法会用来加载并注册 BeanDefiniton,它们又会使用 XmlBeanDefinitionReader 来加载 xml 中的 bean 的定义,bean 定义的解析会使用 DefaultBeanDefinitionDocumentReader,它又会使用 BeanDefinitionParserDelegate 类委托解析 bean 的定义
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//委托BeanDefinitionParserDelegate进行解析 BeanDefinitionHolder bdHolder
= delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name ''" + bdHolder.getBeanName() + "''", ele, ex); } // Send registration event. getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }

上面黑体标注的是将解析的 BeanDefinition 注册到上下文中的过程,我之前没找到这个方法很奇怪 loadBeanDefinition 返回的都是 int 我就在想,BeanDefinition 哪去了。静态方法会调用 BeanDefinitionRegistry

接口的 registerBeanDefinition 方法。而 DefaultListableBeanFactory 实现了这个接口,

public static void registerBeanDefinition(
            BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
            throws BeanDefinitionStoreException {

        // Register bean definition under primary name.
        String beanName = definitionHolder.getBeanName();
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

        // Register aliases for bean name, if any.
        String[] aliases = definitionHolder.getAliases();
        if (aliases != null) {
            for (String alias : aliases) {
                registry.registerAlias(beanName, alias);
            }
        }
    }

到此 BeanDefinition 就被注册到了 ClassPathXmlApplicationContext 中,还有很多细节没贴出来,自己 debug 一下很有意思的

 

ClassPathXmlApplicationContext 加载 spring 配置文件

ClassPathXmlApplicationContext 加载 spring 配置文件

通过 ClassPathXmlApplicationContext 加载 spring 配置文件  但是有两个配置文件中 bean 互相依赖   先加载哪个配置文件  都会出现 BeanCreationException  求指点

ClassPathXMLApplicationContext上下文加载过程

ClassPathXMLApplicationContext上下文加载过程

今天看了一下《spring技术内幕》,看了下spring IOC容器的加载过程,但是里面的代码很杂,就自己用源码的测试用例debug了一下看了下过程

测试用例

    @Test
    public void testSingleConfigLocation() throws IOException {
        ClasspathXmlApplicationContext ctx = new ClasspathXmlApplicationContext(FQ_SIMPLE_CONTEXT);
        assertTrue(ctx.containsBean("someMessageSource"));
        LazyBean bean = ctx.getBean(LazyBean.class);
        Environment environment =ctx.getEnvironment();
        String[] profiles =environment.getDefaultProfiles();
        for(String s :profiles){
            System.out.println(s);
        }
        CollectionBean bean2 = (CollectionBean) ctx.getBean("collection");
        SingletonBean bean3 = ctx.getBean(SingletonBean.class);
        SingletonBean bean4 = ctx.getBean(SingletonBean.class);
        if (bean != null) {
            System.out.println(bean.getTestFiled());
        }
        if (bean2 != null) {
            System.out.println(bean2.getList());
        }
        if (bean3 != null) {
            bean3.process();
        }
        if (bean4 != null) {
            bean4.process();
        }
        System.out.println(ctx.getBeanDeFinitionCount());
        /*
         * System.out.println(ctx.getBean("lazyBean"));
         * System.out.println(ctx.getBean("lazyBean"));
         */
        ctx.close();
    }

加载过程

  • 首先会调用父类AbstractApplicationContext的静态初始化块
    static {
        // Eagerly load the ContextClosedEvent class to avoid weird classloader issues
        // on application shutdown in WebLogic 8.1. (Reported by Dustin Woods.)
        ContextClosedEvent.class.getName();
    }

大概就是说为了避免一些奇怪的问题会首先发布一个ContextClosedEvent事件,然后按照正常的初始化依次初始化父类。

  • 调用构造方法中的refresh方法,这个方法也是上下文初始化的开始
    public ClasspathXmlApplicationContext(
            String[] configLocations,boolean refresh,@Nullable ApplicationContext parent)
            throws BeansException {

        super(parent);
        setConfigLocations(configLocations);
        if (refresh) {
            refresh();
        }
    }
  • refresh方法会调用AbstractRefreshableApplicationContext中的refreshbeanfactory方法创建一个DefaultListablebeanfactory实例,作为上下文的容器
    protected final void refreshbeanfactory() throws BeansException {
        if (hasbeanfactory()) {
            destroyBeans();
            closebeanfactory();
        }
        try {
            DefaultListablebeanfactory beanfactory = createbeanfactory();
            beanfactory.setSerializationId(getId());
            customizebeanfactory(beanfactory);
            loadBeanDeFinitions(beanfactory);
            synchronized (this.beanfactoryMonitor) {
                this.beanfactory = beanfactory;
            }
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean deFinition source for " + getdisplayName(),ex);
        }
    }
  • 创建了容器之后就要从xml文件中加载和注册bean的定义,上面的loadBeanDeFinition方法在AbstractXmlApplicationContext中的实现会被调用
    @Override
    protected void loadBeanDeFinitions(DefaultListablebeanfactory beanfactory) throws BeansException,IOException {
        // Create a new XmlBeanDeFinitionReader for the given beanfactory.
        XmlBeanDeFinitionReader beanDeFinitionReader = new XmlBeanDeFinitionReader(beanfactory);

        // Configure the bean deFinition reader with this context‘s
        // resource loading environment.
        beanDeFinitionReader.setEnvironment(this.getEnvironment());
        beanDeFinitionReader.setResourceLoader(this);
        beanDeFinitionReader.setEntityResolver(new ResourceEntityResolver(this));

        // Allow a subclass to provide custom initialization of the reader,// then proceed with actually loading the bean deFinitions.
        initBeanDeFinitionReader(beanDeFinitionReader);
        loadBeanDeFinitions(beanDeFinitionReader);
    }

    /**
     * Initialize the bean deFinition reader used for loading the bean
     * deFinitions of this context. Default implementation is empty.
     * <p>Can be overridden in subclasses,e.g. for turning off XML validation
     * or using a different XmlBeanDeFinitionParser implementation.
     * @param reader the bean deFinition reader used by this context
     * @see org.springframework.beans.factory.xml.XmlBeanDeFinitionReader#setDocumentReaderClass
     */
    protected void initBeanDeFinitionReader(XmlBeanDeFinitionReader reader) {
        reader.setValidating(this.validating);
    }

    /**
     * Load the bean deFinitions with the given XmlBeanDeFinitionReader.
     * <p>The lifecycle of the bean factory is handled by the {@link #refreshbeanfactory}
     * method; hence this method is just supposed to load and/or register bean deFinitions.
     * @param reader the XmlBeanDeFinitionReader to use
     * @throws BeansException in case of bean registration errors
     * @throws IOException if the required XML document isn‘t found
     * @see #refreshbeanfactory
     * @see #getConfigLocations
     * @see #getResources
     * @see #getResourcePatternResolver
     */
    protected void loadBeanDeFinitions(XmlBeanDeFinitionReader reader) throws BeansException,IOException {
        Resource[] configResources = getConfigResources();
        if (configResources != null) {
            reader.loadBeanDeFinitions(configResources);
        }
        String[] configLocations = getConfigLocations();
        if (configLocations != null) {
            reader.loadBeanDeFinitions(configLocations);
        }
    }
  • 这两个方法会用来加载并注册BeanDefiniton,它们又会使用XmlBeanDeFinitionReader来加载xml中的bean的定义,bean定义的解析会使用DefaultBeanDeFinitionDocumentReader,它又会使用BeanDeFinitionParserDelegate类委托解析bean的定义
    protected void processBeanDeFinition(Element ele,BeanDeFinitionParserDelegate delegate) {
//委托BeanDeFinitionParserDelegate进行解析 BeanDeFinitionHolder bdHolder
= delegate.parseBeanDeFinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDeFinitionIfrequired(ele,bdHolder); try { // Register the final decorated instance. BeanDeFinitionReaderUtils.registerBeanDeFinition(bdHolder,getReaderContext().getRegistry()); } catch (BeanDeFinitionStoreException ex) { getReaderContext().error("Failed to register bean deFinition with name ‘" + bdHolder.getBeanName() + "‘",ele,ex); } // Send registration event. getReaderContext().fireComponentRegistered(new BeanComponentDeFinition(bdHolder)); } }

上面黑体标注的是将解析的BeanDeFinition注册到上下文中的过程,我之前没找到这个方法很奇怪loadBeanDeFinition返回的都是int我就在想,BeanDeFinition哪去了。静态方法会调用BeanDeFinitionRegistry

接口的registerBeanDeFinition方法。而DefaultListablebeanfactory实现了这个接口,

    public static void registerBeanDeFinition(
            BeanDeFinitionHolder deFinitionHolder,BeanDeFinitionRegistry registry)
            throws BeanDeFinitionStoreException {

        // Register bean deFinition under primary name.
        String beanName = deFinitionHolder.getBeanName();
        registry.registerBeanDeFinition(beanName,deFinitionHolder.getBeanDeFinition()); // Register aliases for bean name,if any.
        String[] aliases = deFinitionHolder.getAliases();
        if (aliases != null) {
            for (String alias : aliases) {
                registry.registeralias(beanName,alias);
            }
        }
    }

到此BeanDeFinition就被注册到了ClasspathXmlApplicationContext中,还有很多细节没贴出来,自己debug一下很有意思的

ClassPathXmlApplicationContext类

ClassPathXmlApplicationContext类

org.springframework.context.support 
Class ClassPathXmlApplicationContext

java.lang.Objectextended by org.springframework.core.io.DefaultResourceLoaderextended by org.springframework.context.support.AbstractApplicationContextextended by org.springframework.context.support.AbstractRefreshableApplicationContextextended by org.springframework.context.support.AbstractRefreshableConfigApplicationContextextended by org.springframework.context.support.AbstractXmlApplicationContextextended by org.springframework.context.support.ClassPathXmlApplicationContext
All Implemented Interfaces:
BeanFactory,  BeanNameAware,  DisposableBean,  HierarchicalBeanFactory,  InitializingBean,  ListableBeanFactory,  ApplicationContext,  ApplicationEventPublisher, ConfigurableApplicationContext,  Lifecycle,  MessageSource,  ResourceLoader,  ResourcePatternResolver

public class ClassPathXmlApplicationContext
   

   

   

    
    
extends  AbstractXmlApplicationContext

该类继承了AbstractXmlApplicationContext,实现了BeanFctory和ApplicationContext接口。


使用BeanFactory接口还是ApplicationContext接口?

BeanFactory只是实现了Spring基本的功能,而ApplicationContext添加了更多的功能,并且ApplicationContext完全支持BeanFactory的所有功能,ApplicationContext建立于BeanFactory基础之上的。ApplicationContext是BeanFactory的子接口,而BeanFactory是ApplicationContext的父接口。所以,建议优先使用ApplicationContext接口。

官方文档解释:

In short, the BeanFactory provides the configuration framework and basic functionality, and the ApplicationContext adds more enterprise-specific functionality. The ApplicationContext is a complete superset of the BeanFactory











来自为知笔记(Wiz)


今天关于简单的Spring,将ClasspathApplicationContext用于独立的应用程序,如何重用?spring中的classpath的介绍到此结束,谢谢您的阅读,有关ClassPathXMLApplicationContext 上下文加载过程、ClassPathXmlApplicationContext 加载 spring 配置文件、ClassPathXMLApplicationContext上下文加载过程、ClassPathXmlApplicationContext类等更多相关知识的信息可以在本站进行查询。

本文标签: