Spring IoC 学习(3)

前言

前面因为总结的累了,把IoC的两个步骤,只写了一半,就仅仅把容器启动的方面说了说,对于实例化的阶段,我前面并没有说,在这节中,准备讲一讲,实例化阶段。

生命周期

基础生命周期简图

这个部分,其实实例化,一般都是用反射或者cglib,底层封装的也比较深,我随着代码debug的过程中,也没有接触到这个部分。但是在实例化bean的过程中,还是看到了挺多东西。

生命周期的图,基本上有可能是以下这种

从图中可以看到,在这个阶段,最重要的不是实例化本身,而是实例化前后会做的一些操作。实例化有些不同的,应该就是在实例化时可能会遇到绑定属性的相关操作,这个时候不是用传统的反射来做,而是用BeanWrapper来包装绑定。有个印象即可。

BeanFactory与ApplicationContext生命周期简图

BeanFactory

ApplicationContext

以上两图为借用

各种拓展接口

各色的Aware接口

当对象实例化完成并且相关属性以及依赖设置完成之后,Spring容器会检查当前对象实例是否实现了一系列的以Aware命名结尾的接口定义。如果是,则将这些Aware接口定义中规定的依赖注入给当前对象实例。

下面总结一下各种Aware接口以及作用

LoadTimeWeaverAware 加载Spring Bean时织入第三方模块,如AspectJ
BeanClassLoaderAware 加载Spring Bean的类加载器
ResourceLoaderAware 底层访问资源的加载器
BeanFactoryAware 得到BeanFactory引用
ServletConfigAware 得到ServletConfig
ServletContextAware 得到ServletContext
MessageSourceAware 国际化
ApplicationEventPublisherAware 应用事件

BeanPostProcessor

我们看一下这个接口

package org.springframework.beans.factory.config;

import org.springframework.beans.BeansException;

/**
 *
 */
public interface BeanPostProcessor {

    /**
     *  初始化之前做操作
     */

    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;

    /**
     *  初始化之后做操作
     */

    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;

}

BeanPostProcessor的应用场景

① 在注解时使用

在使用Spring构建目的时候,现在应该很多人都习惯于用注解了,因为注解简单。@Component @Controller @Service @Repository @Autowired 等注解来便捷开发,下面来探讨BeanPostProcessor在@Autowired 中的运用。

在使用@Autowired之前需要在容器中配置AutowiredAnnotationBeanPostProcessor。

② 处理Aware接口类

我们可以来看一小段ApplicationContextAwareProcessor的代码

package org.springframework.context.support;

/**
 * 可以看到是实现自BeanPostProcessor的
 */
class ApplicationContextAwareProcessor implements BeanPostProcessor {

    /**
     * 略去部分代码
     */

    /**
     * 在初始化之前做的操作
     */
    @Override
    public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
        AccessControlContext acc = null;

        if (System.getSecurityManager() != null &&
                (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
                        bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
                        bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
            acc = this.applicationContext.getBeanFactory().getAccessControlContext();
        }

        if (acc != null) {
            AccessController.doPrivileged(new PrivilegedAction<Object>() {
                @Override
                public Object run() {
                    invokeAwareInterfaces(bean);
                    return null;
                }
            }, acc);
        }
        else {
            // 直奔重点,invoke这些Aware接口
            invokeAwareInterfaces(bean);
        }

        return bean;
    }

    private void invokeAwareInterfaces(Object bean) {
        if (bean instanceof Aware) {
            if (bean instanceof EnvironmentAware) {
                ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
            }
            if (bean instanceof EmbeddedValueResolverAware) {
                ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(
                        new EmbeddedValueResolver(this.applicationContext.getBeanFactory()));
            }
            if (bean instanceof ResourceLoaderAware) {
                ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
            }
            if (bean instanceof ApplicationEventPublisherAware) {
                ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
            }
            if (bean instanceof MessageSourceAware) {
                ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
            }
            if (bean instanceof ApplicationContextAware) {
                ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
            }
        }
    }

