Spring(一、xml配置)(看的b站上黑马程序员的课,用的黑马的代码)

前言

1.spring大家族有很多,我们现在学的是spring-framework,因为比较基础

2.spring发展史

        Spring1.0:采用纯配置开发

        Spring2.0:加入了注解的形式

        Spring3.0:注解配置的开发模式,大幅度的提升开发效率

        Spring4.0:紧跟jdk版本,对个别API做了调整

        Spring5.0:全面支持jdk8,如果想使用要把jdk升到8以上

3.spring系统架构图及学习顺序

正文

IOC案例(Spring基础项目的搭建)

Bean:一个java对象,一般被spring管理的对象统称为bean。

IoC:一种控制反转的设计思想,把对象的创建权由对象本身转交给容器,由主动new对象变为外部提供对象

1.先创建一个spring项目,把一些不需要的文件删除,只保留pom.xml文件、src文件夹下的java文件夹和resources文件夹,里面什么都可以没有,先在resources文件里创建spring配置文件(名字就叫spring配置)

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

2.在java文件夹下的org.example文件夹下新建一个dao包,里面写一个接口配上一个实现类,一会要把这个实现类做成bean

package com.example.bookDao;

public interface BookDao {
    public void save();
}
package com.example.bookDao.impl;

import com.example.bookDao.BookDao;

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

3.在resources文件夹下新建一个在xml配置文件,在里面配置bean对象信息

<!--2.配置bean-->
    <!--bean标签标示配置bean
    id属性标示给bean起名字
    class属性表示给bean定义类型-->
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>

4.在工程类中就可以获取IOC容器中的Bean

编写代码时要注意包别导错,使用getBean方法后记得强转为指定类型

import com.itheima.dao.BookDao;
import com.itheima.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App2 {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        BookDao bookDao =(BookDao) ctx.getBean("bookDao");
        bookDao.save();
    }
}

4.然后运行工程类就能运行对应的语句了

DI案例

DI:依赖注入,在容器中创建bean与bean之间的依赖关系的整个过程

在想要依赖别的bean的内部写入被依赖的bean,然后就能依赖了

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

Bean的配置

基本配置

id属性标示给bean起名字
class属性表示给bean定义类型

别名配置

name:为bean指定别名,别名可以有多个,使用逗号,分号,空格进行分隔

作用范围配置

scope:为bean设置作用范围

singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的。
prototype : 每次请求都会创建一个新的 bean 实例。
request : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP request 内有效。
session : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP session 内有效。
global-session: 全局 session 作用域,仅仅在基于 Portlet 的 web 应用中才有意义,Spring5 已经没有了。Portlet 是能够生成语义代码(例如:HTML)片段的小型 Java Web 插件。它们基于 portlet 容器,可以像 servlet 一样处理 HTTP 请求。但是,与 servlet 不同,每个 portlet 都有不同的会话。

Bean的实例化

  • 方式一:构造方法实例化bean

使用了无参的构造方法,还用了反射原理(不管私有还是公有都能访问)

<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
  • 方式二:使用静态工厂实例化bean

工厂模式要在代码中显式地创建工厂对象,然后使用工厂对象来创建具体的对象,这种方式需要我们自己手动创建和管理工厂对象,代码冗余和维护成本依然较高。

import com.itheima.dao.OrderDao;
import com.itheima.dao.impl.OrderDaoImpl;
//静态工厂创建对象
public class OrderDaoFactory {
    public static OrderDao getOrderDao(){
        System.out.println("factory setup....");
        return new OrderDaoImpl();
    }
}
<bean id="orderDao" class="com.itheima.factory.OrderDaoFactory" factory-method="getOrderDao"/>
  • 方式三:使用实例工厂实例化bean

因为方法二中的工厂方法只能调用静态方法,假如工厂方法非静态就能使用这个方法

import com.itheima.dao.UserDao;
import com.itheima.dao.impl.UserDaoImpl;
//实例工厂创建对象
public class UserDaoFactory {
    public UserDao getUserDao(){
        return new UserDaoImpl();
    }
}
<bean id="userFactory" class="com.itheima.factory.UserDaoFactory"/>

    <bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>
  • 方式四:使用FactoryBean实例化bean

由于方法三和方法一过于繁琐,就有了方法四,此方法要实现FactoryBean接口,泛型的类型写要创建的bean的方法,实现接口里的getObject和getObjectType方法

