Spring_1_IoC控制反转_DI属性注入_SpringXML配置_命名空间

Spring 设计思想

IOC 控制反转

概念:

  • IOC(Inversion of Control) 控制反转。是面向对象编程中的一种设计思想,可以用来降低代码之间的耦合度,符合依赖倒置原则。
  • 使用对象时由原先的 new 创建,转换为有外部容器提供对象。此过程中,系统的对象创建控制权从程序转移到外部,该编程实现称之为控制反转。通俗的话来说就是:“将 new 对象的权利转交给 Spring,需要时从Spring 中获取就可”。

Spring IoC:

  • Spring 提供 IoC 容器,充当 IoC 思想中的“外部”。
  • IoC 容器负责对象的创建,初始化等工作,被管理的类对象在该容器中统称为 Bean。
  • 在IoC容器中将有依赖关系的 bean 进行关系绑定(DI 依赖注入)。

DI 依赖注入

概念:

  • DI(Dependency Injection)依赖注入,在容器中建立 bean 与 bean 之间的依赖关系的整个过程,称为依赖注入。
  • 客户端不仅可以直接从 IoC 容器中获取,并且获取到的 bean 已经绑定了所有的依赖关系。

在这里插入图片描述

DIP 依赖倒置

**概念:**依赖倒置原则(Dependence Inversion Principle),简称 DIP,主要倡导面向抽象编程,面向接口编程,不要面向具体编程,让上层不再依赖下层,下面改动了,上面的代码不会受到牵连。这样可以大大降低程序的耦合度,耦合度低了,扩展力就强了,同时代码复用性也会增强。(软件七大开发原则都是在为解耦合服务)

OCP 开闭解耦

概念:

  • 开闭原则是面向对象的可复用设计的第一块基石,它是最重要的面向对象设计原则。
  • 开闭原则定义为:一个软件实体应当对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展。
  • 软件实体从不同的粒度可以理解为模块、类、方法或者属性。

Spring 框架搭建

理论概述

概念:

  • Spring 是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。
  • Spring 最初的出现是为了解决 EJB 臃肿的设计,以及难以测试等问题。
  • Spring 为简化开发而生,让程序员只需关注核心业务的实现,尽可能的不再关注非业务逻辑代码(事务控制,安全日志等)。

特点:

  1. 轻量 (完整的 Spring 框架可以在一个大小只有 1MB 多的 JAR 文件里发布。并且 Spring 所需的处理开销也是微不足道的)。
  2. 控制反转。
  3. 面向切面。

相关依赖

<!-- Spring6 版本的 jar 包未有正式版上传 Maven 中央仓库(截止至2023.3.5) -->
<repositories>
    <repository>
        <id>repository.spring.milestone</id>
        <name>Spring Milestone Repository</name>
        <url>https://repo.spring.io/milestone</url>
    </repository>
</repositories>

<dependencies>
    <!--spring context 依赖-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>6.0.0-M2</version>
    </dependency>
	<!--Spring 对 junit 的支持相关依赖-->
	<dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-test</artifactId>
	    <version>6.0.0-M2</version>
	</dependency>
	<!-- Spring 提供的 JDBC 模版工具依赖-->
	<dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-jdbc</artifactId>
	    <version>6.0.0-M2</version>
	</dependency>
	<!--spring aop 依赖-->
	<dependency>
	  <groupId>org.springframework</groupId>
	  <artifactId>spring-aop</artifactId>
	  <version>6.0.0-M2</version>
	</dependency>
	<!--spring + aspects 依赖-->
	<dependency>
	  <groupId>org.springframework</groupId>
	  <artifactId>spring-aspects</artifactId>
	  <version>6.0.0-M2</version>
	</dependency>
</dependencies>

集成日志

Spring 集成 Log4j 日志框架:

  1. 引入 Log4j2 的依赖。
<!--log4j2的依赖-->
<dependency>
  <groupId>org.apache.logging.log4j</groupId>
  <artifactId>log4j-core</artifactId>
  <version>2.19.0</version>
