当前位置: 首页 > article >正文

对Spring源码的学习:一

目录

BeanFactory开发流程

ApplicationContext

BeanFactory与ApplicationContext对比

基于XML方式的Bean的配置

自动装配


BeanFactory开发流程

这里的第三方指的是Spring提供的BeanFactory,Spring启动时会初始化BeanFactory,然后读取配置清单(xml文件)获取需要被加载的bean。实现上面流程图的具体代码如下

创建beans.xml文件

public class Test {
    public static void main(String[] args) {
        //定义出一个bean工厂
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        //读取xml文件的读取器
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
        //读取配置文件
        reader.loadBeanDefinitions("beans.xml");
        UserService userService = (UserService) beanFactory.getBean("userService");
        System.out.println(userService);
    }
}

因为我们在开发中要遵循三层架构,业务层需要定义数据层,那么接下来我们再在xml文件中指定要一个数据层bean。代码如下

public class UserServiceImpl implements UserService {
    //该方法由beanFactory来调用,set注入
    public void setUserDao(UserDao userDao){
        System.out.println("由bean工厂调用该set方法");
    }
}

需要注意的是,需要property标签中的属性的name应该是setXxx()方法中的Xxx第一个子母小写之后的字符,ref标签指的是bean定义的id。接下来我们查看Test类的运行结果

public class Test {
    public static void main(String[] args) {
        //定义出一个bean工厂
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        //读取xml文件的读取器
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
        //读取配置文件
        reader.loadBeanDefinitions("beans.xml");
        UserService userService = (UserService) beanFactory.getBean("userService");
    }
}

执行结果截图 

BeanFactory是Spring中最重要的核心类,下文中的ApplicationContext虽然叫做Spring容器,但实际上在该类中最后调用的还是BeanFactory。

ApplicationContext

ApplicationContext称为Spring容器,内部封装了BeanFactory,比BeanFactory功能更丰富,使用ApplicationContext时,xml文件配置我们习惯叫做applicationContext.xml。接下来是一个示例代码

public class ApplicationContextTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Object userService = context.getBean("userService");
    }
}

BeanFactory与ApplicationContext对比

  1. BeanFactory是Spring的早期接口,称为Spring的Bean工厂,ApplicationContext是后期更高级接口,称之为Spring 容器
  2. ApplicationContext在BeanFactory基础上对功能进行了扩展,例如: 监听功能、国际化功能等。BeanFactory的API更偏向底层,ApplicationContext的API大多数是对这些底层API的封装;
  3. Bean创建的主要逻辑和功能都被封装在BeanFactory中ApplicationContext不仅继承了BeanFactory,而且ApplicationContext内部还维护着BeanFactory的引用,所以,ApplicationContext与BeanFactory既有继承关系,又有融合关系。
  4. Bean的初始化时机不同,原始BeanFactory是在首次调用getBean时才进行Bean的创建,而ApplicationContext则是配置文件加载,容器一创建就将Bean都实例化并初始化好

基于XML方式的Bean的配置

XmI配置方式

功能描述

<bean id="class="">

Bean的id和全限定名配置

<bean name="">

通过name设置Bean的别名,通过别名也能直接获取到Bean实例

<bean scope="">

Bean的作用范围,BeanFactory作为容器时取值singleton和prototype

<bean lazy-init="">

Bean的实例化时机,是否延迟加载。BeanFactory作为容器时无效

<bean init-method="">

Bean实例化后自动执行的初始化方法,method指定方法名

<bean destroy-method="">

Bean实例销毁前的方法,method指定方法名

<bean autowire="byType">

设置自动注入模式,常用的有按照类型byType,按照名字byName

<bean factory-bean="" factory-method=""/>

指定哪个工厂Bean的哪个方法完成Bean的创建

默认情况下,单纯的Spring环境的Bean的作用范围有两个:Singleton与Prototype

  • Singleton:单例,默认值,Spring容器创建的时候,就会进行Bean的实例化,并存储到容器内部的单例池中,每次getBean时都是从单例池中获取相同的Bean实例。
  • Prototype:原型,Spring容器初始化时不会创建Bean实例,当调用getBean时才会实例化Bean,每次getBean都会创建一个新的Bean实例。

Spring实例化Bean的两种方式如下:

一:通过构造方法实例化

默认在xml文件中配置的信息都是调用了无参构造器,但是如果我们需要参数时,需要添加constructor-arg标签,该标签标识向方法中传递参数。

<beans>
  <bean id="userService" class="com.zmt.service.impl.UserServiceImpl">
    <!-- 默认采用无参构造器,但如果需要参数,则需要进行配置 -->
    <constructor-arg name="参数名称" value="参数值"></constructor-arg>
    <property name="userDao" ref="userDao"></property>
  </bean>
  <bean id="userDao" class="com.zmt.dao.impl.UserDaoImpl"></bean>
</beans>

二:通过调用自定义的工厂方法对Bean进行实例化

静态工厂方法实例化Bean

public class MyBeanFactory {
    public static UserDao getUserDao(){
        //在实例化Bean之前,我们可以进行一些业务逻辑操作
        return new UserDaoImpl();
    }
}
  <beans>
      <!--指定执行自定义的Bean工厂的指定方法去实例化Bean-->
      <bean id="userDao1" class="com.zmt.factory.MyBeanFactory" factory-method="getUserDao"></bean>

      <bean id="userService" class="com.zmt.service.impl.UserServiceImpl">
          <property name="userDao" ref="userDao"></property>
      </bean>
      <bean id="userDao" class="com.zmt.dao.impl.UserDaoImpl"></bean>
  </beans>

