IOC

Spring IoC基础

BeanFactoryApplicationContext区别

 
BeanFactory Spring 框架中 IoC 容器的顶层接口 , 它只是用来定义一些基础功能 , 定义一些基础规范 ,而ApplicationContext是它的一个子接口,所以 ApplicationContext 是具备 BeanFactory 提供的全部功能的。
 
通常,我们称 BeanFactory SpringIOC 的基础容器, ApplicationContext 是容器的高级接口,比BeanFactory要拥有更多的功能,比如说国际化支持和资源访问( xml java 配置类)等等。
 
 
启动 IoC 容器的方式

 

Java环境下启动IoC容器

  • ClassPathXmlApplicationContext:从类的根路径下加载配置文件(推荐使用)
  • FileSystemXmlApplicationContext:从磁盘路径上加载配置文件
  • AnnotationConigApplicationContext:纯注解模式下启动Spring容器
  @org.junit.Test
    public void testIoc(){

      // 通过读取classpath下的xml文件来启动容器(xml模式SE应用下推荐)
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");

        // 不推荐使用
        //ApplicationContext applicationContext1 = new FileSystemXmlApplicationContext("文件系统的绝对路径");

AccountDao accountDao = (AccountDao) applicationContext.getBean("accountDao");
    }
 
 
Web 环境下启动 IoC 容器
  从 xml 启动容器 
<!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>Archetype Created Web Application</display-name>


  <!--配置Spring ioc容器的配置文件-->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
  </context-param>
  <!--使用监听器启动Spring的IOC容器-->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
</web-app>

完全使用注解,从配置类启动容器

<!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>Archetype Created Web Application</display-name>


  <!--告诉ContextloaderListener知道我们使用注解的方式启动ioc容器-->
  <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.bigdata.edu.SpringConfig</param-value>
  </context-param>
  <!--使用监听器启动Spring的IOC容器-->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
</web-app>

Spring IOC实例化bean的三种方式:

方式一:使用无参构造函数
在默认情况下,它会通过反射调用无参构造函数来创建对象。如果类中没有无参构造函数,将创建失败。
  <!--配置service对象-->

<beanid="userService"class="com.bigdata.service.impl.TransferServiceImpl"></bean>

方式二和方式三是为了我们自己new的对象加入到SpringIOC容器管理中

方式二:使用静态方法创建
在实际开发中,我们使用的对象有些时候并不是直接通过构造函数就可以创建出来的,它可能在创建的过程中会做很多额外的操作。此时会提供一个创建对象的方法,恰好这个方法是static修饰的方法,即是此种情况。例如,我们在做Jdbc操作时,会用到java.sql.Connection接口的实现类,如果是mysql数据库,那么用的就是JDBC4Connection,但是我们不会去写JDBC4Connection connection = new JDBC4Connection() ,因为我们要注册驱动,还要提供URL和凭证信息,用 DriverManager.getConnection方 法来获取连接。
那么在实际开发中,尤其早期的项目没有使用 Spring 框架来管理对象的创建,但是在设计时使用了工厂模式解耦,那么当接入spring 之后,工厂类创建对象就具有和上述例子相同特征,即可采用此种方式配置。
 
<bean id="connectionUtils" class="com.bigdata.edu.factory.CreateBeanFactory" factory-method="getInstanceStatic"/>
方式三:使用实例化方法创建
此种方式和上面静态方法创建其实类似,区别是在于获取对象的方法不再是 static 修饰的了,而是类中的一个普通方法。此种方式比静态方法创建的使用概率要高一些。在早期开发的项目中,工厂类中的方法有可能是静态的,也有可能是非静态方法,当是非静态方法时,即可采用下面的配置方式:
 
<bean id="createBeanFactory" class="com.bigdata.edu.factory.CreateBeanFactory"></bean>
    <bean id="connectionUtils" factory-bean="createBeanFactory" factory-method="getInstance"/>