</dependency>
<dependency>
  <groupId>org.apache.logging.log4j</groupId>
  <artifactId>log4j-slf4j2-impl</artifactId>
  <version>2.19.0</version>
</dependency>
  1. 根路径下提供 log4j2.xml 配置文件。
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <loggers>
        <!--
		ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF
        -->
        <root level="DEBUG">
            <appender-ref ref="spring6log"/>
        </root>
    </loggers>
    <appenders>
        <!--输出日志信息到控制台-->
        <console name="spring6log" target="SYSTEM_OUT">
            <!--控制日志输出的格式-->
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss SSS} [%t] %-3level %logger{1024} - %msg%n"/>
        </console>
    </appenders>
</configuration>
  1. 获取日志打印对象。
Logger logger = LoggerFactory.getLogger(FirstSpringClass.class);
logger.info("This is log from FirstSpringClass");

IOC 容器实现

Bean 基础配置

  1. 准备 Bean 类。
// 数据访问Dao层
public interface BookDao {
    void save();	
}

public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("DAO:添加书籍到数据库");
    }
}

// 业务逻辑层
public interface BookService {
    void save();	
}

public class BookServiceImpl implements BookService {
    private BookDao bookDao = new BookDaoImpl();
    //实现业务方法
    @Override
    public void save() {
        System.out.println("业务层:调用添加书籍的方法");
        bookDao.save();
    }
}
  1. 定义 Spring 配置文件 applicationContext.xml。
<?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">
    <!--
		bean标签:表示配置bean
		id属性:表示给bean起名字
		class属性:表示给bean定义类型
		name定义该bean的别名,可定义多个,使用逗号、空格、分号隔开
	-->
    <bean id="bookService" 
          class="com.lxl.service.impl.BookServiceImpl"
		 name="bookImpl,bookSI">
    </bean>
</beans>
  1. 初始化IoC容器(Spring核心容器),通过容器获取bean对象。
public class App {
    public static void main(String[] args) {
        //1.创建IoC容器对象,加载spring核心配置文件
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2 从IOC容器中获取Bean对象(BookService对象)
        BookService bookService= (BookService) ctx.getBean("bookService");
        //3 调用Bean对象(BookService对象)的方法
        bookService.save();
    }
}

Bean 作用域

<bean id="bookService" 
      class="com.lxl.service.impl.BookServiceImpl"
      scope="singleton">
</bean>
<!--
scope属性值,常用范围取值:
	1.singleton:单例(默认),该容器始终提供同一个 bean 对象。
	2.prototype:多例,每次获取该bean对象,容器都会创建一个新的返回。
扩展:scope 的取值不仅仅只有 singleton 和 prototype,在 SpringMVC 环境下还有 request、session、application、 websocket,表示创建出的对象放置在web容器(tomcat)对应的位置。比如:request 表示保存到 request 域中。
-->

Bean 实例化

  1. 构造器实例化。
<bean id="bookDao" class="com.lxl.dao.impl.BookDaoImpl"/>
<!-- 注意:无参构造方法如果不存在,将抛出异常 BeanCreationException -->
  1. 静态工厂实例化。
public class BookDaoFactory {  //定义静态工厂创建 Dao 类
	public static BookDao getBookDao(){
		System.out.println("BookDaoFactory setup....");
		return new BookDaoImpl();
	}
}
<bean id="bookDao" class="com.lxl.factory.BookDaoFactory" factory-method="getBookDao"/>
  1. 实例工厂实例化。
public class BookDaoFactory {
	public BookDao getBookDao(){
		return new BookDaoImpl();
	}
}
<bean id="bookFactory" class="com.lxl.factory.BookDaoFactory"/>
<bean id="bookDao" factory-method="getBookDao" factory-bean="bookFactory"/>
  1. FactoryBean 工厂实例化。
public class BookDaoFactory implements FactoryBean<BookDao> {
	@Override
	public BookDao getObject() throws Exception {
	    return new BookDaoImpl();
	}

	@Override
	public Class<BookDao> getObjectType() {
	    return BookDao.getClass();
	}

