Spring核心容器01

一、核心架构

在这里插入图片描述

二、核心概念

(一)IoC/DI概念(达到充分解耦)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

(二)IoC容器

(1)快速入门

  1. 导入坐标
        <!-- Spring -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
  1. resources文件下创建配置文件New>>XML Configuuration File>>Spring Config>>一般命名applicationContext.xml
  2. 在配置文件配置Bean
<!-- id:自定义的对象名,通过id值获取对应的bean,值要唯一 -->
<!-- class:bean的类型,	new哪一个类(注意不要new成接口了,而且要全路径名) -->
<bean id="bookDao" class="cn.fn.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="cn.fn.service.BookServiceImpl"/>
  1. 初始化IoC容器,通过容器获取Bean
    public static void main(String[] args) {
    	//初始化IoC容器,参数为配置文件名称
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        //通过IoC容器获取Bean,使用方法.getBean("id名"),然后强转为对应的类型
        BookService bookService = (BookService) ctx.getBean("bookService");
        //获取到了相应的对象,下面直接使用对象就可以了
        bookService.save();
    }
  1. 附上BookDaoImpl和BookServiceImpl
public class BookDaoImpl implements BookDao {
    @Override
    public void save() {
        System.out.println("BookDao save...");
    }
}
public class BookServiceImpl implements BookService {
    private BookDao bookDao = new BookDaoImpl();

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

(三)DI依赖注入

(1)快速入门

在IoC容器的基础上:

  1. 在上面的例子中,BookServiceImpl里面依然有new对象的形式存在,需要解耦。
  2. 所以先声明一个变量,而不new这个对象,然后提供一个setBookDao的方法。
public class BookServiceImpl implements BookService {
	//不要new,仅声明
    private BookDao bookDao;

    @Override
    public void save() {
        System.out.println("BookService save....");
        bookDao.save();
    }
	//提供一个set方法给bookDao设置一个对象
    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }
}
  1. 在applicationContext.xml中,因为是BookService需要BookDao的对象,所以在BookService里面新增一个property标签。
    <bean id="bookDao" class="cn.fn.dao.impl.BookDaoImpl"/>
    <bean id="bookService" class="cn.fn.service.impl.BookServiceImpl">
    	<!-- name表示BookServiceImpl里private BookDao bookDao;这个bookDao变量 -->
    	<!-- ref表示需要的bookDao对象 -->
        <property name="bookDao" ref="bookDao"></property>
    </bean>

在这里插入图片描述

三、Bean

  1. 对于Bean,可以使用name="XXXXX"设置他的别名。可以使用, ; 做分隔
    <bean id="bookDao" name="dao bookDao2" class="cn.fn.dao.impl.BookDaoImpl"/>
    <bean id="bookService" name="bookService023" class="cn.fn.service.impl.BookServiceImpl">
    	<!-- name表示BookServiceImpl里private BookDao bookDao;这个bookDao变量 -->
    	<!-- ref表示需要的bookDao对象 -->
        <property name="bookDao" ref="bookDao"></property>
    </bean>
  1. Bean的作用范围
    public static void main(String[] args) {
    	//初始化IoC容器,参数为配置文件名称
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        
        BookService bookService01 = (BookService) ctx.getBean("bookService");
        BookService bookService02 = (BookService) ctx.getBean("bookService");
    }

默认情况下,这种调用Bean的方式只是共同指向同一个Bean对象,并没有生成两个Bean对象。
需要使用scope="prototype/singleton"设置范围,singleton表示单例模式,默认设置;prototype表示生成不同对象。
eg:<bean id="bookService" class="cn.fn.service.impl.BookServiceImpl" scope="prototype">

在这里插入图片描述

(一)Bean实例化三种方式

例子的目录结构
在这里插入图片描述

(1)构造方法(常用)

在类中有无参构造方法即可(Spring内部通过反射创建对象)。

(2)静态工厂实例化(早期使用,了解)

在这里插入图片描述

(3)实例工厂实例化(早期使用,了解)

实例工厂和第2种方法类似,只是他的工厂方法不是static,所以在使用时需要先new实例工厂(不使用spring的话是这样),再用对象调实例工厂的方法来创建需要的对象。
在这里插入图片描述

(4)使用FactoryBean实例化Bean(方式3的变种,常用)

注:此方法默认是单例模式(可以在FactoryBean中改)

  1. 前期环境:接口>>实现接口类>>factoryBean类(如UserDaoFactoryBean)。
  2. factory类继承FactoryBean<T>接口,T表示工厂new对象的类型,比如UserDao。
  3. factory类中重写两个方法。
  4. 配置Bean,class指向这个factory类,其余不用配。
    在这里插入图片描述
    UserDaoFactoryBean
public class UserDaoFactoryBean implements FactoryBean<UserDao> {
    @Override
    public UserDao getObject() throws Exception {
    	//返回接口的实现类
        return new UserDaoImpl();
    }