getObject方法的返回值为bean对象(相当于替换了工厂类的方法),getObjectType方法的返回值为bean的类名,例如:UserDao.class

import com.itheima.dao.UserDao;
import com.itheima.dao.impl.UserDaoImpl;
import org.springframework.beans.factory.FactoryBean;
//FactoryBean创建对象
public class UserDaoFactoryBean implements FactoryBean<UserDao> {
    //代替原始实例工厂中创建对象的方法
    public UserDao getObject() throws Exception {
        return new UserDaoImpl();
    }

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

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

bean的生命周期

  • 实例化(Instantiation)

init-method:设置bean初始化生命周期回调函数,destroy-method:设置bean销毁生命周期回调函数,仅适用于单例对象,也可以实现InitializingBean, DisposableBean接口,效果一样

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

1.创建对象(内存分配)
2.执行构造方法
3.执行属性注入(set操作)
4.执行bean初始化方法

  • 属性赋值(Populate)
  • 初始化(Initialization)
  • 销毁(Destruction)

ClassPathXmlApplicationContext的close方法,直接关闭IOC容器
ClassPathXmlApplicationContext的registerShutdownHook方法,告诉程序在程序关闭前先关闭IOC容器

import com.itheima.dao.BookDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

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

        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        bookDao.save();
        //注册关闭钩子函数,在虚拟机退出之前回调此函数,关闭容器
        //ctx.registerShutdownHook();
        //关闭容器
        ctx.close();
    }
}

依赖注入方式

用构造方法注入基本数据类型、string

在bean中定义基本数据类型并提供可访问的set方法

import com.itheima.dao.BookDao;

public class BookDaoImpl implements BookDao {
    private String databaseName;
    private int connectionNum;

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

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

配置中使用property标签value属性注入基本数据类型的值

<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
        根据构造方法参数名称注入
        <constructor-arg name="connectionNum" value="10"/>
        <constructor-arg name="databaseName" value="mysql"/>
    </bean>

除了这种还有两种方式

这种是降低了因为名称相同而造成的高耦合,但当同一类型的值有多个时无法使用

    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
        根据构造方法参数类型注入
        <constructor-arg type="int" value="10"/>
        <constructor-arg type="java.lang.String" value="mysql"/>
    </bean>

这种通过索引找值的方式虽然不用名称,也不用判断类型,但限制了参数的顺序,增高了耦合度

<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
        <!--根据构造方法参数位置注入-->
        <constructor-arg index="0" value="mysql"/>
        <constructor-arg index="1" value="100"/>
    </bean>

用构造方法注入引用类型

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


import com.itheima.dao.BookDao;
import com.itheima.dao.UserDao;
import com.itheima.service.BookService;

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

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

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

配置中用constructor-arg标签ref属性注入引用类型的值

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

用setter方法注入基本数据类型、string

在bean中定义基本数据类型并提供可访问的set方法

import com.itheima.dao.BookDao;

public class BookDaoImpl implements BookDao {