	@Override
	public boolean isSingleton() {
	    // true表示单例,false表示原型
	    return true;
	}
}
<bean id="bookDao" class="com.lxl.beanfactory.BookDaoFactory"/>
  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"
    xsi:schemaLocation="
		ttp://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.将 use-default-filters 设置为 false
			2.context:include-filter 标签列出哪些注解标注的 Bean 参与实例化
		use-default-filters 属性控制 spring 默认实例化规则
		该属性为 false 时表示即使有 ( Component、Controller、Service、Repository )
		这些注解标注,也不再实例化。
	-->
	<context:component-scan base-package="com.lxl.bean" use-default-filters="false">
		<context:include-filter type="annotation" 
					expression="org.springframework.stereotype.Controller"/>
	</context:component-scan>

    <!-- 
		排除法:
		1.将 use-default-filters 设置为 true
		2.exclude-filter 标签列出哪些注解标注的 Bean 不参与实例化
	-->
	<context:component-scan base-package="com.lxl.bean">
		<context:exclude-filter type="annotation" 
					expression="org.springframework.stereotype.Repository"/>
		<context:exclude-filter type="annotation" 
					expression="org.springframework.stereotype.Service"/>
		<context:exclude-filter type="annotation" 
					expression="org.springframework.stereotype.Controller"/>
	</context:component-scan>
</beans>

Bean 生命周期

概念:

  • 生命周期:从创建到消亡的完整过程。
  • bean 生命周期:bean 从创建到销毁的整体过程。
  • bean 生命周期控制:在 bean 创建后到销毁前做一些事情。

Bean 生命周期/构建流程:

  1. 实例化 Bean:
    • 对于 BeanFactory 容器,当客户向容器请求一个尚未初始化的 bean 时,或初始化 bean 的时候需要注入另一个尚未初始化的依赖时,容器就会调用 createBean 进行实例化。
    • 对于 ApplicationContext 容器,当容器启动结束后,通过获取 BeanDefinition 对象中的信息,实例化所有的 bean。
  2. 设置对象属性(依赖注入):
    • 实例化后的对象被封装在 BeanWrapper 对象中,紧接着,Spring 根据 BeanDefinition 中的信息 以及 通过 BeanWrapper 提供的设置属性的接口完成依赖注入。
  3. 处理 Aware 接口:
    • 如果这个 Bean 已经实现了 BeanNameAware 接口,会调用它实现的 setBeanName() 方法,此处传递的就是 Spring 配置文件中 Bean 的 id 值;
    • 如果这个 Bean 已经实现了 BeanFactoryAware 接口,会调用它实现的 setBeanFactory() 方法,传递的是 Spring 工厂自身。
    • 如果这个 Bean 已经实现了 ApplicationContextAware 接口,会调用 setApplicationContext() 方法,传入 Spring 上下文;
  4. BeanPostProcessor (before):
    • 如果想对 Bean 进行一些自定义的处理,那么可以在当前 xml 文件中配置实现了 BeanPostProcessor 接口的 bean,配置后该 xml 文件中的所有其他 bean 初始化时前将会调用其 postProcessBeforeInitialization(Object obj, String s) 方法。由于这个方法是在当前 XML 文件中所有 Bean 初始化前调用的,所以应位于 beans 的第一条配置,以管理其他 bean。
  5. InitializingBean (前初始化):
    • 如果检查该 bean 实现了 InitializingBean 接口,调用接口方法进行初步初始化。
  6. init-method (后初始化):
    • 如果 Bean 在 Spring 配置文件中配置了 init-method 属性,则会自动调用其配置的初始化方法进行二次初始化。
  7. BeanPostProcessor (after):
    • 如果当前 xml 文件配置了 BeanPostProcessor 接口的实现类 bean,该配置文件中所有其他 bean 初始化后将会调用该 BeanPostProcessor bean 处理器的 postProcessAfterInitialization(Object obj, String s) 方法。
  8. 以上几个步骤完成后,Bean 就已经被正确创建了,之后就可以使用这个 Bean 了。
  9. DisposableBean (前销毁):
    • 当 Bean 不再需要时,会经过清理阶段,如果 Bean 实现了 DisposableBean 这个接口,会调用其实现的 destroy()方法。
  10. destroy-method (后销毁):
    • 最后,如果这个 Bean 的 Spring 配置中配置了 destroy-method 属性,会自动调用其配置的销毁方法。