    @Override
    public Class<?> getObjectType() {
    	//反射接口的字节码文件
        return UserDao.class;
    }

	//继承下面这个方法,true表示单例模式(默认),false表示非单例
	@Override
    public boolean isSingleton() {
        return false;
    }
}

IoC容器配置文件

<!-- 注意这里虽然这样写,但造出来的是该类中getObject()方法返回的对象 -->
<bean id="userDao" class="cn.fn.dao.factory.UserDaoFactoryBean"/>

使用Bean

public class App {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userDao = (UserDao) ctx.getBean("userDao");
        userDao.save();
    }
}

(二)Bean生命周期

bean生命周期:表示Bean从创建到销毁的整个过程。
bean生命周期控制:在bean创建后–到销毁前做一些事情。

(1)原始写法

  1. 在接口实现类中(如BookDaoImpl),初始化和销毁的方法名称可以自定义
public class BookDaoImpl implements BookDao {
    public void init() {
        //做一些初始化操作,如读取文件
        System.out.println("init...");
    }
    
    @Override
    public void save() {
        System.out.println("BookDao save...");
    }

    public void destroy() {
        //最后销毁操作,如关闭流等
        System.out.println("destroy...");
    }
}
  1. 在Bean配置文件中,init-method=" "指定谁是初始化方法,destory-method指定谁是销毁方法
    <bean id="bookDao" class="cn.fn.dao.impl.BookDaoImpl" init-method="init" destroy-method="destroy"/>
  1. 在使用方法中,首先ctx的声明类型要是ClassPathXmlApplicationContext (因为有close方法)。
    然后.registerShutdownHook()表示向JVM注册标记,等spring运行完再关闭JVM;.close()表示强制关闭IoC容器。
public class App {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        bookDao.save();
        ctx.registerShutdownHook();
//        ctx.close();
    }
}

(2)spring提供的规范方法

  1. 在实现类中实现InitializingBean和DisposableBean接口(重写两个接口的方法)
public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {
    private BookDao bookDao;

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

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

	//表示销毁方法
    @Override
    public void destroy() throws Exception {

    }
	
	//表示初始化方法
    @Override
    public void afterPropertiesSet() throws Exception {

    }
}
  1. 在Bean中就不需要init-methoddestroy-method来指定了。

(3)总结

在这里插入图片描述
在这里插入图片描述

四、DI依赖注入

在这里插入图片描述

(一)setter注入

setter注入就是在实现类中提供set方法

(1)简单类型(基本数据类型和String)

比如一个int和String类型的数据,要让IoC容器来传递值。

  1. 在实现类中定义变量但不给值,并提供设置值的set方法。
  2. 在配置Bean时,使用property的value属性注入需要的值。

BookDaoImpl

public class BookDaoImpl implements BookDao {
	//定义变量
    private int connectionNum;
    private String databaseName;

    @Override
    public void save() {
        System.out.println("BookDao save..." + connectionNum + ":" + databaseName);
    }

	//提供set方法
    public void setConnectionNum(int connectionNum) {
        this.connectionNum = connectionNum;
    }

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

IoC容器配置文件

    <bean id="bookDao" class="cn.fn.dao.impl.BookDaoImpl">
    	<!-- name是哪一个变量,value表示给什么值 -->
        <property name="connectionNum" value="10"/>
        <property name="databaseName" value="db1"/>
    </bean>

(2)引用类型

引用类型前面说过,就是传递对象过去,使用ref指定需要的bean的id。

(二)构造器注入

构造器注入就是在构造方法里传参。

(1)简单类型

就是在bean的类中写一个构造方法

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

	//新建一个构造方法
    public BookDaoImpl(int connectionNum, String databaseName) {
        this.connectionNum = connectionNum;
        this.databaseName = databaseName;
    }

    @Override
    public void save() {
        System.out.println("BookDao save..." + connectionNum + ":" + databaseName);
    }
}

然后在配置文件中,使用<constructor-arg>标签替代<property>标签。注意name代表构造方法的行参名。

    <bean id="bookDao" class="cn.fn.dao.impl.BookDaoImpl">
        <!--        <property name="connectionNum" value="10"/>-->
        <!--        <property name="databaseName" value="db1"/>-->
        <constructor-arg name="connectionNum" value="10"/>
        <constructor-arg name="databaseName" value="db1"/>
    </bean>

(2)引用类型

引用类型和上面一样,只是将value换成ref就行。

(三)注入方式怎么选

一句话:spring推荐构造器,但我们自己开发模块还是推荐setter。
在这里插入图片描述

(四)扩展(了解)

像上面这样写,耦合度较高,比如属性name依赖bean类的命名,所以有了下面两个Bean配置中的属性,typeindex
在这里插入图片描述

