一、Java框架之Spring配置文件开发

news2024/11/16 13:44:52

文章目录

  • 1. 基础概念
    • 1.1 Spring Framework
    • 1.2 核心概念
      • 产生背景
      • IoC、Bean、DI
  • 2. 入门案例
    • 2.1 普通Maven项目
    • 2.2 IoC入门案例
    • 2.3 DI入门案例
  • 3. bean配置
    • 3.1 bean基础配置
      • bean的基础配置
      • bean的别名配置
      • bean的作用范围
    • 3.2 bean实例化
      • 实例化方法1:构造方法
      • 实例化方法2:静态工厂
      • 实例化方法3:实例工厂
      • 实例化方法4:FactoryBean
    • 3.3 bean的生命周期
  • 4. 依赖注入
    • 4.1 四种注入场景
      • setter注入引用类型
      • setter注入简单类型
      • 构造器注入引用类型
      • 构造器注入简单类型
    • 4.2 自动装配
    • 4.3 集合注入
  • 5. IOC/DI配置管理第三方bean
    • 5.1 案例:数据源对象管理
      • druid管理
      • c3p0管理
    • 5.2 加载Properties文件
  • 6. 核心容器
    • 6.1 容器创建的方式
    • 6.2 获取Bean的方式
    • 6.3 容器类层次结构

黑马SSM教程

SSM(Spring+SpringMVC+MyBatis)框架集由Spring、MyBatis两个开源框架整合而成(SpringMVC是Spring中的部分内容),常作为数据源较简单的web项目的框架

使用配置文件开发,涉及核心容器三个部分的内容:

  • 1.容器相关;
  • 2.bean相关;
  • 3.依赖注入相关

1. 基础概念

Spring版本

  • Spring1.0是纯配置文件开发
  • Spring2.0为了简化开发引入了注解开发,此时是配置文件加注解的开发方式
  • Spring3.0已经可以进行纯注解开发,使开发效率大幅提升,我们的课程会以注解开发为主
  • Spring4.0根据JDK的版本升级对个别API进行了调整
  • Spring5.0已经全面支持JDK8,现在Spring最新的是5系列所以建议大家把JDK安装成1.8版

1.1 Spring Framework

这里所学的Spring其实是Spring家族中的Spring Framework;
Spring Framework是Spring家族中其他框架的底层基础

Spring Framewor架构图如下:

在这里插入图片描述

(1)核心层

  • Core Container:核心容器,这个模块是Spring最核心的模块,其他的都需要依赖该模块

(2)AOP层

  • AOP:面向切面编程,它依赖核心层容器,目的是在不改变原有代码的前提下对其进行功能增强
  • Aspects:AOP是思想,Aspects是对AOP思想的具体实现

(3)数据层

  • Data Access:数据访问,Spring全家桶中有对数据访问的具体实现技术
  • Data Integration:数据集成,Spring支持整合其他的数据层解决方案,比如Mybatis
  • Transactions:事务,Spring中事务管理是Spring AOP的一个具体实现,也是后期学习的重点内容

(4)Web层

  • 这一层的内容将在SpringMVC框架具体学习

(5)Test层

  • Spring主要整合了Junit来完成单元测试和集成测试

1.2 核心概念

产生背景

在这里插入图片描述

  • 存在的问题:如果在实现类中new了一个对象,那么对象的类需要改变时,就需要重新修改、发布
  • 解决方案:IoC(Inversion of Control)控制反转:使用对象时,由主动new产生对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到外部,此思想称为控制反转
private BookDao bookDao = new BookDaoImpl();
//修改为
private BookDao bookDao;//bookDao改为外部提供

IoC、Bean、DI

(1)核心概念

  • IOC(Inversion of Control)控制反转

    • 使用对象时,由主动new产生对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到外部,此思想称为控制反转
  • Spring和IoC

    • Spring技术对IoC思想进行了实现
    • Spring提供了一个容器,称为IoC容器,用来充当IOC思想中的"外部"
    • IoC容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象(包括service和dao对象)在IOC容器中统称为Bean
  • DI(Dependency Injection)依赖注入:IoC容器中存放了service和dao对象,并发现service对象依赖于dao对象运行,于是为他们建立依赖

    • 在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入

(2)这样做的目的是:充分解耦

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

(3)最终效果

  • 使用对象时不仅可以直接从IOC容器中获取,并且获取到的bean已经绑定了所有的依赖关系