可以看到执行结果,一个是通过无参构造器创建出来的Bean一个是通过自定义的静态工厂创建的。

实例工厂方法实例化Bean

与静态工厂方法实例化Bean区别在于,我们需要将工厂类也加载为Bean对象,然后通过该Bean对象去实例化

public class MyBeanFactory1 {
    public UserDao getUserDao(){
        //在实例化Bean之前,我们可以进行一些业务逻辑操作
        return new UserDaoImpl();
    }
}
<beans>
  <!--加载工厂Bean-->
  <bean id="myBeanFactory1" class="com.zmt.factory.MyBeanFactory1"></bean>
  <!--通过工厂Bean去获取需要的对象-->
  <bean id="userDao2" factory-bean="myBeanFactory1" factory-method="getUserDao"></bean>
  <!--指定执行自定义的Bean工厂的指定方法去实例化Bean-->
  <bean id="userDao1" class="com.zmt.factory.MyBeanFactory" factory-method="getUserDao"></bean>

  <bean id="userService" class="com.zmt.service.impl.UserServiceImpl">
    <property name="userDao" ref="userDao"></property>
  </bean>
  <bean id="userDao" class="com.zmt.dao.impl.UserDaoImpl"></bean>
</beans>

实现FactoryBean规范延迟实例化Bean

//需要指定FactoryBean的泛型
public class MyBeanFactory2 implements FactoryBean<UserDao> {
    //该方法在执行getBean的时候去执行
    @Override
    public UserDao getObject() throws Exception {
        return new UserDaoImpl();
    }

    //获取该Bean工厂产生的Bean类型
    @Override
    public Class<?> getObjectType() {
        return UserDao.class;
    }
}
  <beans>
      <!--Bean名称是userDao3,但加载的是工厂类-->
      <bean id="userDao3" class="com.zmt.factory.MyBeanFactory2"></bean>

      <!--加载工厂Bean-->
      <bean id="myBeanFactory1" class="com.zmt.factory.MyBeanFactory1"></bean>
      <!--通过工厂Bean去获取需要的对象-->
      <bean id="userDao2" factory-bean="myBeanFactory1" factory-method="getUserDao"></bean>
      <!--指定执行自定义的Bean工厂的指定方法去实例化Bean-->
      <bean id="userDao1" class="com.zmt.factory.MyBeanFactory" factory-method="getUserDao"></bean>

      <bean id="userService" class="com.zmt.service.impl.UserServiceImpl">
          <property name="userDao" ref="userDao"></property>
      </bean>
      <bean id="userDao" class="com.zmt.dao.impl.UserDaoImpl"></bean>
  </beans>

延迟加载Bean实际上是先加载了工厂Bean类,当需要用到Bean时,会从单例池中获取FactoryBean后调用该对象中的getObject()方法获取到真正的的Bean对象,并将该Bean对象缓存在factoryBeanObjectCache中,当使用到该Bean对象时从该Map中获取。

自动装配

我们通过编写property标签进行的注入叫做手动注入,而自动装配是不需要编写property标签的,而是在bean标签中使用autowire属性来实现自动注入,aotuwire的值有两个:byName、byType

  • byName:通过属性名自动装配,去匹配setXxx与id="xxx"是否一致
  • byType:通过Bean的类型从容器中匹配,匹配出多个相同Bean类型时,报错

UserServiceImpl存在一个setUserDao方法,因此我们可以这么编写,同样可以将属性注入到UserServiceImpl中

<beans>
    <bean id="userService" class="com.zmt.service.impl.UserServiceImpl" autowire="byName"></bean>
    <bean id="userDao" class="com.zmt.dao.impl.UserDaoImpl"></bean>
</beans>

http://www.kler.cn/a/162289.html

相关文章:

  • ArcGIS Pro属性表乱码与字段名3个汉字解决方案大总结
  • 数据结构与算法-前缀和数组
  • Java设计模式面试题及参考答案
  • 【Rust练习】21.动态数组 Vector
  • 去地面算法——depth_clustering算法调试(1)
  • GEE 数据集——美国gNATSGO(网格化国家土壤调查地理数据库)完整覆盖了美国所有地区和岛屿领土的最佳可用土壤信息
  • 机房动力环境智能监控系统
  • 离高薪测试你可能只差这个理解:python 内存管理机制
  • postgresql pg_hba.conf 配置详解
  • 首次面试经历(忘指导)当我在简历上写了苍穹外卖,瑞吉外卖时……
  • Selenium自动化测试总结
  • 图像处理之把模糊的图片变清晰
  • jira创建用例,与任务关联
  • flask web开发学习之初识flask(三)
  • 从零开发短视频电商 在AWS上用SageMaker部署开源模型并用Java SDK调用
  • 录视频人不在电脑旁,怎么设置定时关机
  • Oracle Flashback示例集锦
  • Flutter 如何更新showModalBottomSheet 中的数据
  • c# 判断是否连接公网
  • ElementUI+vue+nodejs培训学校课程预约网站的设计与开发
  • ULAM公链第九十六期工作总结
  • 学习记录---kubernetes中备份和恢复etcd
  • MacOS M芯片 安装MySQL5.7教程
  • C#应用:MQTT分析——CONNECT为例子
  • 《opencv实用探索·六》简单理解图像膨胀
  • LeetCode力扣每日一题(Java):20、有效的括号