Spring6 笔记

/**
 *  DIP依赖倒置(开发原则):面向接口编程,面向抽象编程,不要面向具体编程。
 *  IoC控制反转(编程思想):将控制对象的创建与销毁和对象间的关系交给了Spring的IoC容器管理。
 *  DI 依赖注入(控制反转实现方式):动态的向某个对象提供它所需要的其他对象。
 *  AOP切面编程(编程思想):单独开发通用功能块、在需要位置通过方法执行前、后等方式切入(自动调用)
 *
 *  	SpringMVC => WEB三层架构
 *  		基本概念:将软件系统分为 Model / view / Controller
 *  			M:Model持久层 => 具体业务操作,如:查询数据库、封装对象
 *  			V:view视图层 => 进行数据展示
 *  			C:Controller控制层 => 1.获取View请求 2.调用Model将数据传给视图层进行展示
 *  		结构关系:
 *  			视图层(发送请求) => 业务逻辑层 => 数据访问层
 *  			数据访问层(返回数据) => 业务逻辑层 => 视图层(展示处理好的数据)
 */

Spring基本入门

①:Maven配置(pom.xml)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.powernode</groupId>
    <artifactId>Spring6-002</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!--配置多个仓库-->
    <repositories>
        <!--spring里程碑版本的仓库-->
        <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>
        <!--junit 单元测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.1</version>
            <scope>test</scope>
        </dependency>
        <!--1og4j2 日志-->
        <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>
    </dependencies>

    <properties>
        <maven.compiler.source>19</maven.compiler.source>
        <maven.compiler.target>19</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
</project>

②:创建实体类

public class User {		//User实体类

}
public class UserDaoImpl {		//UserDaoImpl实体类

}

③:创建Spring配置文件

<?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">
    <!--
        Spring配置文件模板
            文件名称:自定义 => 建议Spring.xml
            创建流程:新建 XML配置文件 => Spring配置
    -->
    
    <bean id="userBean" class="com.powernode.spring6.bean.User"/>
    <bean id="userDaoBean" class="com.powernode.spring6.dao.UserDaoImpl"/>
    <!--
        <bean id="" class=""/>
            id:bean的身份证号 => 不能重复的唯一标识
            class:全限定名 => 类的全路径、带包的类名
    -->
</beans>

④:创建log配置文件

<?xml version="1.0" encoding="UTF-8"?>

<!--log4j2日志配置文件-->
<configuration>
    <loggers>
        <!--
            Level指定日志级别,从低到高的优先级:
                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>

⑤:创建测试类

package com.powernode.spring6.test;

import com.powernode.spring6.bean.User;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 	Spring实例化对象原理:默认情况下Spring通过反射机制、调用类的无参构造方法实例化对象
 * 	Code实现如下:
 * 		Class clazz = Class.forName("com.powernode.spring6.bean.User");
 * 		Object obj = clazz.newInstance();
 * 	Spring底层IoC实现原理:XML解析 + 工厂模式 + 反射机制
 */
public class UserTest {

	@Test
	public void testUserCode(){

		/*	①:获取Spring容器对象
		 * 		ApplicationContext:Spring容器
		 * 		ClassPathXmlApplicationContext:从类路径加载Spring配置文件
		 * 		配置文件加载方式:支持1-多个
		 * 		Code说明:启动Spring容器,解析Spring.xml文件,并实例化所有bean对象,放到Spring容器中		 */
		//	加载单个xml配置文件
		ApplicationContext applicationContext1 = new ClassPathXmlApplicationContext("Spring.xml");
		//	加载多个xml配置文件
		//	ApplicationContext applicationContext2 = new ClassPathXmlApplicationContext("demo1.xml","demo2.xml");
		//	加载自定义文件夹下的xml配置文件
		//	ApplicationContext applicationContext3 = new ClassPathXmlApplicationContext("xml/Spring.xml");

		/*	log4j2记录日志基本使用:
		 *	①:获取指定记录对象 => 指定要记录的类 		 */
		Logger logger = LoggerFactory.getLogger(UserTest.class);
		//	②:设置日志 => 根据log4j2.xml设置的日志级别输出日志
		logger.info("我是一条消息");
		logger.debug("我是调试信息");
		logger.error("我是错误信息");

		/*	②:根据bean的id从Spring容器中获取这个对象
		 *		getBean("userBean",User.class):①、指定Bean id	②、指定返回类型		 */
		//	指定返回对象类型
		User userBean = applicationContext1.getBean("userBean", User.class);
		//	未指定返回对象类型
		Object userDaoBean = applicationContext1.getBean("userDaoBean");

		System.out.println(userBean);
		System.out.println(userDaoBean);
	}
}