public class CreateBeanFactory {

    public static ConnectionUtils getInstanceStatic() {
        return new ConnectionUtils();
    }


    public ConnectionUtils getInstance() {
        return new ConnectionUtils();
    }
}

Bean的作用范围及生命周期

作用范围的改变
spring 框架管理 Bean 对象的创建时, Bean 对象默认都是单例的,但是它支持配置的方式改变作用范围。
作用范围官方提供的说明如下图:

singleton:单例,IOC容器中只有一个该类对象,默认为singleton
prototype:原型(多例),每次使用该类的对象(getBean),都返回给你一个新的对象,Spring只创建对象,不管理对象

 

不同作用范围的生命周期

单例模式:singleton

对象出生:当创建容器时,对象就被创建了。

对象活着:只要容器在,对象一直活着。

对象死亡:当销毁容器时,对象就被销毁了。

一句话总结:单例模式的bean对象生命周期与容器相同。

多例模式:prototype

对象出生:当使用对象时,创建新的对象实例。

对象活着:只要对象在使用中,就一直活着。

对象死亡:当对象长时间不用时,被java的垃圾回收器回收了。

一句话总结:多例模式的bean对象,spring框架只负责创建,不负责销毁。

Spring IOC高级特性

1、lazy-Init 延迟加载

Bean 的延迟加载(延迟创建)
ApplicationContext 容器的默认是为是在启动服务器时将所有 singleton bean 提前进行实例化。提前实例化意味着作为初始化过程的一部分,ApplicationContext 实例会创建并配置所有的 singletonbean。比如:
 
<beanid="testBean"class="cn.lagou.LazyBean"/>
//该bean默认的设置为:
<beanid="testBean"calss="cn.lagou.LazyBean"lazy-init="false"/>
lazy-init="false" ,立即加载,表示在 spring 启动时,立刻进行实例化。如果不想让某个singleton bean ApplicationContext 实现初始化时被提前实例化,那么可以将 bean设置为延迟实例化。
 
设置 lazy-init true bean 将不会在 ApplicationContext 启动时提前被实例化,而是第一次向容器通过 getBean 索取 bean 时实例化的。如果一个设置了立即加载的 bean1 ,引用了一个延迟加载的 bean2 ,那么 bean1 在容器启动时被实例化,而 bean2 由于被 bean1 引用,所以也被实例化,这种情况也符合延时加载的 bean 在第一次调用时才被实例化的规则。
 
如果一个 bean scope 属性为 scope="pototype" 时,即使设置了 lazy-init="false" ,容器启动时也不会实例化bean ,而是调用  getBean 方 法实例化的。
 
应用场景
1 )开启延迟加载一定程度提高容器启动和运转性能
2 )对于不常使用的 Bean 设置延迟加载,这样偶尔使用的时候再加载,不必要从一开始该 Bean 就占用资源
 
 

2、FactoryBean BeanFactory

BeanFactory接口是容器的顶级接口,定义了容器的一些基础行为,负责生产和管理Bean的一个工厂,具体使用它下面的子接口类型,比如ApplicationContext;此处我们重点分析FactoryBean

Spring中Bean有两种,一种是普通Bean,一种是工厂BeanFactoryBean),FactoryBean可以生成某一个类型的Bean实例(返回给我们),也就是说我们可以借助于它自定义Bean的创建过程。Bean创建的三种方式中的静态方法和实例化方法和FactoryBean作用类似,FactoryBean使用较多,尤其在Spring框架一些组件中会使用,还有其他框架和Spring框架整合时使用。

3 、后置处理器

Spring提供了两种后处理bean的扩展接口,分别为 BeanFactoryPostProcessor和BeanPostProcessor ,两者在使用上是有所区别的。

