Spring4.x 笔记(2):Spring 的Ioc容器

了解Ioc容器

  1. Spring 通过一个配置文件描述 Bean 与 Bean 之间的依赖关系,利用反射实例化 Bean 并且建立 Bean 之间的依赖关系。Spring Ioc 容器还提供了 Bean 实例缓存、生命周期管理、Bean 实例代理、事件发布、资源装载等服务

  2. BeanFactory(Bean 工厂)是 Spring 框架最核心的接口,提供了高级 Ioc 的配置机制;ApplicationContext(应用上下文)建立在 BeanFactory 的基础之上,提供更多的功能,如国际化、框架事件体系,更简单的创建实际应用。一般来说,称 BeanFactory 为 ico 容器,而 ApplicationContext 为应用上下文,其实本质上两者都是 Spring 的 Ioc 容器

  3. BeanFactory 是 Spring 框架的基础,面向 Spring 本身;ApplicationContext 面向使用 Spring 的开发者,建议在应用场合直接使用 ApplicationContext

BeanFactory

BeanFactory 的类体系结构

  1. BeanFactory 接口是基础接口,主要方法为 getBean(),从容器获取Bean 对象。BeanFactory 的功能通过其他接口得到扩展。
类名描述
ListableBeanFactory该接口定义了访问容器中 Bean 基本信息的若干方法,如查看 Bean 的个数(getBeanDefinitionCount),获取某一类型 Bean 的配置名称(getBeanNamesForType)
HierarchicalBeanFactory父子层级关联的容器体系,子容器可以通过接口方法访问父容器。如 Spring MVC 展现层位于子容器中,业务层和持久层位于父容器中
ConfigurableBeanFactory这个一个重要接口。增强了Ioc 容器的可定制。定义了设置类装载器、属性编辑器、容器初始化后置处理器等方法
AutowireCapableBeanFactory定义了兼容其中的 Bean 自动装配方法
SingletonBeanRegistry定义了允许在运行期向容器注册单实例 Bean 的方法
BeanDefinitionRegistryspring 配置文件中每一个 节点元素在 spring 容器里都通过一个 BeanDefinition 对象表示,它描述了Bean的配置信息。而 BeanDefinitionRegistry 接口提供向先容器手工注册 BeanDefinition 对象的方法
  1. BeanFactory 接口类图

image

初始化 BeanFactory

  1. 初始化 BeanFactory 容器:通过 DefaultListableBeanFactory 、XmlBeanDefinitionReader 实现。

  2. BeanFactory 容器初始化的时候,不会实例化 bean实例,第一次访问 Bean 才实例化

  3. 对于单例(singleton)的 Bean 来说,BeanFactory 会做缓存,所以第二次 getBean 的时候直接从容器中获取。Spring 在 DefaultSingletonBeanRegistry 类中提供了一个用于缓存单实例(singleton)的缓存器,是 Map 实现的,以 Bean 的 beanName 为键进行保存

  4. 示例

  • Bean 对象类
public interface BeanContainer {
    void done();
}
class BeanContainerImpl implements BeanContainer {
    public BeanContainerImpl() {
        System.out.println("BeanContainerImpl 被实例化了");
    }

    @Override
    public void done() {
        System.out.println("BeanContainerImpl.do() 方法被调用~~");
    }
}
  • 配置文件中,定义一个bean:
<bean name="beanContainer" class="com.learning.spring.ioc.container.BeanContainerImpl"/>
  • BeanFactory 初始化代码:
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
// 使用 ClassPathContextResource
Resource resource = resolver.getResource("spring-context.xml");

// XmlBeanFactory factory = new XmlBeanFactory(resource); 废弃,不用
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(resource);

System.out.println("BeanFactory 容器初始化完成,但是没有实例化bean");

BeanContainer beanContainer = factory.getBean("beanContainer", BeanContainer.class);
beanContainer.done();

// 对于单例(singleton)的Bean来说,会做缓存,锁着第二次 getBean 的时候直接从容器中获取
// 在 DefaultSingletonBeanRegistry 类中提供了一个用于缓存单实例(singleton)的缓存器,是Map实现的。
beanContainer = factory.getBean("beanContainer", BeanContainer.class);
beanContainer.done();

