zoukankan      html  css  js  c++  java
  • Spring IoC容器

    一、Bean作用域

    用来声明IOC容器中的对象应该处的限定场景或者说该对象的存活空间称作Bean的作用域(Scope)。

    IOC容器在对象进入相应的scope之前,生成并装配这些对象,在该对象不再处于这些scope的限定之后,容器通常会销毁这些对象。

    默认是单例模式,@Scope("singleton")。

    • singleton:全局有且仅有一个实例
    • prototype:每次获取Bean的时候会有一个新的实例
    • request:表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效。
    • session:表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP session内有效。
    • application:将单个bean定义限定为ServletContext的生命周期。仅在支持web的Spring应用程序上下文中有效。
    • websocket:将单个bean定义限定为WebSocket的生命周期。仅在支持web的Spring应用程序上下文中有效。
    Singleton Bean 和 prototype Bean 的区别

    当一个bean被声明为单例bean(singleton)的时候,在处理多次请求的时候Spring容器中只会实例化出一个bean,且后续的请求都会共用这个对象,这个对象将被保存在一个Map集合中。当有请求来时则先从缓存中查看之前有无生成该对象,有的话直接使用这个对象,没有则实例化一个新的对象。而对于原型bean(Prototype)来说,每次请求来时都直接实例化新的bean,没有从缓存中查询获取的过程。

    单例Bean的优势
    • 减少了新生成实例的消耗。这个消耗主要体现在 ①Spring在创建实例时会造成性能的消耗。②给对象分配内存也会涉及到一些复杂的算法。
    • 可以快速的获取到bean。在单例下的bean除了第一次生成时需要创建bean外,其余时间都是从缓存(Map)中获取,所以速度快。
    • 减少jvm垃圾回收。对于所有请求只生成一个bean实例,所以垃圾回收自然就少了。
    单例Bean的劣势

    单例bean的一个很大劣势是是线程不安全的。由于所有请求都共享一个bean实例,且当这个bean有状态的时候在并发的场景下容易出现问题,相比之下原型bean则不会有这样的问题(也有例外,比如这个原型bean被单例bean所依赖),因为原型bean会给每个请求都新创建实例。

    什么是有状态Bean和无状态Bean

    有状态会话bean   :每个用户有自己特有的一个实例,在用户的生存期内,bean保持了用户的信息,即“有状态”;一旦用户灭亡(调用结束或实例结束),bean的生命期也告结束。即每个用户最初都会得到一个初始的bean。简单来说,有状态就是有数据存储功能。有状态对象(Stateful Bean),就是有实例变量的对象 ,可以保存数据,是非线程安全的。
    无状态会话bean   :bean一旦实例化就被加进会话池中,各个用户都可以共用。即使用户已经消亡,bean的生命期也不一定结束,它可能依然存在于会话池中,供其他用户调用。由于没有特定的用户,那么也就不能保持某一用户的状态,所以叫无状态bean。但无状态会话bean   并非没有状态,如果它有自己的属性(变量),那么这些变量就会受到所有调用它的用户的影响,这是在实际应用中必须注意的。简单来说,无状态就是一次操作,不能保存数据。无状态对象(Stateless Bean),就是没有实例变量的对象 .不能保存数据,是不变类,是线程安全的。

    不变模式

    不变模式只涉及到一个类。一个类的内部状态创建后,在整个生命期间都不会发生变化时,这样的类称为不变类。这种使用不变类的做法叫做不变模式。

    不变模式有两种形:一种是弱不变模式,另一种是强不变模式。

    弱不变模式

    一个类的实例的状态是不可变化的;但是这个类的子类的实例具有可能会变化的状态。这样的类符合弱不变模式的定义。要实现弱不变模式,一个类必须满足下列条件:

    • 所考虑的对象没有任何方法会修改对象的状态;当对象的构造方法将对象的状态初始化之后,对象的状态将不再改变。
    • 所有的属性都应当是私有的。不要声明任何公开的属性,以防客户端对象直接修改任何内部状态。
    • 这个对象所引用的其他对象如果是可变对象的话,必须设法限制外界对这些可变对象的访问,以防止外界修改这些对象。

    弱不变模式的缺点:

    • 一个弱不变对象的子对象是可以改变的;换言之,一个弱不变对象的子对象可能是可变的。
    • 这个可变的子对象可能可以修改父对象的状态,从而可能会允许外界修改父对象的状态。

    强不变模式

    一个类的实例的状态不会改变, 同时它的子类的实例也具有不可变化的状态。这样的类符合强不变模式,一个类必须首先满足弱不变模式所要求的所有条件,并且还要满足下面条件之一:

    • 所考虑的类所有的方法都应该是final的;这个类的子类不能够重写此类的方法;
    • 类本身是final的,那么这个类也就不可能有子类。

    不变模式在Java中的应用

    • String类
    • 其他包装类,如Integer、Float、Double、Byte、Long、Short和Character等。

    不变模式的优缺点

    优点:

    • 不能修改一个不变对象的状态,所以可以避免由此引起的不必要的程序错误,易于维护。
    • 不变对象本身是线程安全的,这样可以省掉处理同步化的开销。

    缺点:

    一旦需要修改一个对象的状态,就只好创建一个新的同类对象。在需要频繁修改不变对象的环境里,会有大量的不变对象作为中间结果被创建出来再被GC收集,这是一种资源上的浪费。

    二、Bean定制

     Spring框架提供了许多接口,可以用来定制bean。

    生命周期回调

    为了与容器对bean生命周期的管理进行交互,可以实现Spring的InitializationBean 和 DisposableBean接口。容器为前者调用afterPropertiesSet(),为后者调用destroy(),让bean在初始化和销毁bean时执行某些操作。

    JSR-250提供的@PostConstruct和@PreDestroy注解通常被认为是Spring应用程序中接收生命周期回调的最佳实践。使用这些注释意味着bean不耦合到Spring特定的接口。

    如果您不想使用JSR-250注解,但仍然希望消除耦合,请考虑init method和destroy method bean定义元数据。

    ApplicationContextAware 和 BeanNameAware

    当ApplicationContext创建实现org.springframework.context.ApplicationContextAware接口,则为实例提供对该ApplicationContext的引用。

    public interface ApplicationContextAware {
        void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
    }

    通过该种方式,bean可以通过ApplicationContext接口或通过将引用强制转换为该接口的已知子类(例如ConfigurableApplicationContext,它公开了附加功能),以编程方式操作创建它们的ApplicationContext。一个用途是对其他bean进行编程式检索。有时这种能力很有用。但是,一般来说,应该避免它,因为它将代码与Spring耦合。ApplicationContext的其他方法提供对文件资源的访问、发布应用程序事件和访问MessageSource。这些附加功能在ApplicationContext的附加功能中进行了描述。

    import org.springframework.beans.BeansException;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    import org.springframework.stereotype.Component;
    
    @Component
    public final class SpringBeanHelper implements ApplicationContextAware {
    
        private SpringBeanHelper(){}
    
        private static ApplicationContext applicationContext = null;
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            if(SpringBeanHelper.applicationContext == null){
                SpringBeanHelper.applicationContext = applicationContext;
            }
        }
    
        //通过name获取 Bean.
        public static Object getBean(String name){
            return SpringBeanHelper.applicationContext.getBean(name);
        }
    
        //通过class获取Bean.
        public static <T> T getBean(Class<T> clazz){
            return SpringBeanHelper.applicationContext.getBean(clazz);
        }
    
        //通过name,以及Clazz返回指定的Bean
        public static <T> T getBean(String name,Class<T> clazz){
            return SpringBeanHelper.applicationContext.getBean(name, clazz);
        }
    }

    当ApplicationContext创建实现org.springframework.beans.工厂.BeanNameAware接口,则向类提供对其关联对象定义中定义的名称的引用。

    public interface BeanNameAware {
        void setBeanName(String name) throws BeansException;
    }

    在填充普通bean属性之后,但在初始化回调(如initializegbean、afterPropertiesSet或自定义init方法)之前调用回调。

    ApplicationContextAware 和 BeanNameAware在执行顺序上,先执行BeanNameAware接口的setBeanName方法,再执行ApplicationContextAware接口的setApplicationContext方法。

    Aware接口列表
    • ApplicationContextAware
    • ApplicationEventPublisherAware
    • BeanClassLoaderAware
    • BeanFactoryAware
    • BeanNameAware
    • BootstrapContextAware
    • LoadTimeWeaverAware
    • MessageSourceAware
    • NotificationPublisherAware
    • ResourceLoaderAware
    • ServletConfigAware
    • ServletContextAware

    三、容器扩展点

    BeanPostProcessor 

    BeanPostProcessor接口定义回调方法,你可以实现这些方法来提供自己的(或覆盖容器的默认)实例化逻辑、依赖关系解析逻辑等。如果你想在Spring容器完成对bean的实例化、配置和初始化之后实现一些自定义逻辑,那么可以插入一个或多个自定义beanoptprocessor实现。

    public interface BeanPostProcessor {
        //bean初始化方法调用前被调用
        Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
        //bean初始化方法调用后被调用
        Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
    }

    你可以配置多个BeanPostProcessor实例,并且可以通过设置order属性来控制这些BeanPostProcessor实例的执行顺序。仅当BeanPostProcessor实现有序接口时,才能设置此属性。如果你编写自己的BeanPostProcessor,你也应该考虑实现有序接口。

    BeanPostProcessor实例的作用域为容器(ApplicationContext),只对该容器中的bean进行后期处理。

    要更改实际的bean定义,您需要使用BeanFactoryPostProcessor。

    BeanFactoryPostProcessor

    BeanFactoryPostProcessor操作bean配置元数据。

    可以配置多个BeanFactoryPostProcessor实例,并且可以通过设置order属性来控制这些BeanFactoryPostProcessor实例的运行顺序。但是,只有在BeanFactoryPostProcessor实现有序接口时才能设置此属性。如果你编写自己的BeanFactoryPostProcessor,也应该考虑实现有序接口。

    如果要更改实际的bean实例(即从配置元数据创建的对象),则需要使用BeanPostProcessor(前面在使用BeanPostProcessor定制bean中进行了描述)。而在技术上可以在BeanFactoryPostProcessor中使用bean实例(例如,使用BeanFactory.getBean()),这样做会导致过早的bean实例化,违反标准容器生命周期。这可能会产生负面的副作用,比如绕过bean的后期处理。

    ApplicationContext会自动检测部署到其中实现BeanFactoryPostProcessor接口的任何bean。它在适当的时候使用这些bean作为bean工厂的后处理程序。您可以像部署任何其他bean一样部署这些后处理器bean。

    FactoryBean

    FactoryBean接口是springioc容器实例化逻辑的一个可插拔点。如果您的复杂初始化代码可以更好地用Java表示,而不是(可能)冗长的XML,那么您可以创建自己的FactoryBean,在该类中编写复杂的初始化,然后将自定义的FactoryBean插入容器中。

    FactoryBean接口提供了三种方法:

    • Object getObject():返回此工厂创建的对象的实例。实例可以共享,这取决于这个工厂返回的是单例实例还是原型。
    • boolean isSingleton():如果此FactoryBean是singleton,则返回true,否则返回false
    • Class getObjectType():返回由getObject()方法返回的对象类型,如果类型事先未知,则返回null。

    FactoryBean的概念和接口在Spring框架中的许多地方都有使用。超过50个FactoryBean接口的实现随Spring一起提供。

    当您需要向容器请求一个实际的FactoryBean实例本身,而不是它生成的bean时,在调用ApplicationContext的getBean()方法时,在bean的id前面加上(&)。因此,对于一个id为myBean的给定FactoryBean,在容器上调用getBean(“myBean”)将返回FactoryBean的产品,而调用getBean(“&myBean”)则返回FactoryBean实例本身。

  • 相关阅读:
    Cocos2d-x win7下 android环境搭建
    cocos2dx 环境搭建 win7 +vs2012+ cocos2dx-2.1.4
    IOS 通过界面图标启动Web应用 + 全屏应用 + 添加到主屏幕
    js 魔鬼训练
    远程调试 Weinre
    PHP uniqid 高并发生成不重复唯一ID
    html5 炫酷的字幕雨
    学习建模
    jquery 购物车飞入效果
    jquery/zepto 圣诞节雪花飞扬
  • 原文地址:https://www.cnblogs.com/myitnews/p/13302006.html
Copyright © 2011-2022 走看看