IoC容器

具有依赖注入功能的容器,IOC容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。

SET方法注入 - 常用

①:配置 UserDao & UserService 类

public class UserDao {	

}
public class UserService {		

	// 将UserDao对象通过set方法注入到UserService的userDao属性中
	private UserDao userDao;

	/* set注入底层原理:
	 * 		1、通过反射机制调用属性对应的set方法给属性赋值
	 * 		2、要求:必须提供属性的set方法 */
	public void setUserDao(UserDao userDao) {
		this.userDao = userDao;
	}
}

②:配置Spring Bean

    <bean id="userDaoBean" class="com.powernode.spring6.dao.UserDao"/>
    
    <bean id="UserService" class="com.powernode.spring6.service.UserService">
        <property name="userDao" ref="userDaoBean"/>
        <!--
            set注入底层原理:
                1、通过反射机制调用属性对应的set方法给属性赋值
                2、要求:必须提供属性的set方法
            property:属性注入标签 => 属性赋值
                name:属性名 => userDao
                ref:指定要注入对象的bean ID
        -->
    </bean>

构造方法注入 - 不常用

①:配置 UserDao & CustomerService 类

public class CustomerService {

	// 将UserDao对象通过构造方法注入到CustomerService 的userDao属性中
	private UserDao userDao;

	// 通过构造方法注入
	public CustomerService(UserDao userDao) {
		this.userDao = userDao;
	}
}

②:配置Spring Bean

    <bean id="userDaoBean" class="com.powernode.spring6.dao.UserDao"/>
   
    <bean id="CustomerService" class="com.powernode.spring6.service.CustomerService">
        <constructor-arg name="userDao" ref="userDaoBean"/>
        <!--
            构造方法注入底层原理:
                1、通过反射机制调用类的构造方法
                2、要求:必须提供属性的set方法
            constructor-arg:通过构造器注入
                name:根据属性名进行构造方法注入
                index:根据指定参数下标注入 0、1、2... 以此类推
                ref:指定引用类型的bean ID
        -->
    </bean>

SET方法注入 - 外部Bean (推荐) & 内部Bean

    <!--外部定义的Bean-->
    <bean id="orderDaoBean" class="com.powernode.spring6.dao.OrderDao"></bean>
    <bean id="orderServiceBean" class="com.powernode.spring6.service.OrderService">
        <!--
            外部Bean:将外部定义的Bean引入到该Bean中,即为外部Bean
            特点:外部Bean可以被多个对象引用
        -->
        <property name="orderDao" ref="orderDaoBean"/>
    </bean>
    
    <bean id="orderServiceBean2" class="com.powernode.spring6.service.OrderService">
        <property name="orderDao">
            <!--
                内部Bean:在Bean中嵌套Bean,即为内部Bean
                特点:仅被某对象的某属性引用
            -->
            <bean class="com.powernode.spring6.dao.OrderDao"></bean>
        </property>

SET方法注入 - 简单类型

    <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <!--
            简单类型注入:Spring提供bean(数据库连接池) - 其他情况很少使用简单类型baen
                name :属性名
                value:属性值
        -->
        <property name="driverClassName">
            <value>com.mysql.jdbc.Driver</value>
        </property>
        <property name="url">
            <value>jdbc:mysql://localhost:3306/mydb</value>
        </property>
        <property name="username">
            <value>root</value>
        </property>
        <property name="password">
            <value>masterkaoli</value>
        </property>
    </bean>

SET方法注入 - 级联属性

①:方式一

    <bean name="emp" class="com.powernode.spring6.bean.Emp">
        <property name="EName" value="lucy"></property>
        <property name="gender" value="male"></property>
        <property name="dept" ref="dept"></property>
        <!--
            使用级联属性赋值:
                注意:
                ①:配置顺序 -> 1.先引入bean -> 2.在赋值
                ②:被ref引入的类,必须提供get方法
        -->
        <property name="dept.dName" value="安保"></property>
    </bean>
    <bean name="dept" class="com.powernode.spring6.Dept"></bean>