2. 入门案例

  • 管理什么? (Service和Dao)
  • 如何将被管理的对象告知IoC容器?(配置文件)
  • 被管理的对象交给IoC容器,首先如何获取到IOC容器?(Spring框架提供相应的接口)

  • IoC容器得到后,如何从容器中获取bean? (接口方法)

  • 使用Spring导入哪些坐标? (pom.xml)

2.1 普通Maven项目

创建普通的Maven项目,并添加需要的类,结构如下

在这里插入图片描述

public interface BookDao {
    public void save();
}

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

public interface BookService {
    public void save();
}

public class BookServiceImpl implements BookService {
    private BookDao bookDao = new BookDaoImpl();
    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }
}

public class App {
    public static void main(String[] args) {
        BookService bookService = new BookServiceImpl();
        bookService.save();
    }
}

此时运行App.java,正常输出
在这里插入图片描述

2.2 IoC入门案例

(1)在pom.xml添加Spring的依赖jar包

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.2.10.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
</dependencies>

(2)添加Spring配置文件

resources - New - XML Configuration File - Spring Config
在这里插入图片描述

(3)获取IoC容器和Bean

public class App {
    public static void main(String[] args) {
        //3. 获取IoC容器
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");//ApplicationContext是一个接口
        //4. 获取bean - bookDao
        BookDao bookDao = (BookDao) ctx.getBean("bookDao");//填写applicationContext.xml里面的id号
        bookDao.save();
        //获取bean - serviceDao
        BookService bookService = (BookService) ctx.getBean("bookService");
        bookService.save();
    }
}

可以看到在App.java里面已经无需new对象,但此时BookServiceImpl中仍需要new一个对象,下面将通过DI对此进行改进

2.3 DI入门案例

(1)修改业务层需要new对象的部分

public class BookServiceImpl implements BookService {
    //5. 删除业务层中使用new的方式创建的dao对象
    private BookDao bookDao;
    public void save(){
        System.out.println("book service save ...");
        bookDao.save();
    }
    //6. 提供对应的set方法
    public void setBookDao(BookDao bookDao){
        this.bookDao = bookDao;
    }
}

(2)修改applicationContext.xml中的配置

在这里插入图片描述

3. bean配置

3.1 bean基础配置

bean的基础配置

在这里插入图片描述

使用方式已在上一小节演示,重点是idclass属性的使用,此外还要掌握property进行依赖注入

bean的别名配置

在这里插入图片描述

  • name属性
    可以为bean指定多个别名,使用时同id,如

    BookService bookService = (BookService) ctx.getBean("service2");
    

    在这里插入图片描述

bean的作用范围

  • 默认情况下为单例模式(singleton),即getBean(“bookDao”)获取的是同一个对象

    BookDao bookDao1 = (BookDao) ctx.getBean("bookDao");
    BookDao bookDao2 = (BookDao) ctx.getBean("bookDao");
    System.out.println(bookDao1);
    System.out.println(bookDao2);
    //输出时发现地址一致,都是:org.example.dao.impl.BookDaoImpl@25bbe1b6
    
  • 通过scope属性,可以修改为非单例模式(prototype)

    //applicationContext.xml中修改
    <bean id="bookDao" class="org.example.dao.impl.BookDaoImpl" scope="prototype"/>
    

    此后再输出,发现两次获取的bookDao不一致了
    在这里插入图片描述

    注意:使用applicationContext时默认创建了一个bookDao,如果改成prototype,再在程序中创建并调用该bean时,这个过程会执行两次BookDao的构造函数

  • bean默认为单例的原因
    为了提升性能,bean基本都是通过反射的方式创建的,反射的效率非常低
    可以更快速的获取到bean,涉及到Spring的三级缓存
    问题:会带来线程安全问题,因此Spring也提供了其他bean的作用域

3.2 bean实例化

实例化方法1:构造方法

  • 私有的构造方法不会影响bean(不安全)

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

    要点:(1)构造方法被调用了;(2)将构造方法设置为private不影响调用(因为反射)

  • bean调用的是无参构造

    private BookDaoImpl(int i){
        System.out.println("book dao constructor is running ...");
    }
    //报错:BeanCreationException
    

实例化方法2:静态工厂