Bean 销毁时机:

  • 容器关闭前销毁.

关闭容器方式:

  1. 手动关闭容器,调用容器对象的 close() 方法。
  2. 注册钩子函数,在JVM关闭前先关闭容器,调用容器对象 registerShutdownHook() 方法。

Bean 生命周期与作用域:

  • 对于 singleton 作用域的 Bean,Spring 能够精确地知道该 Bean 何时被创建,何时初始化完成,以及何时被销毁。
  • 对于 prototype 作用域的 Bean,Spring 只负责创建,当容器创建了 Bean 的实例后,Bean 的实例就交给客户端代码管理,Spring 容器将不再跟踪其生命周期(只负责到 Bean 生命周期的第七步)。

代码示例:

public class User implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean {
	private String name;

	public User() {
	  System.out.println("1.实例化Bean");
	}

	public void setName(String name) {
	  this.name = name;
	  System.out.println("2.Bean属性赋值");
	}

	public void initBean(){
	  System.out.println("6.初始化Bean");
	}

	public void destroyBean(){
	  System.out.println("10.销毁Bean");
	}

	@Override
	public void setBeanClassLoader(ClassLoader classLoader) {
	  System.out.println("3.类加载器:" + classLoader);
	}

	@Override
	public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
	  System.out.println("3.Bean工厂:" + beanFactory);
	}

	@Override
	public void setBeanName(String name) {
	  System.out.println("3.bean名字:" + name);
	}

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

	@Override
	public void afterPropertiesSet() throws Exception {
	  System.out.println("5.afterPropertiesSet执行");
	}
	}

	public class MyBeanPostProcessor implements BeanPostProcessor {
	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
	  System.out.println("4.Bean后处理器的before方法执行,即将开始初始化");
	  return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
	  System.out.println("7.Bean后处理器的after方法执行,已完成初始化");
	  return bean;
	}
}
<!-- init-method:设置 bean 初始化生命周期回调函数 -->
<!-- destroy-method:设置 bean 销毁生命周期函数,仅适用于单例对象 -->
<bean id="user" class="com.lxl.dao.impl.User" init-method="initBean" destroy-method="destroyBean">
<property name="name" value="LXL"></perproties>
</bean>

<bean id="myBeanPostProcessor" class="com.lxl.beanutil.MyBeanPostProcessor"></bean>

Bean 依赖注入

简单/复杂注入

依赖注入:

  1. 简单类型注入,通过 value 标签或属性完成。
  2. 复杂类型注入,通过 ref 标签或属性完成。

BeanUtils 规定简单类型:

public class BeanUtils{
	public static boolean isSimpleValueType(Class<?> type) {
		return (Void.class != type && void.class != type &&
				(ClassUtils.isPrimitiveOrWrapper(type) ||
				Enum.class.isAssignableFrom(type) ||
				CharSequence.class.isAssignableFrom(type) ||
				Number.class.isAssignableFrom(type) ||
				Date.class.isAssignableFrom(type) ||
				Temporal.class.isAssignableFrom(type) ||
				URI.class == type ||
				URL.class == type ||
				Locale.class == type ||
				Class.class == type));
	}
}
/*
 * 基本数据类型
 * 基本数据类型对应的包装类
 * String或其他的CharSequence子类
 * Number子类
 * Date子类
 * Enum子类
 * URI
 * URL
 * Temporal子类
 * Locale
 * Class
 */
setter 注入
  1. Bean 类中删除 new 创建依赖属性的代码。
  2. 提供依赖对象对应的 setter 方法。
public class BookServiceImpl implements BookService {
    //删除使用new的形式创建对象的代码,解除对象之间的耦合度
    private BookDao bookDao;
    //提供依赖对象对应的setter方法
    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }
    //实现业务方法
    @Override
    public void save() {
        System.out.println("业务层:调用添加书籍的方法");
        bookDao.save();
    }
}
  1. 配置 Service 与 Dao 依赖关系。