②:方式二

    <bean id="emp" class="com.powernode.spring6.bean.Emp">
        <property name="ename" value="zsp"></property>
        <property name="gender" value=""></property>
        <property name="dept" ref="dept"></property>
    </bean>
    <bean id="dept" class="com.powernode.spring6.bean.Dept">
        <!--仅赋值方式不同、性质相同-->
        <property name="dname" value="安保部"></property>
    </bean>

SET方法注入 - 数组类型

①:User

public class User {
	
	// 配置数组属性
	private String []username;
	
	// 通过set注入 - 数组属性
	public void setUsername(String[] username) {
		this.username = username;
	}
}

②:配置Spring Bean

	<bean id="user" class="com.shw.User">
		<property name="username">
			<array>
				<value>张三</value>
				<value>李四</value>
				<value>王五</value>
			</array>
		</property>
	</bean>

③:测试方法

public static void main(String[] args) {

		ApplicationContext context=new ClassPathXmlApplicationContext("Spring.xml");
		User user=(User) context.getBean("user");

		// test
		String []names=user.getUsername();
		for (String str : names) {
			System.out.println(str);
		}
	}

SET方法注入 - list & set集合

    <bean id="personBean" class="com.powernode.spring6.bean.Person">
        <property name="listName">
            <!--
                List集合 => 有序可重复
                类型:
                    简单:value
                    引用:ref
            -->
            <list>
                <value>张三</value>
                <value>李四</value>
                <value>王五i</value>
            </list>
        </property>
        <property name="setName">
            <!--
                set集合 => 无序不可重复
                类型:
                    简单:value
                    引用:ref
            -->
            <set>
                <value>张三</value>
                <value>李四</value>
                <value>王五</value>
            </set>
        </property>
    </bean>

SET方法注入 - map集合

    <bean id="personBean" class="com.powernode.spring6.bean.Person">
        <property name="mapName">
            <map>
                <!--
                    map集合 => 键值对
                    类型:
                        简单:<entry key="" value=""/>
                        引用:<entry key-ref="" value-ref=""/>
                -->
                <entry key="1" value="110"/>
                <entry key="2" value="120"/>
                <entry key="3" value="119"/>
            </map>
        </property>
    </bean>

SET方法注入 - null & 空字符串

    <bean id="catBean" class="com.powernode.spring6.bean.Cat">
        <!--
            不注入 => 属性的默认值就是null
            value="" => 注入空字符串
            异常:
                ①:调用null属性报空指针异常
                ②:调用空字符串属性,不会报异常
        -->
        <!--<property name="name" value="tom"/>-->
        <property name="name" value=""/>
        <property name="age" value="30"/>
    </bean>

SET方法注入 - 特殊符号

    <bean id="mathBean" class="com.powernode.spring6.bean.MathBean">
        <!--
            注入特殊符号:
                ①:使用实体符号(&lt;)代替特殊符号
                ②:使用<![CDATA[]]>,[]中内容当做字符串解析
                ③:<![CDATA[ ]]> => 仅支持<value>标签,不支持value属性
        -->
        <!--<property name="isDemo1" value="2 &lt; 3" />-->
        <property name="isDemo2">
            <value><![CDATA[2 < 3]]></value>
        </property>
    </bean>

SET方法注入 - P命名空间 => 简化set方法注入机制

<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--
        p命名空间注入 => 简化set方法注入机制
	        使用流程:
	        ①:在spring的配置文件头部添加p命名空间:xmlns:p="http://www.sprinqframework.orq/schema/p"
	        ②:使用p命名空间(p:属性名 = "属性值")
	        类型:
	            简单:p:name="小花"
	            引用:p:birth-ref="bean ID"
    -->
    <bean id="dogBean" class="com.powernode.spring6.bean.Dog" p:name="小花" p:age="30" p:birth-ref="birthBean"/>
    <!-- java.util.Date => 获取系统当前时间 -->
    <bean id="birthBean" class="java.util.Date"/>
</beans>

构造方法注入 - C命名空间 => 简化构造方法注入机制