步骤1:普通静态工厂创建对象使用方法

  • 创建OrderDao接口和OrderDaoImpl类

    //接口
    public interface OrderDao {
        public void save();
    }
    //实现类
    public class OrderDaoImpl implements OrderDao {
        public void save() {
            System.out.println("order dao save ...");
        }
    }
    
  • 创建一个工厂类OrderDaoFactory并提供一个静态方法

    在这里插入图片描述

    package org.example.factoiry;
    
    import org.example.dao.OrderDao;
    import org.example.dao.impl.OrderDaoImpl;
    
    public class OrderDaoFactory {
        public static OrderDao getOrderDao(){
            return new OrderDaoImpl();
        }
    }
    
  • 调用静态工厂造对象

    OrderDao orderDao = OrderDaoFactory.getOrderDao();
    orderDao.save();
    

步骤2:使用bean管理静态工厂

  • 创建bean对象

    //在applicationContext.xml中添加
    <bean id="orderDao" class="org.example.factory.OrderDaoFactory" factory-method="getOrderDao"/>
    

    factory-method指定由哪个方法返回对象

  • 获取bean对象(无变化)

    ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    OrderDao orderDao = (OrderDao) ctx.getBean("orderDao");
    orderDao.save();
    

实例化方法3:实例工厂

步骤1:普通实例工厂创建对象使用方法

  • 创建UserDao接口、UserDaoImpl实现类

    //接口
    public interface UserDao {
        public void save();
    }
    //实现类
    public class UserDaoImpl implements UserDao {
        public void save(){
            System.out.println("user dao save ...");
        }
    }
    
  • 创建实例工厂UserDaoFactory(注意非静态工厂)
    在这里插入图片描述

    public class UserDaoFactory {
        public UserDao getUserDao(){
            return new UserDaoImpl();
        }
    }
    
  • 调用实例工厂创建对象

    UserDaoFactory userDaoFactory = new UserDaoFactory();
    UserDao userDao = userDaoFactory.getUserDao();
    userDao.save();
    

步骤2:使用bean管理实例工厂

  • 创建bean对象

    //在applicationContext.xml中添加
    <bean id="userFactory" class="org.example.factory.UserDaoFactory"/>
    <bean id="userDao" factory-bean="userFactory" factory-method="getUserDao"/>
    

    要写2个bean对象,且使用 factory-bean属性

  • 获取bean对象(无变化)

    ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    UserDao userDao = (UserDao) ctx.getBean("userDao");
    userDao.save();
    

实例化方法4:FactoryBean

基于实例化方法3:实例工厂的改良

  • 创建FactoryBean类
    在这里插入图片描述

  • 创建Bean对象

    //在applicationContext.xml中添加
    <bean id="userDao" class="org.example.factory.UserDaoFactoryBean"/>
    
  • 获取bean对象(无变化)

    ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    UserDao userDao = (UserDao) ctx.getBean("userDao");
    userDao.save();
    
  • 由单例修改为非单例(scope方法也可行)

    在UserDaoFactoryBean中重写isSingleton()方法

    //设置是否为单例
    public boolean isSingleton(){
        return false;//true为单例,false为非单例
    }
    

3.3 bean的生命周期

  • 设置生命周期方法一:init-method 和 destory-method

    指定init方法和destory方法

    • BookDaoImpl

      public class BookDaoImpl implements BookDao {
          public void save(){
              System.out.println("book dao save ...");
          }
          //表示bean初始化对应的操作
          public void init(){
              System.out.println("init...");
          }
          public void destory(){
              System.out.println("destory...");
          }
      }
      
    • applicationContext.xml

      <bean id="bookDao" class="org.example.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>
      
    • 关闭容器的两种方法
      Bean的destory尚未执行,虚拟机就退出了,因此不会执行destory()方法。要想执行destory方法可以
      (1)关闭容器:ctx.close()

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

      (2)设置关闭勾子:ctx.registerShutdownHook()

      ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
      ctx.registerShutdownHook();//表示在退出前要先关闭容器,这句话位置只需要在ctx创建之后即可
      

      注意:如果scope设置为prototype,那么依然不会执行destory方法

  • 设置生命周期方法二:InitializingBean 和 DisposableBean

    public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {
        private BookDao bookDao;
        public void save(){
            System.out.println("book service save ...");
            bookDao.save();
        }
        //属性注入
        public void setBookDao(BookDao bookDao){
            this.bookDao = bookDao;
        }
        //destroy方法
        public void destroy() throws Exception{
            System.out.println("service destory");
        }
        //init方法
        public void afterPropertiesSet() throws Exception{
            System.out.println("service init");
        }
    }
    
  • Bean的生命周期小结

    • 初始化容器
      • 1.创建对象(内存分配)
      • 2.执行构造方法
      • 3.执行属性注入(set操作)
      • 4.执行bean初始化方法
    • 使用bean
      • 1.执行业务操作
    • 关闭/销毁容器
      • 1.执行bean销毁方法

