美文网首页
Spring IoC学习笔记

Spring IoC学习笔记

作者: 青年心路 | 来源:发表于2019-05-06 15:28 被阅读0次

一、Spring简介

1.Spring是什么?

    Spring是一个开源的容器框架,其中有两个重要的特性分别为

  • 控制反转(IoC)
  • 面向切面(AOP)

2.为什么使用Spring

  • 可以降低组件之间的耦合度,实现各层次间的解耦
    Controller-->Service-->Dao
  • 让代码的结构变得更好
    面向接口编程
    高低原则:高内聚,低耦合
    开闭原则:对扩展开放、对修改关闭
  • 提供了许多支持
    提供了辅助类,如:JdbcTemplate、HibernateTemplate、StringUtils、CollectionUtils、StreamUtils等
    提供了各种服务,如事务管理服务、消息服务等
    提供了单例模式
    提供了AOP技术
  • 对主流框架提供了集成支持
    集成MyBatis、Hibernate、JPA、Struts等

3.Spring体系结构

Spring体系结构图

二、核心概念

1.IoC

  • 控制反转(Inversion of Control)
public class UserServiceImpl{
    //User由Service创建并维护
    private UserDao userDao = new UserDaoImpl();
    
    public void regist(User user){
        userDao.save(user);
    }
}

是指本身不负责依赖对象的创建及维护,把依赖对象的创建和维护交给外部容器来做,这样控制权就发生了转移,控制权转移就是控制反转。

外部容器/IoC容器:存放对象(bean)的容器。

2.DI

  • 依赖注入(dependency injection)
public class UserServiceImpl{
    //User由Service创建并维护
    private UserDao userDao;
    
    //让容器将创建好的对象注入到Service中
    public void setUserDao(UserDao userDao){
        this.userDao = userDao;
    }
    
    public void regist(User user){
        userDao.save(user);
    }
}

是指在运行期,由外部容器动态的将对象注入到组件中

三、第一个Spring程序

1.添加jar包

添加spring-core、spring-beans、spring-context、spring-expresion

  <dependencies>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>5.0.8.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>5.0.8.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.0.8.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-expression</artifactId>
      <version>5.0.8.RELEASE</version>
    </dependency>

  </dependencies>

2.核心配置文件

用来进行bean的配置,文件名字自定义,一般默认为applicationContext.xml


创建Spring配置文件

2.1 在applicationContext.xml中配置bean

    <!--定义一个bean-->
    <bean id="helloSpring" class="ioc01.HelloSpring"></bean>

2.2 在类中加载配置文件并获取bean然后调用方法

public class Test {
    public static void main(String[] args) {
        //传统的调用方式
//        new HelloSpring().show();

        //使用Spring方式调用
        //1.获取IoC容器,读取配置文件初始化Spring上下文
        ApplicationContext ac = new ClassPathXmlApplicationContext("/ioc01/applicationContext.xml");
        //2.根据id从容器中获取bean
        HelloSpring helloSpring = (HelloSpring) ac.getBean("helloSpring");
        //3.调用方法
        helloSpring.show();
    }
}
运行效果图

问题:
调用方法虽然成功,但是并没有给name属性进行赋值
解决:
使用DI进行注入

<!--定义一个bean-->
<bean id="helloSpring" class="ioc01.HelloSpring">
    <property name="name" value="Tom"/>
</bean>
运行效果图
注意:
  • 使用DI时一定要为私有属性生成set方法
  • property标签中的name名一定要与生成的set方法的名字相同(首字母要小写)

四、IoC容器的类型

  • applicationContext
    ClassPathXmlApplicationContext
    FileSystemXmlApplicationContext
    使用方法:
//ApplicationContext
//类路径下加载
ApplicationContext ac = new ClassPathXmlApplicationContext("ioc03/applicationContext.xml");
//文件系统加载
ApplicationContext ac1 = new FileSystemXmlApplicationContext("D:/applicationContext.xml");
//获取bean
SpringBean springBean = (SpringBean) ac.getBean("springBean");
//输出
System.out.println(springBean);
  • BeanFactory
    使用方法:
//BeanFactory
BeanFactory bf = new XmlBeanFactory(new ClassPathResource("ioc03/applicationContext.xml"));
BeanFactory bf1 = new XmlBeanFactory(new FileSystemResource("D:/applicationContext.xml"));
SpringBean springBean1 = (SpringBean) bf.getBean("springBean");
System.out.println(springBean1);