输出:
BeanFactory 容器初始化完成,但是没有实例化bean
BeanContainerImpl 被实例化了
BeanContainerImpl.do() 方法被调用~~
BeanContainerImpl.do() 方法被调用~~

ApplicationContext

ApplicationContext 类体系结构

  1. 继承了 ListableBeanFactory、HierarchicalBeanFactory接口,又扩展了 BeanFactory 功能,这些扩展的功能接口如下:
接口描述
ApplicationEventPublisher让容器拥有发布上下文事件的功能,包括容器的启动事件、关闭事件。(具体见spring 事件监听相关博文)
ResourcePatternResolver让所有的 ApplicationContext 实现了类似 PathMatchingResourcePatternResolver 的功能。通过带前缀的 Ant 风格的资源文件路径装载 spring的配置文件
MessageSource为应用提供 i18n 国际化
Lifecycle该接口提供start()、stop() 两个方法,主要用于控制异步处理过程。该接口被 ConfigurableApplicationContext 实现,会将start\stop的信息传递给容器中所有实现了该接口的Bean,以达到管理与控制JMX、任务调度等目的
  1. ApplicationContext 类继承体系
接口与类描述
ConfigurableApplicationContext该接口扩展了 ApplicationContext,新增了两个主要的方法,refresh()和close(),让ApplicationContext 具有启动、刷新、关闭应用上下文的功能。
ClassPathXmlApplicationContextXml(Sechma)配置实现的容器扩展,默认配置文件放置在类路径下,classpath: 可以省略。如果配置文件放置在文件系统中,需要显示的使用带资源类型前缀的路径,或者直接使用 FileSystemXmlApplicationContext
AnnotationConfigApplicationContextJava Config (Java-based)实现的容器扩展

image

ApplicationContext 初始化

  1. ApplicationContext 在初始化应用上下文时就实例化所有单实例(singleton)的 Bean,因此初始化的时间会比 beanFactory 长
  2. Spring 支持基于注解的配置方式,是基于 JavaConfig 实现。使用 @Configuration、 @Bean 注解实现,比 xml 文件配置更加灵活(详细的见相关博文)
基于 Xml 配置实现
  1. Bean 对象类
public interface BeanContainer {
    void done();
}
class BeanContainerImpl implements BeanContainer {
    public BeanContainerImpl() {
        System.out.println("BeanContainerImpl 被实例化了");
    }

    @Override
    public void done() {
        System.out.println("BeanContainerImpl.do() 方法被调用~~");
    }
}
  1. Xml 配置:定义一个bean
<bean name="beanContainer" class="com.learning.spring.ioc.container.BeanContainerImpl"/>
  1. 容器初始化:与 BeanFactory 的初始化输出可以做个对比
// 一般xml配置,在classpath下优先使用 ClassPathXmlApplicationContext,spring-context.xml 等同于 classpath:spring-context.xml
// 初始化的容器会实例化bean,所以一开始启动会比 BeanFactory 慢一点
ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");

System.out.println("初始化 ApplicationContext 完成,同时实例化 bean");

BeanContainer beanContainer = context.getBean("beanContainer", BeanContainer.class);
beanContainer.done();
((ClassPathXmlApplicationContext) context).close();

输出:
BeanContainerImpl 被实例化了
初始化 ApplicationContext 完成,同时实例化 bean
BeanContainerImpl.do() 方法被调用~~
基于 JavaConfig 配置实现
  1. Bean 对象类
public interface BeanContainer {
    void done();
}
class BeanContainerImpl implements BeanContainer {
    public BeanContainerImpl() {
        System.out.println("BeanContainerImpl 被实例化了");
    }

    @Override
    public void done() {
        System.out.println("BeanContainerImpl.do() 方法被调用~~");
    }
}
  1. JavaConfig 配置:使用 @Configuration( 标签)、@Bean(标签)
@Configuration
public class AnnotationConfig {

    @Bean(name = "annotationBean")
    public BeanContainer beanContainer() {
        return new BeanContainerImpl();
    }
}
  1. 容器初始化
// AnnotationConfig 配置类,相当于<beans> 标签
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AnnotationConfig.class);
System.out.println("初始化 AnnotationConfigApplicationContext 完成, 同时实例化 bean");

BeanContainer beanContainer = context.getBean("annotationBean", BeanContainer.class);
beanContainer.done();
context.close();