4. 依赖注入

思考:

  • 向一个类中传递数据的方式有几种?
    • 普通方法(set方法)
    • 构造方法
  • 依赖注入描述了在容器中建立bean与bean之间的依赖关系的过程,如果bean运行需要的是数字或字符串呢?
    • 引用类型
    • 简单类型(基本数据类型与String)

于是依赖注入方式分为4种:

  • setter注入
    • 简单类型
    • 引用类型(前面使用的方式)
  • 构造器注入
    • 简单类型
    • 引用类型

4.1 四种注入场景

setter注入引用类型

  • 提供可访问的set方法

    public class BookServiceImpl implements BookService {
        private BookDao bookDao;
        public void setBookDao(BookDao bookDao) {
            this.bookDao = bookDao;
        }
    }
    
  • 配置中使用property标签ref属性注入引用类型对象

    <bean id="bookDao" class="org.example.dao.impl.BookDaoImpl"/>
    <bean id="bookService" class="org.example.service.impl.BookServiceImpl">
    	<property name="bookDao" ref="bookDao"/>
    </bean>
    

    多个注入只需要添加< bean>和< property>即可

setter注入简单类型

  • 提供可访问的set方法

    public class BookDaoImpl implements BookDao {
        private int connectionNum;
        private String databaseName;
        public void setConnectionNum(int connectionNum) {
            this.connectionNum = connectionNum;
        }
        public void setDatabaseName(String databaseName) {
            this.databaseName = databaseName;
        }
        public void save(){
            System.out.println("book dao save ..."+connectionNum+","+databaseName);
        }
    }
    
  • 配置中使用property标签value属性注入简单类型的值

    <bean id="bookDao" class="org.example.dao.impl.BookDaoImpl">
        <property name="databaseName" value="mysql"/>
        <property name="connectionNum" value="10"/>
    </bean>
    

构造器注入引用类型

  • 提供传参的构造器

    public class BookServiceImpl implements BookService {
        private BookDao bookDao;
    	//构造器
        public BookServiceImpl(BookDao bookDao){
            this.bookDao = bookDao;
        }
        public void save(){
            System.out.println("book service save ...");
            bookDao.save();
        }
    }
    
  • 配置中使用constructor-arg标签nameref属性注入简单类型的值

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

    name指的是形参的名称

构造器注入简单类型

  • 提供传参的构造器

    public class BookDaoImpl implements BookDao {
        private int connectionNum;
        private String databaseName;
        public BookDaoImpl(int connectionNum, String databaseName){
            this.connectionNum = connectionNum;
            this.databaseName = databaseName;
        }
        public void save(){
            System.out.println("book dao save ..."+connectionNum+","+databaseName);
        }
    }
    
  • 配置中使用constructor-arg标签nameref属性注入简单类型的值

    //标准写法:name
    <bean id="bookDao" class="org.example.dao.impl.BookDaoImpl">
        <constructor-arg name="connectionNum" value="10"/>
        <constructor-arg name="databaseName" value="mysql"/>
    </bean>
    

    上面的是标准写法,但是这里name标签需要和构造器种的形参名一样,为了降低耦合,还有另一种写法

    <!-- 解决形参名称的问题:type -->
    <bean id="bookDao" class="org.example.dao.impl.BookDaoImpl">
        <constructor-arg type="java.lang.String" value="mysql"/>
        <constructor-arg type="int" value="10"/>
    </bean>
    

    上述无法应对多个相同类型的问题,于是进一步改进

    <!-- 解决参数类型重复问题:index -->
    <bean id="bookDao" class="org.example.dao.impl.BookDaoImpl">
        <constructor-arg index="1" value="mysql"/>
        <constructor-arg index="0" value="10"/>
    </bean>
    

