Bean对象的作用域和生命周期
文章目录:一.Bean的作用域 (1)Bean作用域的含义
(2)Bean的6种作用域
二.Bean的生命周期(1)开辟内存空间
(2) 属性注入
(3)初始化
(4)使用Bean
(5)销毁Bean对象
一.作用域
作用域含义:
Bean的作用域是指Bean在Spring整个框架中的某种行为模式
下面我们通过具体的代码来演示:
我们先来创建一个User类
@Component
public class User3 {public String name;public int age;}
然后通过在方法上添加Bean注解的方式在Spring容器里添加一个user对象
@Component
public class Signal { @Bean(value = "user1")public User3 getuser1(){User3 user=new User3();user.name="小众";user.age=7;return user;}
}
然后在创建两个类,然后把user对象注入到这个类里面,并且在第一个类里面我们把user的name改动
@Component
public class Useuser1 {@Resource(name="user1")public User3 user;public void say(){System.out.println(user.name);user.name="小莲";System.out.println(user.name);}
}
@Component
public class Useuser2 {@Resource(name="user1")public User3 user;public void say(){System.out.println(user.name);}
}
我们分别再启动类里面去运行,看一下打印结果
public static void main(String[] args) {ApplicationContext context=new ClassPathXmlApplicationContext("spring-conflig.xml");Useuser1 user=context.getBean("useuser1",Useuser1.class);user.say();Useuser2 user2=context.getBean("useuser2",Useuser2.class);user2.say();}
我们发现我们只是在Useuser1里面把user对象的名字给改了,但是Useuser2这个类里面的user对象的名字也发生了变化,这时因为默认情况下是单例模式,也就是同一个user对象只初始化一次,这个对象只有一份,是全局共享的,这两个类里面注入的对象是一份。
那可不可以两个类里面注入的对象存在多份,相互不影响呢?其实我们只需要通过添加Scope注解的方式,将模式改为多例作用域即可, prototype即为多例作用域
@Component
public class Signal {@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)@Bean(value = "user1")public User3 getuser1(){User3 user=new User3();user.name="小众";user.age=7;return user;}
}
这时我们再来观察结果:
这时我们发现两个类里面注入的相同对象就不会互相影响了,
多例作用域:当我们多次注入同一个对象的时候,我们拿到的其实是最初的对象的拷贝,不同类里面注入的对象是多份,所以互不影响。
Bean的6种作用域:
1.sigleton:单例作用域 只存在一个实例,Spring默认选择改作用域
2.prototype 多例作用域: 存在多个实例,每次Bean请求都会创建新的实例,
3.request 请求作用域:每次htttp请求都会创建新的Bean实例,类似于prototype,限定于SpringMVC中使用
4.session 会话作用域: 在一个http session中,定义一个Bean实例,限定在SpringMVC中使用
5.application 全局作用域 在一个http servlet Context中,定义一个Bean实例,限定在SpringMVC中使用
6.websocket : 在一个http WebSocket的生命周期中,定义一个Bean实例,限定在Spring WebSocket中使用
单例作用域与全局作用域区别:
singleton是 Spring Core的作用域; application 是spring web 中的容器
singleton 作用 于IOC容器,而application作用于 Servelt容器
二.Bean的生命周期
1.先为Bean分配内存空间,Bean对象的实例化
2.设置属性(注入属性)
3.初始化
(1)实现了各种Aware通知的方法,比如BeanNameAware、BeanFactoryAware
(2)初始化前置方法
(3)初始化方法(两种方式,xml方式和注解方式(PostConstruct))
(4) 执行自己指定的init-method方法
(5)初始化后置方法
4.使用Bean
5.销毁Bean对象
我们具体通过代码的形式来演示Bean的生命周期这一流程
在xml文件里注册beanlife对象,并且设置了一个自定义方法init
<bean id="beanlife" class="kale.pole.Beanlife" init-method="init" > </bean>
@Component
public class Beanlife implements BeanNameAware {自定义的方法public void init() {System.out.println("执行 xml初始化方法");}//表示具体使用Beanpublic void say() {System.out.println("执行say方法");}@PostConstruct //构造方法public void myinit() {System.out.println("执行了注解初始化方法");}@PreDestroy //摧毁beanpublic void preDestroy() {System.out.println("执行 preDestory方法");}@Override //BeanName的通知public void setBeanName(String s) {System.out.println("执行了setBeanName方法:" + s);}
}
我们启动一下这个程序,注意 这里不要再用ApplicationContext这个类了,因为这个类里面没有pre
Destory这个方法,我们用它的子类
public static void main(String[] args) {ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("spring-conflig.xml");Beanlife bean=context.getBean("beanlife",Beanlife.class);bean.say();bean.preDestroy();}
这里再强调一个问题:为什么属性注入要在初始化之前?这是因为如果一个类里面有依赖的对象的时候,我们在执行这个类的时候,需要先把这个对象给赋值。
例如如下代码:
@Component
public class UsePolice3 {public Police police;@Autowiredpublic UsePolice3(Police police){this.police=police;}public void getpolice(){police.say();}}