SPRING框架1

Spring Framework系统框架

  • Core Container:核心容器
    • Beans
    • Core
    • Context
    • SpEl
  • AOP:面向切面编程
  • Aspect:AOP思想的实现
  • DateAccess/Integration:数据访问/数据集成
    • Transactions:事务
    • OXM
    • JMS
    • JDBC
    • ORM
  • Web:Web开发
    • Web
    • Portlet
    • WebSocket
    • Servlet
  • Test:单元测试与集成测试

一、核心容器

核心概念(IoC/DI)

  IoC(Inversion of Control)控制反转:使用对象时,由主动new产生对象转换为由外部(即:IoC容器提供对象,此过程中对象创建控制权由程序转移到外部(即:IoC容器,此思想称为控制反转。

  Spring是怎么实现IoC思想的?

    提供了一个容器,称为IoC容器,用来充当IoC思想中的"外部"。

    IoC容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在IoC容器中被统称为Bean

  DI(Dependency Injection)依赖注入:在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入。

  目标:充分解耦

    •   使用IoC容器管理bean(IoC)
    •   在IoC容器内将有依赖关系的bean进行关系绑定(DI)

  最终效果:使用对象时,不仅可以从IoC容器中获取,并且获得已经绑定了所有的依赖关系。

 

容器基本操作

IoC入门案例思路分析:

  1. 管理什么?(service与Dao)
  2. 如何将被管理对象告知IoC容器?(配置文件)
  3. 被管理的对象交给IoC容器,如何获取到IoC容器?(接口)
  4. IoC容器得到后,如何从容器中获取bean?(接口方法)
  5. 使用Spring导入哪些坐标?(pom.xml)

DI入门案例思路分析:

  1. 基于IoC管理bean
  2. Service中使用new形式创建Dao对象是否保留?(不能保留)
  3. Service中需要Dao对象如何进入到Service中?(setter方法)
  4. Service与Dao间关系如何描述?(配置)
 IoC与DI实现步骤:
<!--1.导入spring的坐标spring-context,对应版本是5.2.10.RELEASE-->
 <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.20.RELEASE</version>
   </dependency>

  

<!--2.配置bean-->
    <bean id="bookDao" class="com.itcast.dao.impl.BookDaoImpl"></bean>
    <bean id="bookService" class="com.itcast.service.impl.BookServiceImpl">
        <!--7.配置Service与dao的关系-->
        <!--property标签表示配置当前bean的属性
            name属性表示配置哪一个具体的属性
            ref表示参照着哪一个bean-->
        <property name="dao" ref="bookDao"></property>
    </bean>

  

package com.itcast;

import com.itcast.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App2 {
    public static void main(String[] args) {
        //3.获取IoC容器
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //4.获取bean
        BookService bookService = (BookService) context.getBean("bookService");
        bookService.find();
    }
}

  

package com.itcast.service.impl;

import com.itcast.dao.BookDao;
import com.itcast.dao.impl.BookDaoImpl;
import com.itcast.service.BookService;

public class BookServiceImpl implements BookService {

    //5.删除业务层中使用new的方式创建的dao对象
    private BookDao dao;

    //6.提供对应的set方法
    public void setDao(BookDao dao) {
        this.dao = dao;
    }

    @Override
    public void find() {
        System.out.println("BookServiceImpl...");
        dao.find();
    }
}
bean的配置

  id:bean的id,使容器可以通过id值获取对应的bean,在一个容器中id值唯一。

  class:bean的类型,即配置bean的全路径类名。

  name:bean的别名,可以有多个别名 用 空格 逗号 分号 隔开。

  ref:引用bean

  scope:作用范围,两个值 prototype(多例) singleton (默认单例)。

 

--适合交给容器管理的bean(单例)

  • 表现层对象
  • 业务层对象
  • 数据层对象
  • 工具对象

--不适合交给容器挂历的bean(多例)

  • 封装实体的域对象

bean的实例化

--构造方法创建(常用)

  提供可访问的构造方法

public class BookDaoImpl implements BookDao {
    public BookDaoImpl() {  //默认存在的构造方法
        System.out.println("BookDao constructor is running");
    }

    @Override
    public void save() {
        System.out.println("Book Dao save...");
    }
}

  配置

<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"></bean>
--静态工厂(了解)

  静态工厂

public class OrderDaoFactory {
    public static OrderDao getOrderDao(){
        return new OrderDaoImpl();
    }
}

  配置

<!--    方式二:使用静态工厂实例化bean-->
    <bean id="orderDao" class="com.itheima.factory.OrderDaoFactory" factory-method="getOrderDao"></bean>
--实例工厂(了解)

  实例工厂

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

  配置

<!--    方式三:使用实力工厂实例化bean-->
    <bean id="userFactory" class = "com.itheima.factory.UserDaoFactory"></bean>
    <bean id="userDao" factory-bean="userFactory" factory-method="getUserDao"></bean>

  

--FactoryBean(实用)

  FactoryBean

public class UserDaoFactoryBean implements FactoryBean<UserDao> {
    //代替原始实例工厂中创建对象的方法
    @Override
    public UserDao getObject() throws Exception {
        return new UserDaoImpl();
    }

    @Override
    public Class<?> getObjectType() {
        return UserDao.class;
    }

    //控制单例非单例
    @Override
    public boolean isSingleton() {
        return false;
    }
}

  配置

<!--    方式四:使用FactoryBean实例化bean-->
    <bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean"></bean>

  

bean的生命周期控制

  提供生命周期控制的方法

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

    //表示bean初始化对应的操作
    public void init(){
        System.out.println("init...");
    }
    //表示bean销毁前的操作
    public void destory(){
        System.out.println("destory...");
    }
}

  配置生命周期的方法

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

  实现InitializingBean, DisposableBean接口

public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {
    private BookDao bookDao;

    public void setBookDao(BookDaoImpl bookDao) {
        System.out.println("set...");
        this.bookDao = bookDao;
    }

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

    @Override
    public void destroy() throws Exception {
        System.out.println("service destory...");
    }

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

bean的生命周期

  初始化容器

    创建对象(内存分配)

    执行构造方法

    执行属性注入(set操作)

    执行bean初始化方法

  使用bean

    执行业务操作

  关闭/销毁容器

    执行bean销毁方法

bean销毁时机

  容器关闭前触发bean的销毁

  关闭容器方式:

    手工关闭容器:ConfigurableApplicationContext接口close()操作

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

public class AppForLifeCycle {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        BookDao bookDao = (BookDao) context.getBean("bookDao");
        bookDao.save();

//        context.registerShutdownHook();//容器关闭钩子
        context.close();//关闭容器
    }
}

 

setter注入--引用类型

setter注入--简单类型(基本数据类型和String)

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

public class BookDaoImpl implements BookDao {
    private int conntctionNum=100;
    private String databaseName;

    public void setConntctionNum(int conntctionNum) {
        this.conntctionNum = conntctionNum;
    }

    public void setDatabaseName(String databaseName) {
        this.databaseName = databaseName;
    }

    @Override
    public void save() {
        System.out.println("book dao save..."+databaseName+","+conntctionNum);
    }
}

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

    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
        <property name="conntctionNum" value="1"></property>
        <property name="databaseName" value="mysql"></property>
    </bean>

构造器注入--引用类型(了解)

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

public class BookServiceImpl implements BookService {
    private BookDao bookDao;
    private UserDao userDao;

    public BookServiceImpl(BookDao bookDao, UserDao userDao) {
        this.bookDao = bookDao;
        this.userDao = userDao;
    }

    @Override
    public void save() {
        System.out.println("book service save...");
        bookDao.save();
        userDao.save();
    }
}

  配置中使用constuctor-arg标签ref属性注入引用类型对象

    <bean id="bookDao" class="itheima.dao.impl.BookDaoImpl"></bean>
    <bean id="userDao" class="itheima.dao.impl.UserDaoImpl"></bean>

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

 

构造器注入--简单类型(了解)

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

public class BookDaoImpl implements BookDao {
    private int conntctionNum=100;
    private String databaseName;

    public BookDaoImpl(int conntctionNum, String databaseName) {
        this.conntctionNum = conntctionNum;
        this.databaseName = databaseName;
    }

    @Override
    public void save() {
        System.out.println("book dao save..."+databaseName+","+conntctionNum);
    }
}

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

<bean id="bookDao" class="itheima.dao.impl.BookDaoImpl">
        <constructor-arg name="conntctionNum" value="12"></constructor-arg>
        <constructor-arg name="databaseName" value="mysql"></constructor-arg>
</bean>

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

<!--解决形参名称问题,与形参名不耦合-->
<bean id="bookDao" class="itheima.dao.impl.BookDaoImpl">
  <constructor-arg type="int" value="12"></constructor-arg>
  <constructor-arg type="java.lang.String" value="mysql"></constructor-arg>
</bean>

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

<!--解决参数类型重复问题,使用位置解决参数匹配-->
    <bean id="bookDao" class="itheima.dao.impl.BookDaoImpl">
        <constructor-arg index="0" value="12"></constructor-arg>
        <constructor-arg index="1" value="mysql"></constructor-arg>
    </bean>

  

依赖注入方法选择

  1. 强制依赖使用构造器进行,使用setter注入有概率不进行修护乳导致null对象出现
  2. 可选依赖使用setter注入进行,灵活性强
  3. Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨
  4. 如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选依赖的注入
  5. 实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注入
  6. 自己开发的模块推荐使用setter注入

 依赖自动装配

自动装配autoware的方式

  按类型byType(常用)

  按名称byName

  按构造方法constructor

  不启动自动装配no

依赖自动装配特征

  自动专拍用于引用类型依赖注入,不能对简单类型进行操作

  使用byType必须保证容器中相同类型的bean唯一,推荐使用

  使用byName必须保证容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用

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

 

集合注入

  数组、List、Set、Map、Properties(引用类型时,value 部分换成ref)

<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
        <property name="array">
            <array>
                <value>100</value>
                <value>1200</value>
                <value>300</value>
            </array>
        </property>
        <property name="list">
            <list>
                <value>itcast</value>
                <value>boxuegu</value>
            </list>
        </property>
        <property name="set">
            <set>
                <value>1</value>
                <value>haoya</value>
            </set>
        </property>
        <property name="map">
            <map>
                <entry key="country" value="china"></entry>
                <entry key="province" value="henan"></entry>
                <entry key="city" value="kaifeng"></entry>
            </map>
        </property>
        <property name="properties">
            <props>
                <prop key="country">china</prop>
                <prop key="province">henan</prop>
                <prop key="city">开封</prop>
            </props>
        </property>
    </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
                    http://www.springframework.org/schema/beans/spring-beans.xsd"
>

    <!--    管理DruidDataSource对象-->
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="driverClassName" value=""></property>
            <property name="url" value=""></property>
            <property name="username" value=""></property>
            <property name="password" value=""></property>
        </bean>
        <bean id="comboPooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
            <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring_db"></property>
            <property name="user" value="root"></property>
            <property name="password" value="root"></property>
        </bean>
  </beans>

加载properties文件

  开启context命名空间

<?xml version="1.0" encoding="UTF-8"?>
<!--1.开启context命名空间-->
<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"
       xsi:schemaLocation="
                    http://www.springframework.org/schema/beans
                    http://www.springframework.org/schema/beans/spring-beans.xsd
                    http://www.springframework.org/schema/context
                    http://www.springframework.org/schema/beans/spring-context.xsd"
>

  使用context命名空间,加载指定properties文件

    <!--2.使用context空间加载properties文件-->
    <context:property-placeholder location="jdbc.properties"></context:property-placeholder>

  使用${ }读取加载的属性值

 <!--3.使用属性占位符${}读取properties文件属性-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>

  不加载系统属性

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

  加载多个properties文件

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

  加载所有properties文件

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

  加载properties文件(标准格式)

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

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

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

  

容器初始化

  方式一:类路径加载配置文件

//1.加载类路径下的配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

  方式二:文件路径加载配置文件

 //2.从文件系统下加载配置文件(绝对路径)
        ApplicationContext context1 = new FileSystemXmlApplicationContext("D:\\IdeaProjects\\javase_code\\spring_10_container\\src\\main\\resources\\applicationContext.xml");

  加载多个配置文件

ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml,bean2.xml");
ApplicationContext context1 = new FileSystemXmlApplicationContext("D:\\IdeaProjects\\javase_code\\spring_10_container\\src\\main\\resources\\applicationContext.xml,a.xml");

获取bean

  方式一:使用bean名称获取

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

  方式二:使用bean名称获取并指定类型

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

  方式三:使用bean类型获取  

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

容器类层次结构图 

 

 

 BeanFactory初始化

  类路径加载配置文件,*创建完毕后所偶bean均为延迟加载*

        Resource resource = new ClassPathResource("applicationContext.xml");
        BeanFactory beanFactory = new XmlBeanFactory(resource);
        BookDao bean = beanFactory.getBean(BookDao.class);
        bean.save();

  

容器总结:  

 

 

 

 bean总结:

 

 

 依赖注入总结:

 

posted @ 2022-05-14 12:00  格兰芬多剁剁剁  阅读(43)  评论(0)    收藏  举报