<?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:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--
        C命名空间 => 简化构造方法注入机制
	        ①:在spring的配置文件头部添加:xmlns:c="http://www.springframework.org/schema/c"
	        ②:使用索引方式 c:_1 = "jack"  => (_1 = 形参的索引)
	        ③:使用形参方式 c:name="jack"  =>  (c:属性名="属性值")
	        类型:
	            简单:c:name="小花"
	            引用:c:birth-ref="bean ID"
    -->
    <!--<bean id="peopleBean" class="com.powernode.spring6.bean.People" c:_0="zhangsan" c:_1="30" c:_2="true"></bean>-->
    <bean id="peopleBean" class="com.powernode.spring6.bean.People" c:name="jack" c:age="30" c:obj-ref="true"></bean>
</beans>

构造方法注入 - 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命名空间 => 快速定义集合(复用集合)
	        ①:在spring的配置文件头部添加:
	            xmlns:util="http://www.springframework.org/schema/util"
	            http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
	        ②:使用util:集合标签 [快速定义集合] => util:properties/map/list/set...
	        ③:将util集合注入其他Bean(复用)
    -->
    
    <!--1.快速定义集合-->
    <util:properties id="propDemo">
        <prop key="driver">com.mysql.cj.jdbc.Driver</prop>
        <prop key="url">jdbc:mysql://localhost:3306/spring6</prop>
        <prop key="username">root</prop>
        <prop key="password">lirui1991</prop>
    </util:properties>

    <!--数据源1(复用集合)-->
    <bean id="ds1" class="com.powernode.spring6.jdbc.MyDataSource1">
        <property name="properties" ref="propDemo"/>
    </bean>
    <!--数据源2(复用集合)-->
    <bean id="ds2" class="com.powernode.spring6.jdbc.MyDataSource2">
        <property name="properties" ref="propDemo"/>
    </bean>
</beans>

SET方法注入 - 根据属性名(byName)自动装配 (不推荐)

    <!--
        根据属性名称自动装配 => byName
	        ①:主bean的属性中包含 spellChecker类型的成员属性
	        ②:主bean的spellChecker类型的成员属性含有set方法
	        ③:byName自动装配底层原理:
	            Spring IoC容器会在配置文件中查找id/name属性为spellChecker的bean,然后使用Seter方法为其注入。
    -->
    <bean id="orderService" class="com.powernode.spring6.service.OrderService" autowire="byName"></bean>
    <bean id="orderDao" class="com.powernode.spring6.dao.OrderDao"/>

SET方法注入 - 根据属性类型(byType)自动装配 (不推荐)

    <!--
        根据属性名称自动装配 => byType
	        ①:主bean的属性中包含 userDao类型的成员属性
	        ②:userDao类型bean在指定加载的spring容器中唯一,否则报异常
	        ③:主bean的userDao类型的成员属性含有set方法
	        ④:byType自动装配底层原理:
	            Spring IoC容器会在配置文件中查找类型为userDao的bean,然后使用Seter方法为其注入。
    -->
    <bean id="userDao" class="com.powernode.spring6.dao.UserDao"></bean>
    <bean id="customerService" class="com.powernode.spring6.service.CustomerService" autowire="byType"></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/spring-context.xsd">
    <!--
        引入外部的properties配置文件
	        ①:引入context命名空间:
	            xmlns:context="http://www.springframework.org/schema/context"
	            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"
	        ②:使用标签context:property-placeholder的ocation属性来指定属性配置文件的路径。
	        ③:Location属性 => 默认从类的根路径下开始加载资源。
    -->
    <context:property-placeholder location="jdbc.properties"/>
    <!--
        将jdbc.properties配置文件的数据读取到bean中
            ①:外部配置文件 jdbc.properties
            ②:Spring默认先从Window环境变量读取数据 => 防止重名,配置文件属性建议添加前缀(jdbc.)
            
            jdbc.driverClass=com.mysql.cj.jdbc.Driver
            jdbc.url=jdbc:mysql://localhost:3306/spring6
            jdbc.username=root
            jdbc.password=123   
    -->
    <bean id="ds" class="com.powernode.spring6.jdbc.MyDataSource">
        <property name="driver" value="${jdbc.driverClass}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>
</beans>

Bean作用域

Bean作用域 - 单例 & 多例

    <!--
        bean作用域单例和多例
            单例:
                ①:bean的scope属性 = singleton
                ②:加载Spring配置文件时,初始化实例对象
                ③:省略bean的scope属性,默认为singleton
            多例:
                ①:bean的scope属性 = prototype
                ②:在调用getBean()方法时,初始化实例对象
    -->
    <bean id="sb" class="com.powernode.spring6.bean.SpringBean" scope="singleton"></bean>