输出:
BeanContainerImpl 被实例化了
初始化 AnnotationConfigApplicationContext 完成
BeanContainerImpl.do() 方法被调用~~

WebApplicationContext

WebApplicationContext 类体系结构

  1. WebApplicationContext 是专门为 Web 应用准备,扩展了 ApplicationContext 的功能,实现了与 ServletContext 的相互访问
功能描述
加载配置路径默认从Web根目录下加载配置文件,可以显示使用资源文件前缀,如 classpath:XXX
增加 Bean作用域在非 web 环境,Bean 只有singleton、prototype,新增 request、session、global session、application(具体见Scope 相关博文)
支持获取 ServletContext定义了一个常量 ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE ,在上下文启动时,WebApplicationContext 实例以此键放置在 ServletContext 的属性列表中,通过 getServletContext() 方法获取 ServletContext 对象
支持在 ServletContext 中获取WebApplicationContext工具类 WebApplicationContextUtils.getWebApplicationContext() 方法可以从 servletContext 中获取 WebApplicationContext 实例,内部就是通过 getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) 方法获取的
  1. WebApplicationContext 类继承体系
类名描述
ConfigurableWebApplicationContext扩展了 WebApplicationContext,允许通过配置的方式实例化 WebApplicationContext。setServletContext 为Spring设置 Web 应用上下文;setConfigLocation 设置spring 配置文件地址,一般情况下,配置文件地址是相对于 Web 根目录的地址,如/WEB-INF/XXX。可以使用带资源类型前缀的地址,classpath:XXX 指定
XmlWebApplicationContext支持使用 Xml 配置实现
AnnotationConfigWebApplicationContext支持使用 JavaConfig 实现

image

WebApplicationContext 初始化

  1. WebApplicationContext 初始化,需要ServletContext 实例,就需要Web 容器支持。需要在 Web.xml 中配置web容器监听器(ServletContextListener)
  2. Spring 提供了用于启动 WebApplicationContext 的 Web 容器监听器:org.springframework.web.context.ContextLoaderListener
使用 ContextLoaderListener 启动 WebApplicationContext
  1. Xml 配置实现的web配置
  • 通过获取 contextConfigLocation 上下文参数,得到 spring 配置文件的位置。多个配置文件可以使用逗号、空格等分隔。不显示指定资源类型前缀,默认从Web的根路径获取
// 指定配置文件
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath*:/spring/spring-context.xml</param-value>
</context-param>

// 监听器
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
  1. 使用注解 @Configuration实现的Java类提供配置信息,web.xml 配置如下:
  • 配置 contextClass 参数,指定Spring 使用 AnnotationConfigWebApplicationContext 上下文替代 XmlWebApplicationContext
  • ContextLoaderListener 获取参数 contextClass ,如果不为空,createWebApplicationContext() 方法会创建 AnnotationConfigWebApplicationContext 上下文,并且解析 contextConfigLocation 获取的标注了@Configuration 的类
// JavaConfig 配置,配置 contextClass 参数,指定Spring 使用  AnnotationConfigWebApplicationContext 上下文
<context-param>
    <param-name>contextClass</param-name>
    <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>
// 指定配置类:配置标注了@Configuration 的类
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>cn.com.sinosoft.smp.web.sys.config.SysConfig</param-value>
</context-param>