4.2 自动装配

  • 自动装配
    IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配(不必再写bean配置)

  • 自动装配方式

    • 按类型(常用)
    • 按名称
    • 按构造方法
    • 不启用自动装配
  • 按类型装配

    • 在实现类种写好 setter方法

    • 在配置中设置自动装配 autowire 及方式 byType

      <bean id="bookDao" class="org.example.dao.impl.BookDaoImpl"/>
      <bean id="bookService" class="org.example.service.impl.BookServiceImpl" autowire="byType"/>
      
    • 问题点:(1)要装配的类BookDaoImpl必须先写在配置种;(2)无法解决重复问题

      <bean id="bookDao1" class="org.example.dao.impl.BookDaoImpl"/>
      <bean id="bookDao2" class="org.example.dao.impl.BookDaoImpl"/>
      <bean id="bookService" class="org.example.service.impl.BookServiceImpl" autowire="byType"/>
      

      此时,autowire将不知道装配哪一个bookDao,于是报错NoUniqueBeanDefinitionException

  • 按名称装配

    • 在实现类种写好 setter方法

    • 在配置中设置自动装配 autowire 及方式 byName

      <bean id="bookDao" class="org.example.dao.impl.BookDaoImpl"/>
      <bean id="bookService" class="org.example.service.impl.BookServiceImpl" autowire="byName"/>
      

      注意,BookDaoImpl的id,即“bookDao”必须要和BookServiceImpl中的setBookDao中的后半部分相对应

  • 依赖自动装配特征

    • 自动装配用于引用类型依赖注入,不能对简单类型进行操作
    • 使用按类型装配时(byType)必须保障容器中相同类型的bean唯一,推荐使用
    • 使用按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用
    • 自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效

4.3 集合注入

  • 准备 - BookDaoImpl.java

    public class BookDaoImpl implements BookDao {
        private int[] array;
        private List<String> list;
        private Set<String> set;
        private Map<String,String> map;
        private Properties properties;
    
        public void setArray(int[] array) {this.array = array;}
        public void setList(List<String> list) {this.list = list;}
        public void setSet(Set<String> set) {this.set = set;}
        public void setMap(Map<String, String> map) {this.map = map;}
        public void setProperties(Properties properties) {this.properties = properties;}
        
        public void save() {
            System.out.println("book dao save ...");
            System.out.println("遍历数组:" + Arrays.toString(array));
            System.out.println("遍历List" + list);
            System.out.println("遍历Set" + set);
            System.out.println("遍历Map" + map);
            System.out.println("遍历Properties" + properties);
        }
    }
    
  • 配置Bean

    包括Array List Set Map Properties
    applicationContext.xml

    <bean id="bookDao" class="org.example.dao.impl.BookDaoImpl">
        <property name="array">
            <array>
                <value>100</value>
                <value>200</value>
                <value>300</value>
            </array>
        </property>
        <property name="list">
            <list>
                <value>first</value>
                <value>second</value>
                <value>third</value>
            </list>
        </property>
        <property name="set">
            <set>
                <value>first</value>
                <value>second</value>
                <value>third</value>
                <value>third</value>
            </set>
        </property>
        <property name="map">
            <map>
                <entry key="country" value="china"/>
                <entry key="province" value="henan"/>
                <entry key="city" value="kaifeng"/>
            </map>
        </property>
        <property name="properties">
            <props>
                <prop key="country">china</prop>
                <prop key="province">henan</prop>
                <prop key="city">kaifeng</prop>
            </props>
        </property>
    </bean>
    
  • 运行

    ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    BookDao bookDao = (BookDao) ctx.getBean("bookDao");
    bookDao.save();
    

5. IOC/DI配置管理第三方bean

5.1 案例:数据源对象管理

druid管理

需求:使用Spring的IOC容器来管理Druid连接池对象
1.使用第三方的技术,需要在pom.xml添加依赖
2.在配置文件中将【第三方的类】制作成一个bean,让IOC容器进行管理
3.数据库连接需要基础的四要素驱动连接用户名密码,【如何注入】到对应的bean中
4.从IOC容器中获取对应的bean对象,将其打印到控制台查看结果

  • 准备 - 添加依赖

    //pom.xml
    <dependencies>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.16</version>
        </dependency>
    </dependencies>
    
  • 配置Bean

    由于DruidDataSource是外部数据源,可以点进去查看里面的setter方法,例如setUserName()方法
    可以发现构造器不符合条件,只能使用setter注入

    <!--    管理DruidDataSource对象-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <!--        或者是com.mysql.cj.jdbc.Driver-->
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/spring_db"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>
    
  • 获取和使用bean

    ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    DataSource dataSource = (DataSource) ctx.getBean("dataSource");
    System.out.println(dataSource);//这里实际上没连接数据库,所以打印一下看下就行
    