Bean作用域 - scope其他属性

    <!--
        bean作用域 - Scope其他属性
            属性值说明:
                ·singleton:默认,单例。
                ·prototype:每次调getBean()方法,则获取一个新的Bean对象
                ·request:一个请求对应一个Bean。(仅用于web)
                ·session:一个会话对应一个Bean。(仅用于web)
                ·global sessionl:portlet应用中专用的...
                ·application:一个应用对应一个Bean。(仅用于web)
                ·websocket:一个websocket生命周期对应一个Bean。(仅用于web)
                
                ·自定义scope:很少使用。
                    自定义scope:
                        ①:配置自定义作用域
                        ②:使用自定义作用域(其他bean中引入scope的自定义作用域类型即可)
    -->

    <!--①:配置自定义的作用域 (bean&property标签固定写法)-->
    <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
        <property name="scopes">
            <map>
                <!--entry key="threadScope" 配置自定义作用域的名称-->
                <entry key="threadScope">
                    <!--class是Spring框架内置的多线程类型-->
                    <bean class="org.springframework.context.support.SimpleThreadScope"/>
                </entry>
            </map>
        </property>
    </bean>
    <!--②:使用自定义的作用域-->
    <bean id="sh" class="com.powernode.spring6.bean.SpringBean" scope="threadScope"></bean>

Bean的实例化方式

Bean的实例化方式 - 构造方法 & 工厂静态方法

// 产品类
public class Star {	

	public Star() {
		System.out.println("Star无参构造...");
	}
}

// 工厂类
public class StarFactory {

	 // 生产方法
	 public static Star get(){
		 return new Star();
	 }
}
    <!--
        Bean的获取方式 => 实例化
            1.通过无参构造方法实例化
            2.通过工厂静态方法实例化
            3.通过工厂非静态方法实例化
            4.通过FactoryBean接口实例化
    -->
    <!--
        ①:通过无参构造方法实例化:
            ①:bean的class属性中引入类的全类名(包名+类名)
            ②:Spring底层自动调用该类的无参构造实例化bean对象
    -->
    <bean id="starId" class="com.powernode.spring6.bean.Star"/>

    <!--
        ②:通过简单工厂实例化:
            ①:创建Star产品类
            ②:创建Star工厂类StarFactory
            ③:配置StarFactory工厂类的生产方法(public static Star get(return new Star();))
            ④:配置starBean => starBean指向工厂类的生产方法factory-method="get"
            注意:工厂类的生产方法是静态方法
    -->
    <bean id="starBean" class="com.powernode.spring6.bean.StarFactory" factory-method="get"/>

Bean的实例化方式 - 工厂非静态方法 & 实现FactoryBean接口

// 产品类 => 通过工厂非静态方法实例化
public class Gun {

	public Gun() {
		System.out.println("Gun的无参构造方法执行...");
	}
}

// 工厂类
public class GunFactory {