五、数据的装配

1.什么是数据的装配

为bean中的属性注入值,被称为数据装配,可以装配不同类型的值

2.简单类型(共19种)--->使用value进行装配

八种基本数据类型及包装类
byte short int long float double char boolean
Byte Short Integer Long Float Double Character Boolean

String Class Resource

3.其他bean的引用--->使用ref进行装配

<bean id="otherBean" class="ioc05.OtherBean">
    <property name="name" value="alice"/>
</bean>

<bean id="springBean" class="ioc05.SpringBean">
    <property name="otherBean" ref="otherBean"/>
</bean>

3.1 集合类型

3.1.1 数组

<!--为数组装配-->
<property name="arrs">
    <array>
        <value>1</value>
        <value>2</value>
        <value>5</value>
    </array>
</property>

3.1.2 List

<!--为list集合装配-->
<property name="list">
 <list>
     <!--引用外部定义的bean-->
     <ref bean="otherBean"/>
     <ref bean="otherBean"/>
     <!--现场装配bean-->
     <bean class="ioc05.OtherBean">
         <property name="name" value="jack"/>
     </bean>
     <bean class="ioc05.OtherBean">
         <property name="name" value="mary"/>
     </bean>
 </list>

3.1.3 Set

<property name="set">
    <set>
        <!--引用外部定义的bean-->
        <ref bean="otherBean"/>
        <ref bean="otherBean"/>
        <!--现场装配bean-->
        <bean class="ioc05.OtherBean">
            <property name="name" value="jack"/>
        </bean>
        <bean class="ioc05.OtherBean">
            <property name="name" value="mary"/>
        </bean>
    </set>
</property>

3.1.4 Map

<property name="map">
    <map>
        <entry key-ref="otherBean" value="java.lang.String"/>
    </map>
</property>

3.1.5 properties

<property name="properties">
    <props>
        <prop key="username">zhangsan</prop>
        <prop key="password">123456</prop>
    </props>
</property>

3.1.6 null类型

<property name="name">
    <null/>
</property>

六、bean的生命周期

1.生命周期各阶段

代码块-->构造方法-->set方法-->就绪-->使用-->从容器中销毁

  • 问题:在测试类中获取bean的时候希望把name可以转换成大写。
  • 解决:在set方法中对name进行大写转换。
public void setName(String name) {
    this.name = name.toUpperCase();
}

2.初始化方法/销毁方法

2.1 初始化方法学习

  • 问题:在测试类中调用getName方法时希望得到name_sex的格式
  • 解决:需要在数据装配完成和就绪状态之间添加一个方法。所以在SpringBean类中创建方法,将当前的名字进行转换并追加性别,然后在Spring配置文件中添加init-method属性并指定方法名。
    代码块-->构造方法-->set方法-->初始化方法-->就绪-->使用-->从容器中销毁
//初始化方法
public void init(){
    this.name = this.name.toUpperCase()+"_"+this.sex.toUpperCase();
}
<bean id="springBean" class="ioc07.SpringBean" init-method="init">
    <property name="name" value="alice"/>
    <property name="sex" value="female"/>
</bean>

2.2 销毁方法的学习

代码块-->构造方法-->set方法-->就绪-->使用-->销毁方法-->从容器中销毁

ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("ioc07/applicationContext.xml");
    SpringBean springBean = (SpringBean) ac.getBean("springBean");
    System.out.println(springBean.getName());
    
    // 销毁容器
    // ac.destroy();
    
    // 代码执行完后,销毁容器
    ac.registerShutdownHook();

七、实例化bean的方式

可以通过多种方式创建对象:

  • 构造方法,无参、有参
  • 静态工厂,无参、有参(静态方法)
  • 实例工厂,无参、有参(非静态方法)

1.构造方法

<!--通过无参构造方法实例化bean-->
<bean id="springBean" class="ioc09.SpringBean">
    <property name="uname" value="tom"/>
    <property name="pwd" value="123"/>
    <property name="age" value="20"/>
</bean>