c3p0管理

  • 准备 - 添加依赖:c3p0
    在这里插入图片描述

    <dependency>
        <groupId>c3p0</groupId>
        <artifactId>c3p0</artifactId>
        <version>0.9.1.2</version>
    </dependency>
    
  • 配置Bean

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring_db"/>
        <property name="user" value="root"/>
        <property name="password" value="root"/>
    </bean>
    
  • 获取和使用Bean

    ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    DataSource dataSource = (DataSource) ctx.getBean("dataSource");
    System.out.println(dataSource);
    

    发现报错:java.lang.ClassNotFoundException: com.mysql.jdbc.Driver

  • 添加mysql依赖

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.16</version>
    </dependency>
    

    此后再运行可以看到注入的数据

5.2 加载Properties文件

需求:将数据库连接四要素提取到properties配置文件,spring来加载配置信息并使用这些信息来完成属性注入

  • 创建jdbc.properties文件
    在resource目录下 - New - Resource Bundle
    在这里插入图片描述

    //jdbc.properties
    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://127.0.0.1:3306/spring_db
    jdbc.username=root
    jdbc.password=root
    
  • 开启一个新的命名空间context

    applicationContext.xml 在这里插入图片描述

  • 使用context空间加载properties配置文件

    applicationContext.xml

    <context:property-placeholder location="jdbc.properties"/>
    
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    	<property name="driverClassName" value="${jdbc.driver}"/>
    	<property name="url" value="${jdbc.url}"/>
    	<property name="username" value="${jdbc.username}"/>
    	<property name="password" value="${jdbc.password}"/>
    </bean>
    
  • 测试 - 将jdbc.username注入到BookDaoImpl中

    • BookDaoImpl

      public class BookDaoImpl implements BookDao {
          private String name;
          public void setName(String name) {this.name = name;}
          public void save(){System.out.println("book dao save ..."+name);}
      }
      
    • applicationContext.xml

      <bean id="bookDao" class="org.example.dao.impl.BookDaoImpl">
          <property name="name" value="${jdbc.driver}"/>
      </bean>
      
    • 运行

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

      结果

      book dao save ...com.mysql.jdbc.Driver
      
  • 系统属性优先级更高
    在jdbc.properties中写的是jdbc.username,如果将其改成username=root,运行时将发现该配置失效
    这是因为系统自身配置中也有一个username属性,且其优先级更高
    可以通过关闭系统配置来解决这个问题,在xml文件中如下修改

    <!--    设置不加载系统属性-->
    <context:property-placeholder location="jdbc.properties" system-properties-mode="NEVER"/>
    
  • 加载多个配置文件

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

    更便利的写法:

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

    标准写法:

    <!--    提供类路径,读取当前工程里面的配置文件,jar包里面的读取不到-->
    <context:property-placeholder location="classpath:*.properties"/>
    <!--    读取所有路径下的配置文件-->
    <context:property-placeholder location="classpath*:*.properties"/>
    

6. 核心容器

6.1 容器创建的方式

  • 方法1:类路径下的XML配置文件(常用)

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

    可以同时加载多个配置文件,以逗号 , 分隔即可

  • 方法2:文件系统下的XML配置文件

    ApplicationContext ctx = new FileSystemXmlApplicationContext("D:\\workspace\\spring\\spring_10_container\\src\\main\\resources\\applicationContext.xml");
    

    通过文件系统查找时,默认当前路径是项目spring所在路径,此时直接找applicationContext.xml是找不到的
    可以通过绝对路径:右击applicationContext.xml - Copy Path - Absolute Path

6.2 获取Bean的方式

  • 方法1:强制类型转换

    BookDao bookDao = (BookDao) ctx2.getBean("bookDao");
    
  • 方法2:bean名称并指定类型class

    BookDao bookDao = ctx.getBean("bookDao", BookDao.class);
    
  • 方法3:指定类型class

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

    这种方式就类似我们之前所学习依赖注入中的按类型注入。必须要确保IOC容器中该类型对应的bean对象只能有一个

6.3 容器类层次结构