	//生产方法
	public Gun get(){
		return new Gun();
	}
}
    <!--
        通过工厂非静态方法实例化
            ①:配置产品类Gun
            ②:配置工厂类GunFactory
            ③:配置工厂类的生产方法	public Gun get(){return new Gun();
            ④:配置工厂类gunFactory的Bean
            ⑤:配置产品类Gun的Bean => 指向工厂类的Bean的生产方法get()
                factory-bean => 指向工厂类的Bean
                factory-method => 指向工厂类的方法
    -->
    <bean id="gunFactory" class="com.powernode.spring6.bean.GunFactory"/>
    <bean id="gun" factory-bean="gunFactory" factory-method="get"/>

    <!--
        通过FactoryBean接口实例化 => 简化2、3实例化操作
            ①:配置产品类产品类Person
            ②:配置工厂类PersonFactory => 且实现FactoryBean(工厂Bean)
            ③:重写工厂Bean的生产方法	getObject(){return new Person();} => 自定义返回实例化对象
            ④:可选 => 重写工厂Bean的单例/多例模式方法 isSingleton(){return true/false} => 默认false单例/true多例
            ⑤:配置产品类Person的Bean => class指向 -> 工厂类PersonFactory即可
            -->
    <bean id="person" class="com.powernode.spring6.bean.PersonFactory"/>
// 产品类 => 通过实现FactoryBean实例化
public class Person {

	public Person() {
	}
}

/**
	 * 工厂类 => 实现FactoryBean
	 * 	FactoryBean:该接口为工厂Bean => 用于创建普通Bean
	 * 	getObject():该方法为生产Bean的方法 => 返回自定义实例化对象 即生产该对象
	 * 	isSingleton():用于配置单例 & 多例多模式
 */

public class PersonFactory implements FactoryBean<Person> {

	// 此方法为 生产方法
	@Override
	public Person getObject() throws Exception {
		// 自定义 产品实例化对象类型
		return new Person();
	}

	@Override
	public Class<?> getObjectType() {
		return null;
	}

	// (不用配置、Spring.xml中有默认实现)
	// 返回true表示单例模式 / 返回false表示多例模式
	@Override
	public boolean isSingleton() {
		return true;
	}
}

New对象 -> 转换为Bean

	@Test
	public void testRegisterBean() {

		// ①:自己new的对象
		Student student = new Student();
		System.out.println(student);

		// ②:将自己new的对象 -> 注册为Bean
		DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
		factory.registerSingleton("studentBean", student);

		// ③:从spring容器中获取Bean
		Student studentBean = (Student)factory.getBean("studentBean");
		System.out.println(studentBean);
	}

Bean的生命周期

Bean生命周期 - 常规5步

注意:

  • 单例:Spring容器进行完整的生命周期管理。
  • 多例:Spring容器不负责销毁
	/**
	 * Bean的生命周期五步:
	 * 第一步:实例化Bean
	 * 第二步:Bean属性赋值
	 * 第三步:初始化Bean
	 * 第四步:使用Bean
	 * 第五步:销毁Bean
	 */

// 产品类
public class User {

	private String name;

	// 通过无参构造创建Bean
	public User() {
		System.out.println("①:无参构造方法执行...");
	}

	// 通过set方法注入属性
	public void setName(String name) {
		this.name = name;
		System.out.println("②:set方法执行...");
	}

	// 对Bean进行初始化操作
	public void initBean() {
		System.out.println("③:初始化Bean...");
	}

	// ④:使用Bean => 此处为表现Bean的生命周期、非配置流程

	// close销毁该Bean
	public void destroyBean() {
		System.out.println("⑤:销毁Bean...");
	}
}
    <!--
        Bean生命周期:
            init-method => 配置Baen初始化方法
            destroy-method => 配置Bean销毁方法
            ②:set方法执行 => 需要注入Bean属性、否则缺失此步
    -->
    <bean id="user" class="com.powernode.spring6.bean.User" init-method="initBean" destroy-method="destroyBean">
        <property name="name" value="lirui"/>
    </bean>
// 测试类
public class BeanTest {

	@Test
	public void testBean(){
		// 获取Ioc容器 => getBean
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("Spring.xml");
		User user = applicationContext.getBean("user", User.class);
		System.out.println("④:使用Bean:"+user);

		// ApplicationContext 没有close方法 => close方法在 ClassPathXmlApplicationContext 中
		ClassPathXmlApplicationContext con = (ClassPathXmlApplicationContext) applicationContext;
		// 销毁Bean
		con.close();
	}
}

Bean生命周期 - 后处理器 - 7步

/**
	 Bean生命周期七步:比五步添加的那两步在哪里?在初始化Bean的前和后。
	 第一步:实例化Bean
	 第二步:Bean属性赋值
	 第三步:执行"Bean后处理器”的before方法。
	 第四步:初始化Bean
	 第五步:执行"Bean后处理器"的after方法。
	 第六步:使用Bean
	 第七步:销毁Bean
	 // Bean后处理器需要手动配置
		 ①:创建处理器实体类 实现 BeanPostProcessor 接口
		 重写:Before & After 方法
		 ②:Spring.xml配置文件中配置该Bean
		 <bean class="com.powernode.spring6.bean.LogBeanPostProcessor"/>
	*/

// 配置Bean后处理器 => 实现BeanPostProcessor 
public class LogBeanPostProcessor implements BeanPostProcessor {

	// Before方法
	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		System.out.println("执行Bean后处理器的Before方法...");
		return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
	}

	// After方法
	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		System.out.println("执行Bean后处理器的After方法...");
		return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
	}
}
    <!--
        配置Bean后处理器 => 配置后即生效
        注意:"Bean后处理器"将作用于当前配置文件中所有的Bean
    -->
    <bean class="com.powernode.spring6.bean.LogBeanPostProcessor"/>

    <!--
        Bean生命周期:
            init-method => 配置Baen初始化方法
            destroy-method => 配置Bean销毁方法
            ②:set方法执行 => 需要注入Bean属性、否则缺失此步
    -->
    <bean id="user" class="com.powernode.spring6.bean.User" init-method="initBean" destroy-method="destroyBean">
        <property name="name" value="lirui"/>
    </bean>