(五)依赖自动注入(只支持引用类型,不能用在简单类型上)

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

  • 按类型(byType,常用)
  • 按名称(byName,耦合高,不推荐)
  • 按构造方法(constructor,不推荐)

(1)具体操作

不同方式的共同特点:

  • 必须在bean类提供set方法。
  • 配置文件中使用autowire=""属性。
  • 以下面的为例,bookService需要bookDao的依赖,所以在bookService中配置autowire属性。
  1. 按类型方式byType(常用)
    在依赖的bean配置文件中,使用autowire="byType"
    这种方式是通过class属性去判断,所以两个class属性相同的bean会报错,要避免。
	<!-- 以byType方式,class名称相同会报错 -->
    <bean id="bookDao" class="cn.fn.dao.impl.BookDaoImpl"/>
    <bean id="bookDao2" class="cn.fn.dao.impl.BookDaoImpl"/>

    <bean id="bookService" class="cn.fn.service.impl.BookServiceImpl" scope="prototype"  autowire="byType"/>
  1. 按名称方式byName
    首先,BookServiceImpl需要一个BookDao,里面有一个setBookDao()方法
    id="bookDao这里的属性值要和BookServiceImplsetBookDao()方法set后面的单词相同(bookDao)。
	<!-- 以byName方式,class可以相同,但id不能相同 -->
    <bean id="bookDao" class="cn.fn.dao.impl.BookDaoImpl"/>
    <bean id="bookDao2" class="cn.fn.dao.impl.BookDaoImpl"/>

    <bean id="bookService" class="cn.fn.service.impl.BookServiceImpl" scope="prototype"  autowire="byName"/>

(2)总结

在这里插入图片描述

(六)如何注入集合

给出以下例子:
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;
    }

    @Override
    public void save() {
        System.out.println("BookDaoImp遍历所有:");
        Stream.of(array).forEach(System.out::print);
        System.out.println("List: " + list);
        System.out.println("Set: " + set);
        System.out.println("Map: " + map);
        System.out.println("Properties" + properties);
    }
}

xml中

    <bean id="bookDao" class="cn.fn.dao.impl.BookDaoImpl">
        <!-- 数组 -->
        <property name="array">
            <array>
                <value>100</value>
                <value>200</value>
                <value>300</value>
            </array>
        </property>
        <!-- List -->
        <property name="list">
            <list>
                <value>张三</value>
                <value>李四</value>
                <value>王五</value>
            </list>
        </property>
        <!-- Set -->
        <property name="set">
            <set>
                <value>chongqing</value>
                <value>chengdu</value>
                <value>yunnan</value>
                <value>yunnan</value>
            </set>
        </property>
        <!-- Map -->
        <property name="map">
            <map>
                <entry key="name" value="zhangsan"/>
                <entry key="age" value="18"/>
                <entry key="address" value="chongqing"/>
            </map>
        </property>
        <!-- Properties -->
        <property name="properties">
            <props>
                <prop key="className">test001</prop>
                <prop key="methodName">read</prop>
            </props>
        </property>
    </bean>

如果要包含引用类型,将各自的<value>标签改为<ref bean=beanId">

(七)案例,使用Druid

在这里插入图片描述

五、Spring如何读取Properties文件

  1. 开辟一个命名空间(复制现有内容,再改)
    原内容
    在这里插入图片描述

添加命名空间(xmlns表示xmlNameSpace),把原有的beans单词换为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/context/spring-context.xsd
">
  1. <bean>标签上,使用该命名空间,并指定配置文件(location),context即命名空间的名称。
    <context:property-placeholder location="jdbc.properties"/>
  2. 在bean中使用value=${XXX}代替原有的value=XXX
    注意:最好使用jdbc.XXX的形式,不然可能会报错。
    <context:property-placeholder location="jdbc.properties"/>
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

(一)注意事项

  1. 如上文说,使用username不使用jdbc.username会报错,是因为username这个名称和系统配置冲突了,解决办法:
<!-- 加了一个system-properties-mode属性,表示不加载系统属性 -->
<context:property-placeholder location="jdbc.properties" system-properties-mode="NEVER"/>
  1. 如果有多个配置文件怎么加?在属性location中,可以使用通配符*加载所有文件,也可以使用,列举文件
<context:property-placeholder location="*.properties" system-properties-mode="NEVER"/>
或则
<context:property-placeholder location="jdbc001.properties,jdbc002.properties" system-properties-mode="NEVER"/>
  1. 对于第2步的写法,最正规的写法应该加上classPath:(推荐)
<context:property-placeholder location="classpath:*.properties" system-properties-mode="NEVER"/>
  1. 最后,以上方式只能读取本项目的properties文件,要想读取其他jar包的properties,必须使用classPath*:*.properties的格式
<context:property-placeholder location="classpath*:*.properties" system-properties-mode="NEVER"/>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值