今天是学习ssm框架的第一天,以后我也会继续在这个账号分享学习经历感悟和历程。

Ioc容器和DI:

核心目的:

Ioc容器和DI的目的时为了解耦,试想一下你在一个类中需要使用另一个类的一个方法,于是你通过new创建了一个这个对象(如果地球online也可以new一个对象就好了),但是在你后续的开发中,你发现这个类的功能不过完善,于是你重新new了一个对象,这是就有一个问题,如果我们每次改变这个类是不是都要重新new,重新编译,重新测试,这样的话我们的工作量将指数级增加,
那么有没有一个好的方法解决呢?这时ioc和DI就出现了

解耦的原理:

通过ioc容器管理bean;在ioc容器中将有依赖关系的bean进行绑定(DI)

基本概念:

当我们需要使用对象时,可以不用主动new产生对象转换为从外部提供对象,此过程中对象创建控制权有程序转换到了外部,此思想称为控制反转

ioc实现步骤

1.导入spring坐标

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

2.定义spring管理的类(接口)

public interface BookService {
    public void save();
}

public class BookServiceImpl implements BookService {

    private BookDao bookDao = new BookDaoImpl();
    
    public void save() {
      bookDao. save();
    }
}

3.创建spring配置文件,配置对象类作为spring的bean

<? xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                        https://www.springframework.org/schema/beans/spring-beans.xsd">

//id:为这个类去的名字,这里的id不能重复命名;class:这个类所在的位置
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl"></bean>

</beans>

4.初始化IoC容器(Spring核心容器/Spring容器),通过容器获取bean

public class App {
public static void main(String[] args) {
    //加载配置文件得到上下文对象,也就是容器对象
    ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    //获取资源
    BookService bookService = (BookService) ctx.getBean("bookService");
    bookService.save();
  }
}

通过上述4个步骤我们就完成了ioc容器的bean的保存,但在app这个类中依然有new中操作,那怎么解决这个问题呢,这就涉及到我们的DI注入了

DI注入bean

1.删除使用new形式创建对象的代码

public class BookServiceImpl implements BookService {

  private BookDao bookDao = new BookDaoImpl();

  public void save() {
    bookDao.save();
  }
  
}

2.提供依赖对象对象的setter方法

public class BookServiceImpl implements BookService {

  private BookDao bookDao;

  public void save() {
    bookDao. save();
  }

  public void setBookDao(BookDao bookDao) {
    this.bookDao = bookDao;
  }

}

3.配置service和dao的关系

<? xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns: xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi: schemaLocation="http://www.springframework.org/schema/beans
                            https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="bookService" class="com.itheima.di.service.impl.BookServiceImpl">
    //这里ref是配置文件中所写的id。name是我们为这个属性的命名
    <property name="bookDao" ref="bookDao"/>
    </bean>
    <bean id="bookDao" class="com.itheima.di.dao.impl.BookDaoImpl"/>

</beans>

bean

bean的作用范围

bean默认是单例模式,我们也可以在配置文件中的bean标签中添加scope="prototype"将bean范围改成非单例

实例化bean的三种方法

1.构造方法(常用)

提供可访问的构造方法,bean的实例化底层是提供反射创建的,所以必须要有无参构造方法

public class BookDaoImpl implements BookDao {
  public BookDaoImpl() {
      System.out.println("book constructor is running ... ");
  }
  public void save() {
      System.out.println("book dao save ... ");
  }
}

配置

#### 2.静态工厂(了解)
静态工厂
public class OrderDaoFactory {
  public static OrderDao getOrderDao(){
    return new OrderDaoImpl();
  }
}

配置

<bean
  id="orderDao"
  //factory-method是指这个类中那个方法是实例化bean方法的
  factory-method="getOrderDao"
  class="com. itheima. factory. OrderDaoFactory"
/>
3.实例工厂(了解)

实例工厂

public class UserDaoFactory {
  public UserDao getUserDao(){
    return new UserDaoImpl();
  }
}

配置

<bean id="userDaoFactory" class="com. itheima. factory. UserDaoFactory"/>
<bean>
    id="userDao"
    factory-method="getUserDao"
    factory-bean="userDaoFactory"
/>
4.FactoryBean(实用)

FactoryBean

public class UserDaoFactoryBean implements FactoryBean<UserDao> {
    public UserDao getdbject() throws Exception {
      return new UserDaoImpl();
    }
    public Class <? > getObjectType() {
      return UserDao.class;
    }
}

配置

<bean
    id="userDao"
    class="com.itheima.factory. UserDaoFactoryBean"
/>

bean生命周期

生命周期控制

1.提供生命周期控制方法