<!--
	bean标签:表示配置bean。
		id属性:定义 bean 的名字。
		class属性:定义 bean 的类型。
	property 标签:配置当前 bean 中依赖属性,底层调用对应 setter 方法。
		name 属性:依赖属性的名称。
		ref 属性:复杂类型注入时对应 bean 的 id。
		value 属性:简单类型注入时的值。
-->
<bean id="bookDao" class="com.lxl.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.lxl.service.impl.BookServiceImpl">
    <property name="bookDao" ref="bookDao"/>
</bean>

setter 注入原理:

  1. 通过bean类的无参构造器创建对象。
  2. 通过配置文件从容器中获取所需依赖对象,并通过反射机制调用对应的setter方法为其赋值。
constructor 注入
  1. Bean 类中提供有参构造器。
  2. 配置 Service 与 Dao 依赖关系。
<bean id="bookDao" class="com.lxl.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.lxl.service.impl.BookServiceImpl">
	<!-- 指定有参构造器的参数名注入-->
	<constructor-arg name="bookDao" ref="bookDao"/>
	<!-- 指定参数位置注入,0表示第一个参数,1表示第二个参数,以此类推-->
	<constructor-arg index="0" ref="bookDao"/>
	<!-- 通过类型自动匹配注入,注入多个相同类型时不可用该方法-->
	<constructor-arg ref="bookDao"/>
</bean>
setter 多场景注入
<!-- 外部注入:注入的 bean 定义在外部 -->
<bean id="bookDao" class="com.lxl.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.lxl.service.impl.BookServiceImpl">
    <property name="bookDao" ref="bookDao"/>
</bean>

<!-- 内部注入:注入的 bean 定义在自己内部(了解即可) -->
<bean id="bookService" class="com.lxl.service.impl.BookServiceImpl">
	<property name="bookDao">
		<bean class="com.lxl.dao.impl.BookDaoImpl"></bean>
	</property>
</bean>

<!-- 级联属性注入,必须先父后子顺序 user -> user.name -->
<bean id="user" class="com.lxl.pojo.User"></bean>
<bean id="bookDao" class="com.lxl.dao.impl.BookDaoImpl">
	<property name="portNumber" value="10"/>
	<property name="user" ref="user"/>
	<property name="user.name" value="小明"/>
</bean>

<!-- 简单数据类型-数组、List、Set注入 -->
<!--数组、List、Set数据类型由于注入方式相同,故其 array、set、list 标签可混用-->
<property name="arrayName">
    <array>
        <value>100</value>
        <value>200</value>
        <value>300</value>
    </array>
</property>

<property name="listName">
    <list>
        <value>aaa</value>
        <value>bbb</value>
        <value>ccc</value>
    </list>
</property>

<property name="setName">
    <set>
        <value>aaa</value>
        <value>bbb</value>
        <value>ccc</value>
    </set>
</property>

<!-- 复杂数据类型-数组注入 -->
<bean id="good1" class="com.lxl.pojo.Good">
	<property name="name" value="苹果"/>
</bean>
<bean id="good2" class="com.lxl.pojo.Good"/>
	<property name="name" value="香蕉"/>
</bean>
<bean id="order" class="com.lxl.pojo.Order">
    <property name="goods">
        <array>
            <!-- 这里使用ref标签即可 -->
            <ref bean="good1"/>
            <ref bean="good2"/>
        </array>
    </property>
</bean>

<!-- 简单数据类型-Map集合注入 -->
<property name="mapName">
    <map>
        <entry key="1" value="aaa"/>
        <entry key="2" value="bbb"/>
        <entry key="3" value="ccc"/>
    </map>
</property>

<!-- 简单数据类型 properties 集合注入 -->
<property name="propertiesName">
    <props>
        <prop key="1">aaa</prop>
        <prop key="2">bbb</prop>
        <prop key="3">ccc</prop>
    </props>
</property>