<!--调用带参的构造方法-->
<bean id="springBean2" class="ioc09.SpringBean">
    <constructor-arg name="uname" value="alice"/>
    <constructor-arg name="pwd" value="123"/>
    <constructor-arg name="age" value="18"/>
</bean>

2.静态工厂

<!--通过静态工厂实例化bean-->
<!--
    使用factory-method属性可以不调用SpringBeanFactory的构造方法,
    而是去调用SpringBeanFactory中的getSpringBean方法
-->
<!--无参-->
<bean id="springBean" class="ioc10.SpringBeanFactory" factory-method="getSpringBean">
    <property name="name" value="tom"/>
</bean>

<!--带参-->
<bean id="springBean2" class="ioc10.SpringBeanFactory" factory-method="getSpringBean">
    <constructor-arg name="name" value="alice"/>
</bean>

3.实例工厂

<!--实例工厂-->
<bean id="springBeanFactory" class="ioc12.SpringBeanFactory"></bean>

<!--无参-->
<bean id="springBean" factory-bean="springBeanFactory" factory-method="getSpringBean">
    <property name="name" value="tom"/>
</bean>

<!--带参-->
<bean id="springBean2" factory-bean="springBeanFactory" factory-method="getSpringBean">
    <constructor-arg name="name" value="alice"/>
</bean>

注意:实例化带参工厂的时候,需要使用setXxx("")的方式进行赋值

八、实例化bean的时机

1.ApplicationContext

在加载Spring配置文件时对bean初始化
优点:调用getBean方法时已经初始化完成,可以直接使用比较方便
缺点:因为没有对这个bean进行操作就对bean进行了实例化,所以造成了内存的浪费。
注意:也可以在bean标签中使用laze-init=true设置为调用方法时才初始化。

2.BeanFactory

在调用getBean方法时对bean进行初始化
优点:在调用getBean方法时才进行实例化,可以节约内存。
缺点:在调用getBean方法时才去实例化,比较费时,不方便。

九、bean的作用域

在IoC容器中同一个类默认只有一个bean,也就是单例的
问题:多线程访问时,单例模式下是不安全的。
解决1:可以在bean标签中将scope设置为prototype

<bean id="springBean" class="ioc15.SpringBean" scope="prototype">
    <property name="name" value="alice"/>
</bean>

解决2:可以将属性设置为局部变量

public String getName(String name) {
    return name;
}
  • 注意:在单例模式下,Spring配置文件加载完成就会对bean进行实例化,但是在非单例模式下,只有调用bean的时候才会进行实例化。

十、继承配置

  • 简介
    用来简化代码,减少配置

  • 用法

    • 用法1:不同的子bean类继承自父bean
<!--用法1-->
<bean id="parent" abstract="true">
    <property name="pwd" value="123"/>
</bean>

<bean id="springBean" class="ioc16.SpringBean" parent="parent">
    <property name="uname" value="admin"/>
    <property name="age" value="20"/>
</bean>

<bean id="otherBean" class="ioc16.OtherBean" parent="parent">
    <property name="uname" value="alice"/>
    <property name="sex" value="female"/>
</bean>
  • 用法2:相同的子bean类继承自父bean
<!--用法2-->
<bean id="parent2" class="ioc16.SpringBean" abstract="true">
    <property name="pwd" value="000"/>
</bean>

<bean id="bean1" parent="parent2">
    <property name="uname" value="zhangsan"/>
    <property name="age" value="20"/>
</bean>

<bean id="bean2" parent="parent2">
    <property name="uname" value="lisi"/>
    <property name="age" value="21"/>
</bean>

十一、自动装配

1.简介

IoC容器可以根据bean的名称、类型、或构造方法自动进行注入,称为自动装配。
只适用于其他bean的引用

2.配置

通过bean标签中的autowire属性进行注入,默认情况下为default

  • 1.default:不进行自动装配,和no是同样的作用
  • 2.byName:根据属性名进行自动装配(查找与属性名相同的bean)
  • 3.byType(推荐):根据属性的类型进行自动装配(查找与属性类型相同的bean)
  • 4.constructor:根据构造方法自动装配(先按byName方式进行装配,如果没有查找到对应的属性名则按照byType方式进行装配)
    注意:此时可以不要setXxx('')方法
    <!--自动注入-->
    <bean id="otherBean" class="ioc17.OtherBean">
        <property name="name" value="alice"/>
    </bean>

    <bean id="springBean" class="ioc17.SpringBean" autowire="byName">
        <!--<property name="otherBean" ref="otherBean"/>-->
    </bean>

