- "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 id="student" class="com.atguigu.spring.pojo.Student" >
- <property name="sid" value="1001">property>
- <property name="sname" value="张三">property>
- bean>
-
- beans>
- @Test
- public void testScope(){
- ApplicationContext ioc = new ClassPathXmlApplicationContext("spring-scope.xml");
- Student student1 = ioc.getBean(Student.class);
- Student student2 = ioc.getBean(Student.class);
- System.out.println(student1 == student2);
- }
结果为true 所以默认为单例,
多例
- "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 id="student" class="com.atguigu.spring.pojo.Student" scope="prototype">
- <property name="sid" value="1001">property>
- <property name="sname" value="张三">property>
- bean>
-
- beans>
测试:
- package com.atguigu.spring.pojo;
-
- /**
- * Date:2022/7/1
- * Author:ybc
- * Description:
- */
- public class User {
-
- private Integer id;
- private String username;
- private String password;
- private Integer age;
- public User() {
- }
- public User(Integer id, String username, String password, Integer age) {
- this.id = id;
- this.username = username;
- this.password = password;
- this.age = age;
- }
- public Integer getId() {
- return id;
- }
- public void setId(Integer id) {
- this.id = id;
- }
- public String getUsername() {
- return username;
- }
- public void setUsername(String username) {
- this.username = username;
- }
- public String getPassword() {
- return password;
- }
- public void setPassword(String password) {
- this.password = password;
- }
- public Integer getAge() {
- return age;
- }
- public void setAge(Integer age) {
- this.age = age;
- }
- @Override
- public String toString() {
- return "User{" +
- "id=" + id +
- ", username='" + username + '\'' +
- ", password='" + password + '\'' +
- ", age=" + age +
- '}';
- }
- }
- "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 id="user" class="com.atguigu.spring.pojo.User" >
-
- <property name="id" value="1">property>
- <property name="username" value="admin">property>
- <property name="password" value="123456">property>
- <property name="age" value="23">property>
-
- bean>
- beans>
- package com.atguigu.spring.pojo;
-
- /**
- * Date:2022/7/1
- * Author:ybc
- * Description:
- */
- public class User {
-
- private Integer id;
-
- private String username;
-
- private String password;
-
- private Integer age;
-
- public User() {
- System.out.println("生命周期1:实例化");
- }
-
- public User(Integer id, String username, String password, Integer age) {
- this.id = id;
- this.username = username;
- this.password = password;
- this.age = age;
- }
-
- public Integer getId() {
- return id;
- }
-
- public void setId(Integer id) {
- System.out.println("生命周期2:依赖注入");
- this.id = id;
- }
-
- public String getUsername() {
- return username;
- }
-
- public void setUsername(String username) {
- this.username = username;
- }
-
- public String getPassword() {
- return password;
- }
-
- public void setPassword(String password) {
- this.password = password;
- }
-
- public Integer getAge() {
- return age;
- }
-
- public void setAge(Integer age) {
- this.age = age;
- }
-
- @Override
- public String toString() {
- return "User{" +
- "id=" + id +
- ", username='" + username + '\'' +
- ", password='" + password + '\'' +
- ", age=" + age +
- '}';
- }
-
- public void initMethod(){
- System.out.println("生命周期3:初始化");
- }
-
- public void destroyMethod(){
- System.out.println("生命周期4:销毁");
- }
-
- }
- @Test
- public void test(){
- //ConfigurableApplicationContext是ApplicationContext的子接口,其中扩展了刷新和关闭容器的方法
- // ConfigurableApplicationContext ioc = new ClassPathXmlApplicationContext("spring-lifecycle.xml");
- ApplicationContext ioc = new ClassPathXmlApplicationContext("spring-lifecycle.xml");
- User user = ioc.getBean(User.class);
- System.out.println(user);
- }
要设置初始化init和销毁destroy的方法 要通过bean标签的属性来指定的
bean
- "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 id="user" class="com.atguigu.spring.pojo.User" init-method="initMethod" destroy-method="destroyMethod">
-
- <property name="id" value="1">property>
- <property name="username" value="admin">property>
- <property name="password" value="123456">property>
- <property name="age" value="23">property>
-
- bean>
- beans>
测试
- @Test
- public void test(){
- //ConfigurableApplicationContext是ApplicationContext的子接口,其中扩展了刷新和关闭容器的方法
- // ConfigurableApplicationContext ioc = new ClassPathXmlApplicationContext("spring-lifecycle.xml");
- ApplicationContext ioc = new ClassPathXmlApplicationContext("spring-lifecycle.xml");
- User user = ioc.getBean(User.class);
- System.out.println(user);
- }
-
- }
ioc的bean在什么时候销毁 是在ioc容器关闭的时候ioc.close();销毁
- @Test
- public void test(){
- //ConfigurableApplicationContext是ApplicationContext的子接口,其中扩展了刷新和关闭容器的方法
- ConfigurableApplicationContext ioc = new ClassPathXmlApplicationContext("spring-lifecycle.xml");
- // ApplicationContext ioc = new ClassPathXmlApplicationContext("spring-lifecycle.xml");
- User user = ioc.getBean(User.class);
- System.out.println(user);
- ioc.close();
- }
- }
总结:
* 生命周期的步骤: * 1、实例化 * 2、依赖注入 * 3、初始化,需要通过bean的init-method属性指定初始化的方法 * 4、IOC容器关闭时销毁,需要通过bean的destroy-method属性指定销毁的方法
测试:
- @Test
- public void test(){
- //ConfigurableApplicationContext是ApplicationContext的子接口,其中扩展了刷新和关闭容器的方法
- ConfigurableApplicationContext ioc = new ClassPathXmlApplicationContext("spring-lifecycle.xml");
- // ApplicationContext ioc = new ClassPathXmlApplicationContext("spring-lifecycle.xml");
- /* User user = ioc.getBean(User.class);
- System.out.println(user);
- ioc.close();*/
- }
修改bean
- "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 id="user" scope="prototype" class="com.atguigu.spring.pojo.User" init-method="initMethod" destroy-method="destroyMethod">
-
- <property name="id" value="1">property>
- <property name="username" value="admin">property>
- <property name="password" value="123456">property>
- <property name="age" value="23">property>
-
- bean>
- beans>
测试
- @Test
- public void test(){
- //ConfigurableApplicationContext是ApplicationContext的子接口,其中扩展了刷新和关闭容器的方法
- ConfigurableApplicationContext ioc = new ClassPathXmlApplicationContext("spring-lifecycle.xml");
- // ApplicationContext ioc = new ClassPathXmlApplicationContext("spring-lifecycle.xml");
- /* User user = ioc.getBean(User.class);
- System.out.println(user);
- ioc.close();*/
- }
结论:当我们把bean的作用域设置成多例的时候 ,因为每一次通过bean获取到的对象都是一个新的对象,没有必要ioc获取的时候就直接把对象创建好,因为是多例,所以每一次获取都是一个新对象,也就是说并不是在获取ioc容器的时候执行
在测
- @Test
- public void test(){
- //ConfigurableApplicationContext是ApplicationContext的子接口,其中扩展了刷新和关闭容器的方法
- ConfigurableApplicationContext ioc = new ClassPathXmlApplicationContext("spring-lifecycle.xml");
- // ApplicationContext ioc = new ClassPathXmlApplicationContext("spring-lifecycle.xml");
- User user = ioc.getBean(User.class);
- System.out.println(user);
- ioc.close();
- }
总结:
如果是多例,前三个步骤是在获取bean的时候执行 不是获取ioc容器的时候执行,设置成多例后,每一次通过bean来获取的对象都是一个新的对象,所以没有必要提前创建
问题 :当把容器关闭后 销毁并没有执行
当我们把bean的作用域设置成多例的时候,销毁的方法不由我们的ioc容器管理了(了解)
ctrl+O 重写方法
MyBeanPostProcessor
- public class MyBeanPostProcessor implements BeanPostProcessor {
-
-
- @Override
- public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
- //此方法在bean的生命周期初始化之前执行
- System.out.println("MyBeanPostProcessor-->后置处理器postProcessBeforeInitialization");
- return bean;
- }
-
- @Override
- public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
- //此方法在bean的生命周期初始化之后执行
- System.out.println("MyBeanPostProcessor-->后置处理器postProcessAfterInitialization");
- return bean;
- }
- }
- "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 id="user" class="com.atguigu.spring.pojo.User" init-method="initMethod" destroy-method="destroyMethod">
-
- <property name="id" value="1">property>
- <property name="username" value="admin">property>
- <property name="password" value="123456">property>
- <property name="age" value="23">property>
- bean>
-
- <bean id="myBeanPostProcessor" class="com.atguigu.spring.process.MyBeanPostProcessor">bean>
- beans>
测试
- @Test
- public void test(){
- //ConfigurableApplicationContext是ApplicationContext的子接口,其中扩展了刷新和关闭容器的方法
- ConfigurableApplicationContext ioc = new ClassPathXmlApplicationContext("spring-lifecycle.xml");
- // ApplicationContext ioc = new ClassPathXmlApplicationContext("spring-lifecycle.xml");
- User user = ioc.getBean(User.class);
- System.out.println(user);
- ioc.close();
- }
总结:
/**
具体的生命周期过程
* 1、实例化
* 2、依赖注入
* 3、后置处理器的postProcessBeforeInitialization
* 4、初始化,需要通过bean的init-method属性指定初始化的方法
* 5、后置处理器的postProcessAfterInitialization
* 6、IOC容器关闭时销毁,需要通过bean的destroy-method属性指定销毁的方法
*
* bean的后置处理器会在生命周期的初始化前后添加额外的操作
* 需要实现BeanPostProcessor接口且配置到IOC容器中
* 需要注意的是,bean后置处理器不是单独针对某一个bean生效,而是针对IOC容器中所有bean都会执行
*
* 注意:
* 若bean的作用域为单例时,生命周期的前三个步骤会在获取IOC容器时执行
* 若bean的作用域为多例时,生命周期的前三个步骤会在获取bean时执行
*/
- package org.springframework.beans.factory;
- import org.springframework.lang.Nullable;
-
-
- //
工厂所提供的类型 - public interface FactoryBean
{ - String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
-
- //获取对象
- @Nullable
- T getObject() throws Exception;
-
- //获取对象的类型
- @Nullable
- Class> getObjectType();
-
- //是否单例
- default boolean isSingleton() {
- return true;
- }
- }
ctrl+i 重写
- package com.atguigu.spring.factory;
-
- import com.atguigu.spring.pojo.User;
- import org.springframework.beans.factory.FactoryBean;
-
- /**
- * Date:2022/7/1
- * Author:ybc
- * Description:
- * FactoryBean是一个接口,需要创建一个类实现该接口
- * 其中有三个方法:
- * getObject():通过一个对象交给IOC容器管理
- * getObjectType():设置所提供对象的类型
- * isSingleton():所提供的对象是否单例
- * 当把FactoryBean的实现类配置为bean时,会将当前类中getObject()所返回的对象交给IOC容器管理
- *
- */
- public class UserFactoryBean implements FactoryBean
{ - @Override
- public User getObject() throws Exception {
- return new User();
- }
-
- @Override
- public Class> getObjectType() {
- return User.class;
- }
- }
spring-factory.xml
- "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 class="com.atguigu.spring.factory.UserFactoryBean">bean>
-
- beans>
把UserFactoryBean里面getObject()方法的所返回的对象 return new User();交给IOC容器
真正交给IOC管理的是UserFactoryBean里面getObject()方法里面User的bean
测试: FactoryBeanTest
- public class FactoryBeanTest {
-
- @Test
- public void testFactoryBean(){
- //获取IOC容器
- ApplicationContext ioc = new ClassPathXmlApplicationContext("spring-factory.xml");
- User user = ioc.getBean(User.class);
- System.out.println(user);
- }
-
- }
我们把FactoryBean配置到IOC容器中,并不是把UserFactoryBean这个类型交给IOC容器管理,而是把UserFactoryBean类型中的getObject()方法的返回值交给IOC容器管理
FactoryBean和普通工厂的区别:(以后在整理 现在有点乱)
总结:
* FactoryBean是一个接口,需要创建一个类实现该接口 * 其中有三个方法: * getObject():通过一个对象交给IOC容器管理 * getObjectType():设置所提供对象的类型 * isSingleton():所提供的对象是否单例 * 当把FactoryBean的实现类配置为bean时,会将当前类中getObject()所返回的对象交给IOC容器管理
拓展:
一.FactoryBean和普通Bean的区别
Spring 中有两种类型的Bean:一种是普通Bean,另一种是工厂Bean 即 FactoryBean。
FactoryBean跟普通Bean不同,其返回的对象不是指定类的一个实例,而是该FactoryBean的getObject方法所返回的对象。创建出来的对象是否属于单例由isSingleton中的返回决定。二 .spring中FactoryBean和BeanFactory的区别
1 .BeanFactory
BeanFactory,以Factory结尾,表示它是一个工厂类(接口), 它负责生产和管理bean的一个工厂,我们可以通过它获取工厂管理的对象。在Spring中,BeanFactory是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。它定义了getBean()、containsBean()等管理Bean的通用方法。但BeanFactory只是个接口,并不是IOC容器的具体实现,但是Spring容器给出了很多种实现,如 :
DefaultListableBeanFactory
XmlBeanFactory
ApplicationContext其中XmlBeanFactory就是常用的一个,该实现将以XML方式描述组成应用的对象及对象间的依赖关系。
源码:
public interface BeanFactory {
/**
用于区分factoryBean和bean,后面会讲到
/*String FACTORY_BEAN_PREFIX = "&";
/**
返回byName返回bean的实例
*/
Object getBean(String name) throws BeansException;
T getBean(String name, Class requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
T getBean(Class requiredType) throws BeansException;
T getBean(Class requiredType, Object... args) throws BeansException;
ObjectProvider getBeanProvider(Class requiredType);
ObjectProvider getBeanProvider(ResolvableType requiredType);
/**
判断工厂中是否包含给定名称的bean定义,若有则返回true
*/
boolean containsBean(String name);
/**
判断bean是否为单例
*/
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
/**
判断bean是否为多例
*/
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
/**
检查具有给定名称的bean是否匹配指定的类型。
*/
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, Class> typeToMatch) throws NoSuchBeanDefinitionException;
/**
返回给定名称的bean的Class,如果没有找到指定的bean实例,则排除*/
@Nullable
Class> getType(String name) throws NoSuchBeanDefinitionException;
/**
返回给定bean名称的所有别名
*/
String[] getAliases(String name);
}
使用场景从Ioc容器中获取Bean(byName or byType)
检索Ioc容器中是否包含指定的Bean
判断Bean是否为单例2 .FactoryBean
使用XML配置spring容器的时候,Spring通过反射机制利用
的class属性指定实现类实例化Bean,在某些情况下,实例化Bean过程比较复杂,如果按照传统的方式,则需要在 中提供大量的配置信息。配置方式的灵活性是受限的,比如一个类大量依赖了其他的对象属性,此时就算是使用自动装配,不需要再显式的写出bean之间的依赖关系,但是其依赖的对象也需要将其装配到spring容器中,也需要为它所依赖的多有对象都创建bean标签将他们注入,如果这个类依赖了上百个对象,那么这个工作量无疑是非常大的。 Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑。FactoryBean接口对于Spring框架来说占用重要的地位,Spring自身就提供了70多个FactoryBean的实现。它们隐藏了实例化一些复杂Bean的细节,给上层应用带来了便利。从Spring3.0开始,FactoryBean开始支持泛型,即接口声明改为FactoryBean
的形式。 Spring中共有两种bean,一种为普通bean,另一种则为工厂bean
以Bean结尾,表示它是一个Bean,不同于普通Bean的是:它是实现了FactoryBean
接口的Bean,根据该Bean的ID从BeanFactory中获取的实际上是FactoryBean的getObject()返回的对象,而不是FactoryBean本身,如果要获取FactoryBean对象,请在id前面加一个&符号来获取。
源码:public interface FactoryBean
{
//从工厂中获取bean
@Nullable
T getObject() throws Exception;
//获取Bean工厂创建的对象的类型
@Nullable
Class> getObjectType();
//Bean工厂创建的对象是否是单例模式
default boolean isSingleton() {
return true;
}
}从它定义的接口可以看出,FactoryBean表现的是一个工厂的职责。 即一个Bean A如果实现了FactoryBean接口,那么A就变成了一个工厂,根据A的名称获取到的实际上是工厂调用getObject()返回的对象,而不是A本身,如果要获取工厂A自身的实例,那么需要在名称前面加上'&'符号。
getObject('name')返回工厂中的实例
getObject('&name')返回工厂本身的实例区别:
BeanFactory 以Factory结尾,表示它是一个工厂类,用于管理Bean的一个工厂。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。该接口是IoC容器的顶级接口,是IoC容器的最基础实现,也是访问Spring容器的根接口,负责对bean的创建,访问等工作
对FactoryBean而言,以Bean结尾,说明这是一个交给容器去管理的bean。这个Bean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似。
三 . 理解Spring中ApplicationContext和BeanFactory以及FactoryBean1.BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化,这样,我们就不能发现一些存在的Spring的配置问题。而ApplicationContext则相反,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误。 相对于基本BeanFactory,ApplicationContext 唯一的不足是占用内存空间。当应用程序配置Bean较多时,程序启动较慢。
BeanFacotry延迟加载,如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常;而ApplicationContext则在初始化自身是检验,这样有利于检查所依赖属性是否注入;所以通常情况下我们选择使用 ApplicationContext。
应用上下文则会在上下文启动后预载入所有的单实例Bean。通过预载入单实例bean ,确保当你需要的时候,你就不用等待,因为它们已经创建好了。2.BeanFactory和ApplicationContext都支持BeanPostProcessor,BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册。(Applicationcontext比 beanFactory 加入了一些更好使用的功能。而且 beanFactory 的许多功能需要通过编程实现而 Applicationcontext 可以通过配置实现。比如后处理 bean , Applicationcontext 直接配置在配置文件即可而 beanFactory 这要在代码中显示的写出来才可以被容器识别。 )
3.beanFactory主要是面对与 spring 框架的基础设施,面对 spring 自己。而 Applicationcontex 主要面对与 spring 使用的开发者。基本都会使用 Applicationcontex 并非 beanFactory 。
4. BeanFactory是个bean 工厂,是一个工厂类(接口), 它负责生产和管理bean的一个工厂
是ioc 容器最底层的接口,是个ioc容器,是spring用来管理和装配普通bean的ioc容器(这些bean成为普通bean)。FactoryBean是个bean,在IOC容器的基础上给Bean的实现加上了一个简单工厂模式和装饰模式,是一个可以生产对象和装饰对象的工厂bean,由spring管理后,生产的对象是由getObject()方法决定的。