<!-- 复杂数据类型-Map集合注入 -->
<property name="goods">
    <map>
        <entry key-ref="1" value-ref="good1"/>
        <entry key-ref="2" value-ref="good2"/>
    </map>
</property>

Bean 自动装配

自动依赖装配

概述:

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

自动装配方式:

  1. 按类型(常用)byType
  2. 按名称 byName
  3. 不启用自动装配 no

自动装配特征:

  • 自动装配用于引用类型依赖注入,不能对简单类型进行操作。
  • 使用按类型装配时(byType)必须保障容器中相同类型的 bean 唯一,推荐使用。
  • 使用按名称装配时(byName)必须保障容器中具有指定名称的 bean,因变量名与配置耦合,不推荐使用。将查找其类中所有的 set 方法名,例如 setCat,获得将set去掉并且首字母小写的字符串,即 cat。后去spring容器中寻找是否有此字符串名称 id 的对象。如果有,就取出注入;如果没有,就报空指针异常。
  • 自动装配优先级低于 setter 注入与构造器注入,同时出现时,自动装配配置失效。
  • XML配置中的autowire,底层调用 bean 类 setter 方法注入

自动装配用例:

<bean id="bookDao" class="com.lxl.dao.impl.BookDaoImpl"/>
<bean id="bookService"
      class="com.lxl.service.impl.BookServiceImpl"
      autowire="byType" />

Bean 命名空间

P 命名空间
<!-- p命名空间简化 setter 注入配置,需要对应的属性提供 setter 方法 -->
<?xml version="1.0" encoding="UTF-8"?>
<!--第一:在XML头部信息中添加p命名空间的配置信息 xmlns:p-->
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:p="http://www.springframework.org/schema/p"
    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">
	<bean id="bookDao" class="com.lxl.dao.impl.BookDaoImpl"/>
	<bean id="bookService" 
	      class="com.lxl.service.impl.BookServiceImpl" 
	      p:bookDao-ref="bookDao"
	      p:portNumber="10" />
	<!-- 简单类型 p:属性名 注入,非简单类型 p:birth-ref="beanId/beanName" -->
</beans>
C 命名空间
<!-- c 命名空间简化构造器注入,需要对应的属性提供构造器方法 -->
<?xml version="1.0" encoding="UTF-8"?>
<!--第一:在XML头部信息中添加 c 命名空间的配置信息 xmlns:c-->
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:c="http://www.springframework.org/schema/c"
    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">
	<bean id="bookDao" class="com.lxl.dao.impl.BookDaoImpl"/>
	<!-- 指定参数名注入-->
	<bean id="bookService1" 
	      class="com.lxl.service.impl.BookServiceImpl" 
	      c:bookDao-ref="bookDao"
	      c:portNumber="10" />
	<!-- 指定参数位置注入,0表示第一个参数,1表示第二个参数,以此类推-->
	<bean id="bookService2" 
	      class="com.lxl.service.impl.BookServiceImpl" 
	      c:_0-ref="bookDao"
	      c:_1="10" />
	<!-- 索引注入 c:_索引 ,参数名注入 c:day="1" -->
</beans>
Util 命名空间
<!-- Util 命名空间的作用是配置复用 -->
<?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:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
    <!-- util:properties 定义一个 Properties 类型的 bean -->
    <!-- 
		默认通过 location 指定的文件中定义的键值对拥有更高的优先级。
		local-override 为 true 时 prop 标签定义的值优先级更高
	-->
    <util:properties id="prop" location="classpath:jdbc.properties"
                     local-override="false">
        <prop key="driver">com.mysql.cj.jdbc.Driver</prop>
        <prop key="url">jdbc:mysql://localhost:3306/test</prop>
        <prop key="username">root</prop>
        <prop key="password">123456</prop>
    </util:properties>
    
    <!-- util:list 定义一个 java.util.List 类型的 bean -->
    <!-- 
		value-type 属性默认为 java.lang.String
		list-class 属性默认为 java.util.ArrayList
	-->
    <util:list id="utilList" value-type="java.lang.Integer" 
               list-class="java.util.LinkedList">
    	<value>1</value>
    	<value>2</value>
	</util:list>
    
	<!-- util:list 定义一个 java.util.Set 类型的 bean -->
	<!-- 
		value-type 属性默认为 java.lang.String
		set-class 属性默认为 java.util.LinkedHashSet
	-->
    <util:set id="utilSet" value-type="java.lang.Integer" 
              set-class="java.util.HashSet">
    	<value>1</value>
    	<value>2</value>
	</util:set>
    
    <!-- util:map 定义一个 java.util.Map 类型的 bean -->
	<!-- 
		value-type 属性默认为 java.lang.String
	-->
	<util:map id="utilMap">
	    <entry key="a" value="1"
               value-type="java.lang.Integer"/>
	    <entry key-ref="utilSet" value-ref="utilSet"/>
	</util:map>