    private String databaseName;
    private int connectionNum;
    //setter注入需要提供要注入对象的set方法
    public void setConnectionNum(int connectionNum) {
        this.connectionNum = connectionNum;
    }
    //setter注入需要提供要注入对象的set方法
    public void setDatabaseName(String databaseName) {
        this.databaseName = databaseName;
    }

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

配置中使用property标签value属性注入基本数据类型的值

<!--注入简单类型-->
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
        <!--property标签:设置注入属性-->
        <!--name属性:设置注入的属性名,实际是set方法对应的名称-->
        <!--value属性:设置注入简单类型数据值-->
        <property name="connectionNum" value="100"/>
        <property name="databaseName" value="mysql"/>
    </bean>

用setter方法注入引用类型

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

private UserDao userDao;
//setter注入需要提供要注入对象的set方法
public void setUserDao(UserDao userDao) {
    this.userDao = userDao;
}

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

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

<!--注入引用类型-->
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
    <!--property标签:设置注入属性-->
    <!--name属性:设置注入的属性名,实际是set方法对应的名称-->
    <!--ref属性:设置注入引用类型bean的id或name-->
    <property name="bookDao" ref="bookDao"/>
    <property name="userDao" ref="userDao"/>
</bean>

依赖注入方式的选择

强制依赖私用构造器,可选依赖用setter注入
spring框架推荐构造器(严谨),个人使用推荐setter
有必要可同时使用
具体情况具体分析

依赖自动装配

IoC容器根资源在容据bean所依赖的器中自动查找并注入到bean中的过程称为自动装配

<bean class="com.itheima.dao.impl.BookDaoImpl"/>
    <!--autowire属性:开启自动装配,通常使用按类型装配-->
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl" autowire="byType"/>

autowire的一些值分别有

特征

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

集合注入

之前学习的都是一些单个的数据注入,现在开始写多个数据:集合,这种类型的注入,这种类型又分别分成以下几种类型,分别有:

数组注入

<!--数组注入-->
        <property name="array">
            <array>
                <value>100</value>
                <value>200</value>
                <value>300</value>
            </array>
        </property>


list集合注入

<!--list集合注入-->
        <property name="list">
            <list>
                <value>itcast</value>
                <value>itheima</value>
                <value>boxuegu</value>
                <value>chuanzhihui</value>
            </list>
        </property>

set集合注入

<!--set集合注入-->
        <property name="set">
            <set>
                <value>itcast</value>
                <value>itheima</value>
                <value>boxuegu</value>
                <value>boxuegu</value>
            </set>
        </property>


map集合注入

<!--map集合注入-->
        <property name="map">
            <map>
                <entry key="country" value="china"/>
                <entry key="province" value="henan"/>
                <entry key="city" value="kaifeng"/>
            </map>
        </property>


Properties注入

<!--Properties注入-->
        <property name="properties">
            <props>
                <prop key="country">china</prop>
                <prop key="province">henan</prop>
                <prop key="city">kaifeng</prop>
            </props>
        </property>


注意

list和数组的标签可以互相使用,注入引用类型用ref标签


案例:数据源对象管理

一个第三方的类的对象的管理

步骤:

1.先导依赖(c3p0的坐标可以去mvnrepository网站上搜)

<dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.16</version>
        </dependency>
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

2.再配置xml配置文件

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
           <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 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"/>
           <property name="maxPoolSize" value="1000"/>
       </bean>

3.最后在驱动类中就可以调用这个bean了

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

加载properties文件

要想让配置的bean生效,就必须先让properties文件生效

加载properties文件的步骤

1.开启一个namespace,命名空间叫context,开启的方法就是将原来的xmlns这行还有下面的两行http开头的复制,然后粘贴到跟复制的那段代码同级的位置上,然后把beans改为context

未开启:

<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
            ">

已开启:

<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/context/spring-context.xsd
            ">

2.使用context空间加载properties文件

property-placeholder叫做属性占位符,location的值用来指定所配置的文件名,当文件多个时,可以用引号包住,中间用逗号分隔,支持通配符,默认的系统文件的优先级比自己配置的文件的优先级高,system-properties-mode属性表示是否加载系统属性,never说明不加载系统属性,在文件名前加classpath:,可以不加但推荐加,现在默认只扫描当前工程里的配置文件,如果在给classpath:加上星号classpath*:,则表示可以扫描所有依赖的jar包

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

3.使用属性占位符${}读取properties文件中的属性

说明:idea自动识别${}加载的属性值,需要手工点击才可以查阅原始书写格式

<bean 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>

容器

两种创建容器的方法,这两种创建方法都支持配置多个文件
1.加载类路径下的配置文件

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

2.从文件系统下加载配置文件

ApplicationContext ctx = new FileSystemXmlApplicationContext("D:\\workspace\\spring\\spring_10_container\\src\\main\\resources\\applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
System.out.println(bookDao);

三种获取bean的方法

1.使用bean名称获取

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

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

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

3.使用eban的类型获取(使用此方法时,容器内这种类型的bean只能有一个)

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

还有一种获取bean的方法比较老(顶层接口初始化)(了解即可)

BeanFactory初始化的bean全部都是延迟加载,而ApplicationContext初始化出来的是立即加载的,lazy-init="true",给配置的bean加上这个属性可以设置让bean延迟加载

import com.itheima.dao.BookDao;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
//初始化BeanFactory
public class AppForBeanFactory {
    public static void main(String[] args) {
        Resource resources = new ClassPathResource("applicationContext.xml");
        BeanFactory bf = new XmlBeanFactory(resources);
        BookDao bookDao = bf.getBean(BookDao.class);
        bookDao.save();
    }
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值