spring容器、BeanFactory、ApplicatContext、WebApplicationContext

1、BeanFactory接口

package org.springframework.beans.factory;

import org.springframework.beans.BeansException;
import org.springframework.core.ResolvableType;

public interface BeanFactory {
    String FACTORY_BEAN_PREFIX = "&";
    // getBean()方法从容器中返回Bean
    Object getBean(String var1) throws BeansException;

    <T> T getBean(String var1, Class<T> var2) throws BeansException;

    Object getBean(String var1, Object... var2) throws BeansException;

    <T> T getBean(Class<T> var1) throws BeansException;

    <T> T getBean(Class<T> var1, Object... var2) throws BeansException;
    // 容器里有没有一个Bean
    boolean containsBean(String var1);
    // 一个Bean是不是单例的
    boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;
    // 一个Bean是不是复例的
    boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;

    boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException;

    boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;

    Class<?> getType(String var1) throws NoSuchBeanDefinitionException;

    String[] getAliases(String var1);
}
View Code

BeanFactory的子接口ListableBeanFactory

package org.springframework.beans.factory;

import java.lang.annotation.Annotation;
import java.util.Map;
import org.springframework.beans.BeansException;
import org.springframework.core.ResolvableType;

public interface ListableBeanFactory extends BeanFactory {
    // BeanDefinition
    boolean containsBeanDefinition(String var1);
    // BeanDefinition
    int getBeanDefinitionCount();
    // BeanDefinition
    String[] getBeanDefinitionNames();

    String[] getBeanNamesForType(ResolvableType var1);

    String[] getBeanNamesForType(Class<?> var1);

    String[] getBeanNamesForType(Class<?> var1, boolean var2, boolean var3);

    <T> Map<String, T> getBeansOfType(Class<T> var1) throws BeansException;

    <T> Map<String, T> getBeansOfType(Class<T> var1, boolean var2, boolean var3) throws BeansException;

    String[] getBeanNamesForAnnotation(Class<? extends Annotation> var1);

    Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> var1) throws BeansException;

    <A extends Annotation> A findAnnotationOnBean(String var1, Class<A> var2) throws NoSuchBeanDefinitionException;
}
View Code

BeanFactory的子接口HierarchicalBeanFactory  [ˌhaɪəˈrɑːkɪkl] 

通过这个接口Spring的IoC容器可以建立父子层级关联的容器体系,子容器可以访问父容器中的Bean,但父容器不能访问子容器中的Bean。

package org.springframework.beans.factory;

public interface HierarchicalBeanFactory extends BeanFactory {
    // 获得父级的BeanFactory
    BeanFactory getParentBeanFactory();

    boolean containsLocalBean(String var1);
}
View Code

AutowireCapableBeanFactory接口

定义了自动装配

DefaultSingletonBeanRegistry接口

DefaultSingletonBeanRegistry里有一个addSingleton()方法,会把单例的Bean保存到一个ConcurrentHashMap

    // 缓存到一个map里
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256); 

    protected void addSingleton(String beanName, Object singletonObject) {
        Map var3 = this.singletonObjects;
        synchronized(this.singletonObjects) {
            // 添加单对象到map
            this.singletonObjects.put(beanName, singletonObject != null ? singletonObject : NULL_OBJECT);
            this.singletonFactories.remove(beanName);
            this.earlySingletonObjects.remove(beanName);
            this.registeredSingletons.add(beanName);
        }
    }
View Code

DefaultListableBeanFactory 实现类

这个类实现了上面所有的接口

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
      http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="tank" class="my.Tank"></bean>

</beans>
View Code
package my;

import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import java.io.IOException;

public class MyTest {
    public static void main(String[] args) throws IOException {
        // 创建一个资源加载器
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        // 使用ClassPathResource加载配置文件
        Resource resource = resolver.getResource("classpath:my.xml");

        // 创建一个BeanFactory的对象
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
        reader.loadBeanDefinitions(resource);

        // 单例的Bean已经缓存到容器中
        Tank tank = (Tank)factory.getBean(Tank.class);
        tank.run();
    }
}
class Tank {
    public void run() {
        System.out.println("run...");
    }
}
View Code

2、ApplicatContext接口 

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
        MessageSource, ApplicationEventPublisher, ResourcePatternResolver {}

ApplicationContext继承了ListableBeanFactory、HierarchicalBeanFactory,另外还通过其它几个接口扩展了BeanFactory的功能。

ApplicationEventPublisher让spring容器拥有发布事件的功能,包括spring容器启动、关闭。ApplicationContext基于Observer模式(java.util包中有对应实现),提供了针对Bean的事件传播功能。事件传播的一个典型应用是,当Bean中的操作发生异常(如数据库连接失败),则通过事件传播机制通知异常监听器进行处理。

ResourcePatternResolver,所有的ApplicationContext实现类都实现了类似于PathMatchingResourcePatternResolver的功能,可以通过文件路径装载spring配置文件。

import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import java.io.IOException;

public class MyTest {
    public static void main(String[] args) throws IOException {
        // 使用ClassPathXmlApplicationContext可以省略路径字符串的classpath前缀
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:my.xml");
        //AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
        Tank tank = context.getBean(Tank.class);

        tank.run();
    }
}
class Tank {
    public void run() {
        System.out.println("run...");
    }
}
@Configuration
class MyConfig{
    @Bean
    public Tank tank() {
        return new Tank();
    }
}
View Code
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
      http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="tank" class="my.Tank"></bean>

</beans>
View Code