十二、在bean中获取IoC容器

定义一个IoC容器的工具类
步骤:

  • 1.获取IoC容器
  • 2.在Spring配置文件中配置ApplicationContextHolder
  • 3.在ApplicationContextHolder中创建获取bean的方法
  • 4.在工具bean中通过ApplicationContextHolder获取bean并获取属性
  • 5.在测试类中调用工具bean

十三、FactoryBean

1.简介

Spring中有两种类型的bean

  • 普通bean,返回的是bean本身的对象。
  • 工厂bean,即FactoryBean
    应用场景:如果普通的bean的配置比较复杂,在配置文件中定义时步骤比较多,此时可以使用FactoryBean

2.定义FactoryBean

步骤:

  • 1.定义一个类,实现FactoryBean接口
  • 2.将该bean添加到IoC容器中
  • 3.获取到FactoryBean的对象
    注意:该Bean返回的并不是FactoryBean类型的对象,而是getObject方法的返回值类型的对象
  • 实现
/**
 * 该FactoryBean是用来生成PreparedStatement的
 */
public class PreparedStatementFactoryBean implements FactoryBean<PreparedStatement>{

    //生成实例的过程
    @Override
    public PreparedStatement getObject() throws Exception {
        //加载驱动
        Class.forName("com.mysql.jdbc.Driver");
        //获取连接对象
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/project", "root", "root");
        //获取发送器
        PreparedStatement ps = conn.prepareStatement("select * from t_user");
        return ps;
    }

    //生成实例的类型
    @Override
    public Class<?> getObjectType() {
        return PreparedStatement.class;
    }

    //生成的实例是否为单例
    @Override
    public boolean isSingleton() {
        return true;
    }
}

十四、Resource类

1.简介

本质就是java.io.File的封装

根据资源位置的不同,提供了不同的实现类,用来快速获取文件资源

  • FileSystemResource
  • ClassPathResource
  • UrlResource
  • InputResource

2.基本用法

ApplicationContext ac = new ClassPathXmlApplicationContext("ioc21/applicationContext.xml");
Resource resource = new FileSystemResource("D:/a.txt");
//Resource resource = new ClassPathResource("ioc21/a.txt");
System.out.println(resource.getFilename());
System.out.println(resource.contentLength());
System.out.println(resource.exists());
//获取输入流
InputStream inputStream = resource.getInputStream();
//使用工具类进行文件的复制
StreamUtils.copy(inputStream,new FileOutputStream("D:/b.txt"));

装配Resource

<bean id="springBean" class="ioc21.SpringBean">
    <property name="resource" value="ioc21/a.txt"/>
</bean>

十五、后(置)处理器

1.两种后处理器

  • Bean后处理器,实现BeanPostProcessor接口。
  • BeanFactory后处理器,实现BeanFactoryPostProcessor接口,也称之为容器后处理器。

2.BeanPostProcessor

2.1 简介

Bean后处理器用来对bean的功能进行增强和扩展,对IoC容器中的所有bean都有效。
时机: 执行初始化方法之前和之后
bean的生命周期:
代码块-->构造方法-->set方法-->初始化之前-->初始化方法-->初始化之后-->就绪-->使用-->从容器中销毁

2.2 实现步骤

  • 定义一个类,实现BeanPostProcessor接口
  • 将该后处理器添加到IoC容器中

3.BeanFactoryPostProcessor

3.1 简介

容器后处理器在bean创建之前,修改bean的定义属性
bean的生命周期:
BeanFactoryPostProcessor-->代码块-->构造方法-->set方法-->初始化之前-->初始化方法-->初始化之后-->就绪-->使用-->从容器中销毁

3.2 实现步骤

  • 定义一个类,实现BeanFactoryPostProcessor
  • 将容器后处理器添加到IoC容器中
  • 定义属性编辑器PropertyEditor(转换器),实现PropertyEditor接口或继承PropertyEditorSupport父类
  • 在容器后处理器中注册属性编辑器

相关文章

网友评论

      本文标题:Spring IoC学习笔记

      本文链接:https://www.haomeiwen.com/subject/sruunqtx.html