    /**
     * 初始化之后就没有做其他操作了
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        return bean;
    }

}

自定义BeanPostProcessor

当然,每个人都可以自己写一个BeanPostProcessor的实现类。

不过写完之后注意要在Spring配置文件中配置一下。具体操作:

http://blog.csdn.net/caihaijiang/article/details/35552859

InitializingBean、init-method和@PostConstruct

这个两个东西,其实都是做一件事,就是在bean的初始化阶段做一些其他的操作。

比如,在有些情况下,某个业务对象实例化完成后,还不能处于可以使用状态。这个时候就可以让该业务对象实现该接口,并在方法afterPropertiesSet()中完成对该业务对象的后续处理。

以上这段文字是摘抄下来的,但是我真的想不到,到底为什么要这样操作,你说要改变初始化的状态,那在一开始初始化时直接改成那个状态不就可以了吗?为什么要在这里做变化?不懂。但是操作就是,在bean初始化阶段做操作。

这种操作,有三种方式来做InitializingBean、init-method和@PostConstruct。

InitializingBean

这是一个接口,只有一个方法。

public interface InitializingBean {

    void afterPropertiesSet() throws Exception;

}

如果一个bean想要在初始化阶段做操作,第一种方法就是实现这个接口

public Person implements InitializingBean {
    void afterPropertiesSet() throws Exception{
        System.out.println(" 初始化阶段操作 ")
    }
}

但是这种方式,其实还是会有点儿问题,这个对象和Spring的耦合度比较高。如果想使这个耦合度比较低,那么就用其他的两种方法了。

init-method

用一个例子,就能很好的把这个东西说清楚。

Person

class Person{
    ...
    void eat(){
        System.out.println("I am eating...");
    }
}

beans.xml

<beans>
    <bean id="person" class="Person" .
    init-method="eat">
</bean>
...
</beans>

到时候实例化Person的时候,就会调用这个eat方法了。

@PostConstruct

其实这个注解和init-method是一样的。

person

class Person{
    ...
    @PostContruct
    void eat(){
        System.out.println("I am eating...");
    }
}

DisposableBean、destroy-method和@PreDestroy

在Bean销毁之前肯定也可以做些操作,这三者的特点和用法,其实都和初始化那部分差不多。不同的地方在下面这部分代码处体现。

Person

class Person{
     ...
    @PostContruct
    void eat(){
        System.out.println("I am eating...");
    }

    @PreDestroy
    void sleep(){
        System.out.println("I will go to sleep...");
    }
}

Main

class Main{
    public static void main(String [] args){
        ApplicationContext ac=new ClasspathXmlApplicationContext("beans.xml");
        Person person = (Person) ac.getBean("person");
        // 不一样之处,销毁时要调用,不然没人知道你什么不要。

        person.sleep();
    }

beans.xml

<beans>
    <bean id="person" class="Person" >
    ...
    </bean>
</beans>

总结

这一小节和上一节应该是一个部分。本小节这要写的是BeanFactory的实例化的过程,当然在举例子的时候,还用到了ApplicationContext,但是总的来说并没有仔细的说ApplicationContext不同的高级特别,这部分内容,将会在下节做出阐述。

参考

http://blog.csdn.net/topwqp/article/details/8681497
http://blog.csdn.net/topwqp/article/details/8681497
http://www.cnblogs.com/sishang/p/6576665.html
http://blog.csdn.net/ikaraide/article/details/24180641
http://zhukunrong.iteye.com/blog/1929171
http://blog.csdn.net/shuangyue/article/details/8585736
http://997004049-qq-com.iteye.com/blog/1729793
http://www.cnblogs.com/liunanjava/p/4401089.html

时间: 2024-10-03 09:31:34

Spring IoC 学习(3)的相关文章

Spring IoC 学习(2)

前言 知道了IoC的好处和优势之后,本来应该有的一步是,搞清楚怎么用.因为前面我写的顺序是:是什么,为什么?下一个part肯定的就是怎么办或者怎么用?但是,按照Spring的官方的Guide,我觉得应该大家是可以写个Hello World.网上这类的教程也很多,加上其实我这次学习Spring是想更加深入的学习,因此,重点就不放在这个部分了.主要放在学习背后的故事. 这小节的内容就是学习IoC的容器. 两种容器 概述 整个IoC容器可以分为两个阶段,容器启动阶段和实例化阶段. 容器启动阶段 ①就是

Spring IoC 学习(1)

基本概念 IoC是什么? 如果这个问题要是面试的问题,那么我会这么回答. IoC(Inversion of Control 控制反转),当然它还有另一个名字,DI(Dependency Injection 依赖注入).这两个名称其实实质上指的都是同一样的东西.只不过看问题的角度是不一样的.IoC指的是,原来我们需要获得一个对象(Object)的时候,我们的第一想法就是用new.搭配下图,效果更好. 现在我们不用new了,是别人给我们的.既然是别人给的,那么,别人可以给,也可以不给.主动权这个时候

Spring IoC 学习(4)

前言 前面的三篇文章,主要用BeanFactory介绍了Spring中IoC容器的两个阶段:容器启动阶段和实例化阶段.接下来的这篇文章主要说的是Spring的统一资源定位策略. Spring为什么要整这个 写下这篇文章之前的绝大部分时间,我都在思考,为什么要整这个功能.任何一个功能.实现肯定有其道理.那道理是什么呢?有人是这么解释的: 要搞清楚Spring为什么提供这么一个功能,还是从Java SE提供的标准类java.net.URL说起比较好.URL全名是Uniform Resource Lo

谈谈对Spring IOC的理解

学习过Spring框架的人一定都会听过Spring的IoC(控制反转) .DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC .DI这两个概念是模糊不清的,是很难理解的,今天和大家分享网上的一些技术大牛们对Spring框架的IOC的理解以及谈谈我对Spring Ioc的理解. 一.分享Iteye的开涛对Ioc的精彩讲解 首先要分享的是Iteye的开涛这位技术牛人对Spring框架的IOC的理解,写得非常通俗易懂,以下内容全部来自原文,原文地址:http://jinniansh

spring IOC容器实现探讨

   spring IOC容器的实现,一开始我被复杂的接口和类所掩埋,看不清整体的思路和设计,踟蹰于代码丛林中,摸不清前进的方向.一开始我就决定只研读以xml文件做配置文件的XmlFactoryBean的具体实现为主要目标,渐渐地有了点感觉,用UML把spring中的bean工厂体系展现出来之后就更清晰了,让你不得不感叹设计的精巧和复杂.本文只是我个人对spring IOC实现的理解,如有错误,请不吝赐教,谢谢.     首先,需要理解的是spring容器中bean的生命周期,<spring i

利用Spring IOC技术实现用户登录验证机制_java

利用 Spring IOC 技术实现用户登录的验证机制,对用户进行登录验证. 首先利用 Spring 的自动装配模式将 User 对象注入到控制器中,然后将用户输入的用户名和密码与系统中限定的合法用户的用户名和密码进行匹配. 当用户名与密码匹配成功时,跳转到登录成功页面:当用户名与密码不匹配时,跳转到登录失败的页面. 1.创建 User 对象,定义用户名和密码属性,代码如下: package com.importnew; public class User { private String us

《Spring攻略(第2版)》——第1章 Spring简介 1.1实例化Spring IoC容器

第1章 Spring简介 在本章中,你将参加关于Spring.核心容器以及容器所提供的一些全局可用设施的一个速成班(或者一次复习),你还将了解Spring XML配置格式,以及注释驱动的支持.本章将带给你应付本书余下部分中引入的概念所需要的知识.你将学习Spring IoC容器中的基本组件配置.在Spring框架的核心部分,IoC容器的设计具有高度的适应性和可配置性,提供了使你的组件配置尽可能简单的一组工具.你能够很简单地设置运行于Spring IoC容器中的组件. 在Spring中,组件也被称

Spring IoC[控制反转]

近段时间正在学习spring.对于spring IOC发表一下自己的见解 1 spring IoC 1.1 什么是IoC 控制反转(Inversion of Control,英文缩写为IoC).主要是用来降低程序之间耦合度的一种方式. 1.2 IoC主要形式 ◇依赖查找:容器提供回调接口和上下文条件给组件.组件就必须使用容器提供的API来查找资源和协作对象,容器将调用这些回调方法,从而让应用代码获得相关资源. ◇依赖注入:组件不做定位查询,只提供普通的Java方法让容器去决定依赖关系.容器全权负

spring ioc

spring ioc是spring的核心之一,也是spring体系的基础,那么spring ioc所依赖的底层技术是什么的?反射,以前我们开发程序的时候对象之间的相互调用需要用new来实现,现在所有的bean都是通过spring容器来管理.这样做有什么好处呢?解耦!以前程序直接的调用用new直接给写死了,现在我们可以通过注入不同的接口实现类来完成对象直接的调用.   首先来聊聊Java的反射机制 1.反射机制的作用:   反编译:.class-->.java   通过反射机制访问java对象的属