在这里插入图片描述

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver {...}

顺着ListableBeanFactory往上,最终得到IoC顶层接口BeanFactory(已过时)
BeanFactory是最早期的容器接口,后来经过发展被ApplicationContext替代

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

BeanFactory和ApplicationContext的区别:前者是延迟加载,后者是立即加载
使用ApplicationContext会立即执行类的构造方法,而BeanFactory不会,如果希望ApplicationContext能够延迟加载,需要设置:

<bean id="bookDao" class="org.example.dao.impl.BookDaoImpl" lazy-init="true"/>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/160676.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Chrome浏览器http访问跨越问题与解决方法

一、Chromium 内核&#xff08;<93版本&#xff09;跨越问题解决方法 设置Chrome浏览器的 disable-web-security, 实现跨域访问后端的接口。这个参数可以降低chrome浏览器的安全性&#xff0c;禁用同源策略&#xff0c;利于开发人员本地调试。 解决办法&#xff1a; 新建一…

【区间合并】AcWing 803. 区间合并

803. 区间合并 文章目录题目描述输入格式&#xff1a;输出格式&#xff1a;数据范围输入样例输出样例方法&#xff1a;区间合并解题思路代码复杂度分析&#xff1a;题目描述 给定 nnn 个区间 [li,ri][l_i,r_i][li​,ri​]&#xff0c;要求合并所有有交集的区间。 注意如果在端…

按键精灵免字库本地识别OCR

按键精灵免字库识别—基于百度飞桨PaddleOCR的RapidOCR前言为什么为什么有大漠了还要使用其它OCR为什么要使用RapidOCR开发PaddleOCR介绍PaddleOCR使用衍生项目版——小白方案按键精灵post调用图片转base64方法转json方法post调用JVM版改为mavenOcrEngine路径idea Run配置网页版…

Hudi系列7:使用SparkSQL操作Hudi

文章目录一. SparkSQL连接Hudi1.1 Hive配置1.2 SparkSQL连接Hudi二. 创建表2.1 常规的建表2.2 CTAS三. 插入数据四. 查询数据五. 更新数据5.1 普通5.2 MergeInto六. 删除数据七. Insert Overwrite参考:一. SparkSQL连接Hudi 1.1 Hive配置 我们需要将Hive 的 metastore服务独立…

【Ubuntu18.04系统开启防火墙】

【Ubuntu18.04系统开启防火墙】1 查看防火墙状态2 开启防火墙3 关闭防火墙4 允许开启防火墙时&#xff0c;ssh连接和22端口许可4.1 允许tcp 22端口通过防火墙4.2 允许SSH服务4.3 防火墙规则重启4.4 验证端口号是否开启1 查看防火墙状态 sudo ufw status2 开启防火墙 sudo ufw…

如何重装windows10系统(超详细图文版)

目录1.&#xff08;制作装机盘&#xff09;准备好装机U盘2. (下载驱动软件&#xff09;(※这步很重要&#xff09;3.&#xff08;下载镜像&#xff09;准备好要安装的新操作系统镜像4.&#xff08;查询bios快捷键&#xff09;查询你的主板品牌&#xff0c;找到你主板品牌进入bi…

医用球囊和导管制造中的精确压力控制

摘要&#xff1a;在医用导管和球囊成型过程中对压力控制有非常严格要求&#xff0c;如高精度和宽量程的控制能力&#xff0c;需具备可编程、自动手动切换和外接压力传感器功能&#xff0c;还需具备可用于球囊泄漏、爆破和疲劳性能测试的多功能性。本文介绍了可满足这些要求的压…

连Pycharm都不知道怎么用,学什么Python?(doge))

python初始设置日常使用一、设置Python 解释器1.1 远程配置2、调整字体及其大小2.1 调整编辑器字体及其大小2.2 调整控制台的字体及其大小3、设置编码4、修改文件背景颜色5、设置Git 和Github5.1 配置git5.2 配置github5.3 下载仓库内容6 、新建.py文件时默认添加信息7、恢复代…

[ 环境搭建篇 ] 安装 java 环境并配置环境变量(附 JDK1.8 安装包)

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…

Demo演示:ARM+FPGA主流嵌入式架构板卡-HDMI显示摄像画面