public class BookDaoImpl implements BookDao {
    public void save() {
      System.out.println("book dao save ... ");
    }

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

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

配置生命周期控制方法

<bean id="bookDao" class="com. itheima.dao. impl. BookDaoImpl" init-method="init" destroy-method="destory"/>

2.实现InitializingBean,DisposableBean接口

public class BookServiceImpl implements BookService , InitializingBean, DisposableBean {
    public void save() {
      System.out.println("book service save ... ");
    }
    public void afterPropertiesSet() throws Exception {
      System.out.println("afterPropertiesSet");
    }
    public void destroy() throws Exception {
      System.out.println("destroy");
    }
}
bean初始化过程

初始化容器

1.创建对象(内存分配)

2.执行构造方法

3.执行属性注入(set操作)

4.执行bean初始化方法

使用bean

1.执行业务操作

关闭/销毁容器

1.执行bean销毁方法

关闭容器方式

1.手动关闭容器
ConfigurableApplicationContext接口close()操作

2.注册关闭钩子,在虚拟机退出前先关闭容器再退出虚拟机
ConfigurableApplicationContext接口registerShutdownHook()操作

setter输入-基本格式

1.在bean中定义引用类型属性并提供可访问的set方法

public class BookDaoImpl implements BookDao {
    private int connectionNumber;
    public void setConnectionNumber(int connectionNumber) {
    this. connectionNumber = connectionNumber;
    }
}

2.配置中使用property标签value属性注入简单类型数据

<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
    //为类中的属性赋基本类型时使用value,赋引用类型时用ref
    <property name="connectionNumber" value="10"/>
</bean>

构造器注入

引用类型

1.在bean中定义引用类型属性并提供可访问的构造方法

public class BookServiceImpl implements BookService{

    private BookDao bookDao;
    
    public BookServiceImpl(BookDao bookDao) {
    this. bookDao = bookDao;
    }
}

2.在配置中使用constructor-arg标签ref标签属性注入引用类型对象

<bean id="bookService" class="com. itheima. service. impl. BookServiceImpl">
    <constructor-arg name="bookDao" ref="bookDao"/>
</bean>
<bean id="bookDao" class="com. itheima.dao. impl.BookDaoImpl"/>

基本类型

1.在bean中定义引用类型属性并提供可访问的set方法

public class BookDaoImpl implements BookDao {
    private int connectionNumber;

    public void setConnectionNumber(int connectionNumber) {
      this. connectionNumber = connectionNumber;
    }
}

2.配置中使用constructor-arg标签value属性注入简单类型数据

<bean id="bookDao" class="com. itheima.dao.impl. BookDaoImpl">
  <constructor-arg name="connectionNumber" value="10"/>
</bean>

配置中使用constructor-arg标签type属性设置按形参类型注入,解决形参名称变化问题

<bean id="bookDao" class="com. itheima.dao.impl.BookDaoImpl">

    <constructor-arg type="int" value="10"/>
    <constructor-arg type="java.lang.String" value="mysq1"/>
</bean>

配置中使用constructor-arg标签index属性设置按形参位置注入,解决多个相同类型形参问题

<bean id="bookDao" class="com.itheima.dao. impl.BookDaoImpl">

    <constructor-arg index="0" value="10"/>
    <constructor-arg index="1" value="mysq1"/>
</bean>

如何依赖注入选择

  1. 强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现

  2. 可选依赖使用setter注入进行,灵活性强

  3. Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨

  4. 如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选依赖的注入

  5. 实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注入

  6. 自己开发的模块推荐使用setter注入

自动装配

配置中使用bean标签autowire属性设置自动装配的类型

<bean id="bookDao" class="com.itheima.dao.impl. BookDaoImpl"/>
<bean id="bookService" class="com. itheima. service.impl. BookServiceImpl" autowire="byType"/>
  1. 自动装配用于引用类型依赖注入,不能对简单类型进行操作

  2. 使用按类型装配时(byType)必须保障容器中相同类型的bean唯一,推荐使用

  3. 使用按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用

  4. 自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效

加载properties文件

1.开启context空间

<? xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns: xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns : context="http://www.springframework.org/schema/context"
    //添加context的地方要和xmlns后面的参数名一致
    xsi: schemaLocation="
      http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/bean spring-beans.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context.xsd">
</beans>
```yaml
2.使用context命名空间,加载指定properties文件
``` 3.使用${}读取加载的属性值 ``` ``` ### **注意事项**

● 不加载系统属性

<context : property-placeholder location="jdbc.properties" system-properties-mode="NEVER"/>

● 加载多个properties文件

<context : property-placeholder location="jdbc.properties, msg.properties"/>

● 加载所有properties文件

<context : property-placeholder location=" *. properties"/>

● 加载properties文件标准格式

<context : property-placeholder location="classpath :*. properties"/>

● 从类路径或jar包中搜索并加载properties文件

<context : property-placeholder location="classpath *:*. properties"/>

创建容器

1.类路径加载配置文件

ApplicationContlext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

2.文件路径加载配置文件

ApplicationContext ctx = new FileSystemXmlApplicationContext("D:\applicationContext.xml");

3.加载多个配置文件

ApplicationContext ctx = new ClassPathXmlApplicationContext("bean1.xml","bean2.xml");

获取bean

1.使用bean名获取

BookDao bookDao = (BookDao) ctx.getBean("bookDao");

2.使用bean名称获取指定类型

BookDao bookDao = ctx.getBean("bookDao", BookDao.class);

3.使用bean类型获取

BookDao bookDao = ctx.getBean(BookDao. class);

更多推荐