</beans>
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"
    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/springcontext.xsd">

    <!-- context:property-placeholder 标签用于加载 property 属性文件 -->
	<context:property-placeholder location="jdbc.properties"/>
	<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
		<property name="driverClassName" value="${db.driver}"/>
		<property name="url" value="${db.url}"/>
		<property name="username" value="${db.username}"/>
     	<!-- 不可直接使用 ${username},因为优先读取系统属性 username -->
		<property name="password" value="${db.password}"/>
	</bean>
    <!--
		自动扫描,它会将 base-package 指定位置下的具有 spring 对应注解
		@Component,@Service,@Repository,@Controller 等
		的类在加载容器时都注入 springIOC 容器中
	-->
    <context:component-scan base-package="com.lxl"/>
</beans>

在这里插入图片描述

Bean 依赖循环

spring 中的依赖循环:

  1. 在 singleton+set 注入的情况下,循环依赖是没有问题的。
  2. 在 singleton+constructor 注入的情况下,无法解决循环依赖。
  3. 循环依赖的所有 Bean的scope=“prototype” 时产生的循环依赖,会出现 BeanCurrentlyInCreationException 异常。
  4. 循环依赖的两个 Bean ,如果其中一个是 singleton,另一个是 prototype,循环依赖是没有问题的。

Spring 解决循环依赖的机理(步骤):

  1. 此时可以先不给属性赋值,可以提前将该 Bean 对象“曝光”给外界。
  2. 所有的单例 Bean 全部实例化完成之后,再调用 setter 方法给属性赋值。

Spring 的三级缓存:

image-20230320212218972

  1. Cache of singleton objects: bean name to bean instance。单例对象的缓存:key 存储 bean 名称,value 存储 Bean 对象【一级缓存】,缓存单例完全体 Bean。
  2. Cache of early singleton objects: bean name to bean instance。早期单例对象的缓存:key 存储 bean 名称,value 存储 Bean 对象【二级缓存】,缓存单例残缺体 Bean。
  3. Cache of singleton factories: bean name to ObjectFactory.单例工厂缓存:key 存储 bean 名称,value 存储该 Bean 对应的 ObjectFactory 对象【三级缓存】,缓存 Bean 对应的 ObjectFactory 对象,处理 AOP 代理问题。

在这里插入图片描述

Spring 整合 Druid (XML)

  1. 导入Maven依赖坐标
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.8</version>
</dependency>

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

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.10.RELEASE</version>
</dependency>
  1. 配置Druid连接池对象为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"
       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/springcontext.xsd">

	<context:property-placeholder location="jdbc.properties"/>
	<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
		<property name="driverClassName" value="${db.driver}"/>
		<property name="url" value="${db.url}"/>
		<property name="username" value="${db.username}"/>
		<property name="password" value="${db.password}"/>
	</bean>
</beans>
  1. IoC容器中获取DruidDataSource对象
// 1.加载类路径下的配置文件
ClassPathXmlApplicationContext context = new
    ClassPathXmlApplicationContext("applicationContext.xml");

// 2.从IoC容器获取bean

DataSource dataSource = (DataSource) context.getBean("dataSource");
Connection connection = dataSource.getConnection();

// 3.关闭容器
context.close();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值