各位工程师小伙伴们&#xff0c;大家好&#xff0c;ARMFPGA 作为一种主流的嵌入式系统的处理架构。相对于单纯的的ARM开发或单纯的FPGA开发&#xff0c;ARM加FPGA能够带来功耗、性能、成本等组合优势。 米尔新推出的MYD-JX8MMXA7开发板基于ARMFPGA架构&#xff0c;集成i.MX 8M…

多线程理解之3

1.怎么解决多线程并发访问临界资源的产生的问题&#xff1f; 用锁 pthread_mutex_t mtx解决。 2.mtx锁的作用具体是什么&#xff1f; 先把临界资源锁起来&#xff0c;再把它打开&#xff0c;这样一来&#xff0c;多个执行流想要同时执行临界资源就不可以了&#xff0c;只能一个…

[C++]string的使用及模拟实现

&#x1f941;作者&#xff1a; 华丞臧 &#x1f4d5;​​​​专栏&#xff1a;【C】 各位读者老爷如果觉得博主写的不错&#xff0c;请诸位多多支持(点赞收藏关注)。如果有错误的地方&#xff0c;欢迎在评论区指出。 推荐一款刷题网站 &#x1f449;LeetCode 文章目录一、stri…

Android Compose——Paging3

Paging3效果视频简述HiltRetrofit访问接口网络实例PagingSourceViewModelView效果视频 简述 本Demo采用HiltRetrofitPaging3完成&#xff0c;主要为了演示paging3分页功能的使用&#xff0c;下列为Demo所需要的相关依赖 //retrofitimplementation com.squareup.retrofit2:retr…

多线程之内功精修

文章目录一、常见的锁策略&#xff08;一&#xff09;悲观锁和乐观锁&#xff08;二&#xff09;读写锁和互斥锁&#xff08;三&#xff09;重量级锁和轻量级锁&#xff08;四&#xff09;挂起等待锁和自旋锁&#xff08;五&#xff09;公平锁和非公平锁&#xff08;六&#xf…

nerdctl容器管理工具

nerdctl容器管理工具nerdctl简介nerdctl的两个版本安装nerdctl1.配置nerdctl自动补全2.将nerdctl设别名为dockernerdctl使用方法1、运行/计入容器2、容器管理3、镜像管理4、镜像构建nerdctl简介 k8s1.22版本及以上强制安装containerd,要求卸载Docker. 虽然Docker能干的事Conta…

嗨格式数据恢复的 10 种最佳替代方法

当您意识到自己删除了错误的文件时&#xff0c;您是否有过那种恐惧和无助的感觉&#xff1f;或者&#xff0c;也许您的计算机在一项重要任务到期的前一天死机了——您所有的辛勤工作突然消失了。 嗨格式数据恢复是一款流行的数据恢复软件应用程序&#xff0c;它为找回这些文件…

《人月神话》浅读一下吧(上)

1.焦油坑 1.什么是焦油坑 焦油坑是作者用来形容大型系统开发的一个概念。史前时代&#xff0c;恐龙、猛犸象、剑齿虎这些大型食肉动物碰到焦油坑也是没有办法挣脱的&#xff0c;而且越用力就越容易被沉入坑底。 而在项目中好像没有任何一个单独的问题会导致困难&#xff0c;每个…

Spring基础(一)

Spring基础&#xff08;一&#xff09;Spring是什么下载地址IOCAop导入对象创建Spring是什么 Spring是开源的J2EE应用程序框架&#xff0c;针对bean的生命周期进行管理的轻量级容器&#xff0c;其中轻量级是指jar包数量较少。 下载地址 https://repo.spring.io/ui/native/re…

堆与优先级队列

目录 一、堆 1、简介 2、堆的模拟实现 a、向下调整堆 b、向上调整堆 c、插入元素 d、删除堆的根结点 e、获得堆顶元素 二、优先级队列 1、简介 2、常用方法 3、Top-k问题 一、堆 1、简介 堆也是一种数据结构&#xff0c;将一组数据集合按照完全二叉树的方式存储…

C++ 算法进阶系列之从 Brute Force 到 KMP 字符串匹配算法的优化之路

1. 字符串匹配算法 所谓字符串匹配算法&#xff0c;简单地说就是在一个目标字符串中查找是否存在另一个模式字符串。如在字符串 ABCDEFG 中查找是否存在 EF 字符串。 可以把字符串 ABCDEFG 称为原始&#xff08;目标&#xff09;字符串&#xff0c;EF 称为子字符串或模式字符…