工厂初始化(BeanFactory—> Bean对象

在BeanFactory初始化之后可以使用BeanFactoryPostProcessor进行后置处理做一些事情

Bean对象实例化(并不是Bean的整个生命周期完成)之后可以使用BeanPostProcessor进行后置处理做一些事情

BeanDefinition对象:

 

BeanFactoryPostProcessor

是BeanFactory级别的处理,是针对整个Bean的工厂进行处理,典型应用:PropertyPlaceholderConigurer

此接口只提供了一个方法,方法参数为ConigurableListableBeanFactory,该参数类型定义了一些方法

其中有个方法名为 getBeanDefi nition 的方法,我们可以根据此方法,找到我们定义 bean 的BeanDefi nition 对象。然后我们可以对定义的属性进行修改,以下是 BeanDefi nition 中的方法
 
 
 
方法名字类似我们 bean 标签的属性, setBeanClassName 对应 bean 标签中的 class 属性,所以当我们拿到BeanDefi nition 对象时,我们可以手动修改 bean 标签中所定义的属性值。(修改一些占位符)
BeanDefinition 对象: 我们在 XML 中定义的 bean 标签, Spring 解析 bean 标签成为一个 JavaBean ,这个JavaBean 就是 BeanDefi nition
注意:调? BeanFactoryPostProcessor ?法时,这时候 bean 还没有实例化,此时 bean 刚被解析成
BeanDefi nition 对象
 
当工厂实例化之后就可以生产bean了,接下来说一下bean的生命周期。
 
 

SpringBean的生命周期

 * spring启动时,spring读取加载xml配置文件中bean的信息,解析成一个一个BeanDefinition对象
 * springBean 的生命周期
 * 1.通过new或反射方式实例化bean
 * 2.依赖依赖注入返程所有属性的赋值
 * 3.如果bean实现了BeanNameAware接口,则bean调用setBeanName方法,则可以拿到注册我成为bean时定义的id
 * 4.如果bean实现了BeanFactoryAware接口,则bean调用setBeanFactory方法,可以拿到bean的外部环境工厂实例对象
 * 5.实现ApplicationContextAware接口,bean调用setApplicationContext,可以拿到高级容器接口
 * 6.BeanPostProcessor是bean级别的处理,可以拦截到所有bean,调用预处理化postProcessBeforeInitialization方法可以,可以对bean进行预加工
 *  before方法在自定义iniMethod之前
 * 7.

 

 

 

package com.bigdata.edu.pojo;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

/**
 * spring启动时,spring读取加载xml配置文件中bean的信息,解析成一个一个BeanDefinition对象
 * springBean 的生命周期
 * 1.通过new或反射方式实例化bean,读取配置文件时已经把<bean>解析成一个一个BeanDefinition对象了
 * 2.依赖依赖注入返程所有属性的赋值
 * 3.如果bean实现了BeanNameAware接口,则bean调用setBeanName方法,则可以拿到注册我成为bean时定义的id
 * 4.如果bean实现了BeanFactoryAware接口,则bean调用setBeanFactory方法,可以拿到bean的外部环境工厂实例对象
 * 5.实现ApplicationContextAware接口,bean调用setApplicationContext,可以拿到高级容器接口
 * 6.BeanPostProcessor是bean级别的处理,可以拦截到所有bean,调用预处理化postProcessBeforeInitialization方法可以,可以对bean进行预加工
 *  before方法在自定义iniMethod之前
 * 7.
 */
public class Result implements BeanNameAware , BeanFactoryAware , ApplicationContextAware , InitializingBean , DisposableBean {

    private String status;
    private String message;

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    @Override
    public String toString() {
        return "Result{" +
                "status='" + status + '\'' +
                ", message='" + message + '\'' +
                '}';
    }

    public Result() {
        System.out.println("1,result 无参构造");
    }

    @Override
    public void setBeanName(String s) {
        System.out.println("3,setBeanName,bean的id:"+s);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("4,setBeanFactory,管理我的beanfactory为"+beanFactory);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("5,高级接口applicationContext:"+applicationContext);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("7,afterPropertiesSet");
    }

    public void initMethod(){
        System.out.println("8,我是bean的initMethod方法");
    }
//  和ini-method 等值可以互换,但还是 有顺序的,优先于7afterPropertiesSet方法执行
    @PostConstruct
    public void  postConstruct(){
        System.out.println("postConstruct..");
    }

    // 注解方式
    @PreDestroy
    public void mydestroy(){
        System.out.println("PreDestroy..");
    }

    // 销毁方法
    @Override
    public void destroy() throws Exception {
        System.out.println("destroy");
    }

    public void destroyMethod(){
        System.out.println("destroyMethod");
    }

    /** 1,
     * 3,setBeanName,bean的id:result
     * 4,setBeanFactory,管理我的beanfactory为org.springframework.beans.factory.support.DefaultListableBeanFactory@76012793: defining beans [accountDao,proxyFactory,transferService,connectionUtils,transactionManager,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,druidDataSource,result,myBeanPostProcessor]; root of factory hierarchy
     * 5,高级接口applicationContext:org.springframework.context.support.ClassPathXmlApplicationContext@2d2e5f00: startup date [Tue Mar 03 15:53:56 CST 2020]; root of context hierarchy
     * 6,postProcessBeforeInitialization
     * postConstruct..
     * 7,afterPropertiesSet
     * 8,我是bean的initMethod方法
     * 9,postProcessAfterInitialization
     * result:Result{status='200', message='成功'}
     * PreDestroy..
     * destroy
     * destroyMethod
     *
     *
     */
}

 

BeanPostProcessor 是针对 Bean 级别的处理,可以针对某个具体的 Bean.该接口提供了两个方法,分别在Bean 的初始化方法前和初始化方法后执行,具体这个初始化方法指的是什么方法,类似我们在定义bean 时,定义了 init-method 所指定的方法,
定义一个类实现了 BeanPostProcessor ,默认是会对整个 Spring 容器中所有的 bean 进行处理。如果要对具体的某个bean处理,可以通过方法参数判断,两个类型参数分别为Object String ,第一个参数是每个bean 的实例,第二个参数是每个 bean name 或者 id 属性的值。所以我们可以通过第二个参数,来判断我们将要处理的具体的bean
注意:处理是发生在 Spring 容器的实例化和依赖注入之后。
package com.bigdata.edu.pojo;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {

        if ("result".equalsIgnoreCase(beanName)){
            System.out.println("6,postProcessBeforeInitialization");
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if ("result".equalsIgnoreCase(beanName)){
            System.out.println("9,postProcessAfterInitialization");
        }
        return bean;
    }
}

 

@org.junit.Test
    public void testIoc(){

        ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
       // AccountDao accountDao = (AccountDao) classPathXmlApplicationContext.getBean("accountDao");
        Result result = (Result) classPathXmlApplicationContext.getBean("result");
        System.out.println("result:"+result);
        classPathXmlApplicationContext.close();
    }

输出结果:

/**    1,result 无参构造
     * 3,setBeanName,bean的id:result
     * 4,setBeanFactory,管理我的beanfactory为org.springframework.beans.factory.support.DefaultListableBeanFactory@76012793: defining beans [accountDao,proxyFactory,transferService,connectionUtils,transactionManager,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,druidDataSource,result,myBeanPostProcessor]; root of factory hierarchy
     * 5,高级接口applicationContext:org.springframework.context.support.ClassPathXmlApplicationContext@2d2e5f00: startup date [Tue Mar 03 15:53:56 CST 2020]; root of context hierarchy
     * 6,postProcessBeforeInitialization
     * postConstruct..
     * 7,afterPropertiesSet
     * 8,我是bean的initMethod方法
     * 9,postProcessAfterInitialization
     * result:Result{status='200', message='成功'}
     * PreDestroy..
     * destroy
     * destroyMethod
     *
     *
     */

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值