Bean生命周期 - 十步

  • "产品类"实现对应接口 => 重写方法即可 自动调用
/**	 
	 Bean生命周期十步:比七步添加的那三步在哪里?
	 第一步:实例化Bean
	 第二步:Bean属性赋值
	 点位1:检查Bean是否实现了Aware相关的接口
	 第三步:执行"Bean后处理器”的before方法。
	 点位2:检查Bean是否实现了InitializingBean接口
	 第四步:初始化Bean
	 第五步:执行"Bean后处理器"的after方法。
	 第六步:使用Bean
	 点位3:检查Bean是否实现了DisposableBean接口
	 第七步:销毁Bean
	 添加的这三个点位的特点:都是在检查你这个Bean是否实现了某些特定的接口,如果实现了这些接口,则Spring容器会调用这个接口中的方法。
 */

Bean的循环依赖

  • 循环依赖说明:
    • 两个类互相引用为属性,A中有B、B中有A

SET注入情况

  • 仅支持SET注入的情况 => 不支持构造方法注入的情况
    <!--
    	支持情况:
    		SET + 两个Bean都为单例模式 / 其中一个Bean为单例模式
   		不支持情况:
   			SET + 两个Bean都为多例模式 => 报异常(多例在getBean时才会实例化)
    -->
    <bean id="husbandBean" class="com.powernode.spring6.bean.Husband" scope="singleton">
        <property name="name" value="张三"/>
        <property name="wife" ref="wifeBean"/>
    </bean>
    <bean id="wifeBean" class="com.powernode.spring6.bean.Wife" scope="singleton">
        <property name="name" value="小花"/>
        <property name="husband" ref="husbandBean"/>
    </bean>

注解式IoC

注解入门程序

①:确认Maven(pom.xml)配置Spring-context核心依赖

        <!--Spring-context 基础-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.0.0-M2</version>
        </dependency>

②:配置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/spring-context.xsd">

③:配置Spring框架扫描哪些包中的类

  • 多个包,之间用逗号分割
    • <context:component-scan base-package=“com.powernode.spring6.bean,
      com.powernode.spring6.bean”"/>
  • 也可以加载多个包的父包(但会影响扫描速度)
    • <context:component-scan base-package=“com.powernode.spring6”/>
<context:component-scan base-package="com.powernode.spring6.bean"/>

④:在类上使用注解

  • 以下注解底层基于@Component,为增强MVC阅读性
    • @Controller -> 控制器
    • @Service -> 业务
    • @Repository -> DAO
/**
 * 	@Component -> 组件:仅用于类,可以被反射机制读取
 * 		@Component(value="userBean") 
 * 		作用等同于:<bean id="userBean" class="com.powernode.spring6.bean.Order"></bean>
 * 
 * 	( )中配置可以省略,省略后Bean名称为类名首字母小写user
 * 		@Component
 * 		作用等同于:<bean id="user" class="com.powernode.spring6.bean.Order"></bean>
 */
@Component
public class User {

}

⑤:测试:获取Bean

/**
 * 	声明Bean的注解 => Spring注解基于Spring-context核心依赖
 *  	@Component -> 组件:①:仅用于类,可以被反射机制读取
 *
 *  - 以下三个注解底层基于@Component,为增强MVC阅读性
 *  	@Controller -> 控制器
 *  	@Service -> 业务
 *  	@Repository -> DAO
 */
public class UserTest {

	@Test
	public void testBean(){

		// 获取Bean
		ApplicationContext context = new ClassPathXmlApplicationContext("Spring.xml");
		User user = context.getBean("user", User.class);
		System.out.println(user);
	}
}

Bean选择性实例化

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值