// 监听器,会根据上面配置使用 AnnotationConfigWebApplicationContext 根据 contextConfigLocation 指定的配置类启动容器
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
使用 SpringServletContainerInitializer 启动 WebApplicationContext
  1. Servlet3.x 新增 ServletContext 的性能增强:(具体的新功能见博文 Servlet笔记系列(12):Servlet3.X版本新特性
  • 支持在运行时动态部署监听器、过滤器等
  • 使用web容器初始化接口 ServletContainerInitializer 取代web.xml配置
  • ServletContainerInitializer 使用
    • /META-INF/services/javax.servlet.ServletContainerInitializer 文件中配置实现类的全路径类名
    • 实现类需要使用 @HandlesTypes 注解来指定希望被处理的类,过滤掉不希望给 onStartup() 处理的类
  1. Spring 中 org.springframework.web.SpringServletContainerInitializer 实现了 ServletContainerInitializer接口:
  • 在 spring-web 模块中有如下配置:/META-INF/services/javax.servlet.ServletContainerInitializer,内容为org.springframework.web.SpringServletContainerInitializer
  • 并且通过 @HandlesTypes 注解指定 org.springframework.web.WebApplicationInitializer 来处理具体的业务
  1. 实现方法:
  • 实现 WebApplicationInitializer,重写 onStartup 方法,依次添加各种配置,如spring的context上下文、Spring Listener。
public class WebInitializer implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        // 注册上下文与配置,这边使用 Xml 实现或者 JavaConfig 实现都可以
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.register(MvcConfig.class);
        ctx.setServletContext(servletContext);

        // 添加 Spring Listener
        servletContext.addListener(new ContextLoaderListener(ctx));

        // 添加 CharacterEncodingFilter
        CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
        characterEncodingFilter.setEncoding("utf-8");
        FilterRegistration.Dynamic registration = servletContext.addFilter("characterEncodingFilter", characterEncodingFilter);
        registration.setAsyncSupported(isAsyncSupported());
        registration.addMappingForUrlPatterns(getDispatcherTypes(), false, "/*");

        // 配置spring mvc,这边可以配置servlet的配置
        ServletRegistration.Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
        servlet.addMapping("/");
        servlet.setLoadOnStartup(1);

    }

    private boolean isAsyncSupported() {
        return true;
    }

    private EnumSet<DispatcherType> getDispatcherTypes() {
        return isAsyncSupported() ?
                EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE, DispatcherType.ASYNC) :
                EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE);
    }
}
  • 默认 WebApplicationInitializer 有一个实现类 AbstractContextLoaderInitializer,可以实现他,重写createRootApplicationContext() 即可。
  • Spring-mvc 模块中有 AbstractDispatcherServletInitializer、AbstractAnnotationConfigDispatcherServletInitializer 类实现了WebApplicationInitializer接口,使用 springmvc 可以直接继承,比较简单
public class WebInitializer2 extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{MvcConfig.class};
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return null;
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}

父子容器

  1. 通过 HierarchicalBeanFactory 接口,Spring 容器可以实现父子层级关联的容器体系,子容器可以通过接口方法访问父容器中的 Bean,但是父容器不能访问子容器中的 Bean
  2. 在容器中 Bean 的id 必须是唯一的,但是子容器可以拥有一个和父容器id相同的 Bean
  3. 在 Spring MVC 中,展现层 Bean 位于子容器中,业务层和持久层 Bean 位于父容器中,这样展现层 Bean 可以引用业务层和持久层 Bean,反之就不可以

参考

  1. 源码地址
  2. Servlet笔记系列(12):Servlet3.X版本新特性

Fork me on Gitee

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 内容概要 《计算机试卷1》是一份综合性的计算机基础和应用测试卷,涵盖了计算机硬件、软件、操作系统、网络、多媒体技术等多个领域的知识点。试卷包括单选题和操作应用两大类,单选题部分测试学生对计算机基础知识的掌握,操作应用部分则评估学生对计算机应用软件的实际操作能力。 ### 适用人群 本试卷适用于: - 计算机专业或信息技术相关专业的学生,用于课程学习或考试复习。 - 准备计算机等级考试或职业资格认证的人士,作为实战演练材料。 - 对计算机操作有兴趣的自学者,用于提升个人计算机应用技能。 - 计算机基础教育工作者,作为教学资源或出题参考。 ### 使用场景及目标 1. **学习评估**:作为学校或教育机构对学生计算机基础知识和应用技能的评估工具。 2. **自学测试**:供个人自学者检验自己对计算机知识的掌握程度和操作熟练度。 3. **职业发展**:帮助职场人士通过实际操作练习,提升计算机应用能力,增强工作竞争力。 4. **教学资源**:教师可以用于课堂教学,作为教学内容的补充或学生的课后练习。 5. **竞赛准备**:适合准备计算机相关竞赛的学生,作为强化训练和技能检测的材料。 试卷的目标是通过系统性的题目设计,帮助学生全面复习和巩固计算机基础知识,同时通过实际操作题目,提高学生解决实际问题的能力。通过本试卷的学习与练习,学生将能够更加深入地理解计算机的工作原理,掌握常用软件的使用方法,为未来的学术或职业生涯打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值