3、WebApplicationContext 

WebApplicationContext是专门为web应用准备的。

WebApplicationContext源码:

package org.springframework.web.context;

import javax.servlet.ServletContext;
import org.springframework.context.ApplicationContext;

public interface WebApplicationContext extends ApplicationContext {
    /**
     *  WebApplicationContext作为属性保存到了ServletContext中,Spring为此专门提供了一个工具类WebApplicationContextUtils,
     *  通过该类的getWebApplicationContext(ServletContext sc)方法,可以从ServletContext中获取WebApplicationContext的实例。
     *
     *  常量ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE是在ServletContext中保存WebApplicationContext的key
     *  可以通过以下方法获得WebApplicationContext的实例
     *  WebApplicationContext context = 
     *  (WebApplicationContext)servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
     *
     *  这也正是WebApplicationContextUtils的getWebApplicationContext(ServletContext sc)方法的内部实现方式。
     */
    String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";
    /**
     * 在非web应用的环境下,Bean只有singleton和prototype两种作用域。
     * WebApplicationContext为Bean添加了三个新的作用域:
     * 分别是request、sesseion和global sesseion。
     */
    String SCOPE_REQUEST = "request";
    String SCOPE_SESSION = "session";
    String SCOPE_GLOBAL_SESSION = "globalSession";
    String SCOPE_APPLICATION = "application";
    String SERVLET_CONTEXT_BEAN_NAME = "servletContext";
    String CONTEXT_PARAMETERS_BEAN_NAME = "contextParameters";
    String CONTEXT_ATTRIBUTES_BEAN_NAME = "contextAttributes";
    // 也可以WebApplicationContext中获取ServletContext
    ServletContext getServletContext();
}

 ConfigurableWebApplicationContext源码:

package org.springframework.web.context;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import org.springframework.context.ConfigurableApplicationContext;

public interface ConfigurableWebApplicationContext extends WebApplicationContext, ConfigurableApplicationContext {
    String APPLICATION_CONTEXT_ID_PREFIX = WebApplicationContext.class.getName() + ":";

    String SERVLET_CONFIG_BEAN_NAME = "servletConfig";

    void setServletContext(ServletContext var1);

    void setServletConfig(ServletConfig var1);

    ServletConfig getServletConfig();

    void setNamespace(String var1);

    String getNamespace();
    // 设置配置文件地址,允许通过配置文件实例化WebApplicationContext
    void setConfigLocation(String var1);

    void setConfigLocations(String... var1);

    String[] getConfigLocations();
}

XmlWebApplicationContext、AnnotationConfigWebApplicationContext这两个类都实现了上面的接口

但WebApplicationContext的初始化方式和BeanFactory、ApplicationContext不一样,因为它们必须在拥有Web容器的前提下才能启动。使用XmlWebApplicationContext或AnnotationConfigWebApplicationContext实例化WebApplicationContext需要在web.xml中定义监听器ContextLoaderListener。ContextLoaderListener通过ServletContext参数contextConfigLocation获取Spring配置文件的位置,用户可以指定多个配置文件,用逗号、空格或冒号分隔均可。 

package com.test;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.WebApplicationContext;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/run")
public class MyTest extends HttpServlet {
    private Tank tank;

    public void setTank(Tank tank) {
        this.tank = tank;
    }

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        WebApplicationContext context = (WebApplicationContext) req.getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
        MyTest myTest = context.getBean(MyTest.class);
        myTest.tank.run();
    }
}
class Tank {
    public void run() {
        System.out.println("run ...");
    }
}
@Configuration
class MyConfig {
    // 这个方法随便声明、方法参数随便写,因为这是一个新的方法,在这个方法的内部调用其它方法
    @Bean
    public MyTest myTest(Tank tank) {
        MyTest myTest = new MyTest();
        myTest.setTank(tank);
        return myTest;
    }
    @Bean
    public Tank tank() {
        return new Tank();
    }
}
View Code
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
      http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="tank" class="com.test.Tank"/>

    <bean id="myTest" class="com.test.MyTest" p:tank-ref="tank"/>

</beans>
View Code
<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
  <display-name>spring-demo</display-name>
  <!--让spring使用AnnotationConfigWebApplicationContext而非XmlWebApplicationContext启动容器
      如果想使用XmlWebApplicationContext,不需要下面这个<context-param>的配置
  -->
  <!--<context-param>-->
    <!--<param-name>contextClass</param-name>-->
    <!--<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>-->
  <!--</context-param>-->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <!--<param-value>com.test.MyConfig</param-value>-->
    <param-value>classpath:/my.xml</param-value>
  </context-param>
  <listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
</web-app>
View Code
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.test.spring</groupId>
  <artifactId>spring-demo</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>spring-demo</name>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>javax.servlet.jsp-api</artifactId>
      <version>2.2.1</version>
      <scope>provided</scope>
    </dependency>
  </dependencies>

  <build>
    <finalName>spring-demo</finalName>
    <plugins>
      <plugin>
        <groupId>org.apache.tomcat.maven</groupId>
        <artifactId>tomcat7-maven-plugin</artifactId>
        <version>2.2</version>
        <configuration>
          <path>/</path>
          <port>80</port>
          <uriEncoding>UTF-8</uriEncoding>
          <server>tomcat7</server>
        </configuration>
      </plugin>
    </plugins>
    <pluginManagement>
      <plugins>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-war-plugin</artifactId>
          <version>3.2.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>
View Code
原文地址:https://www.cnblogs.com/Mike_Chang/p/10261122.html