先定义一个 Cat 类:
public class Cat {
private int id;
private String name;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Cat{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
定义一个公共的 Bean:
@Component
public class CatBeans {
@Bean
public Cat cat() {
Cat cat = new Cat();
cat.setId(1);
cat.setName("喵喵喵");
cat.setAge(8);
return cat;
}
}
小明 在使用时,修改了 Bean:
@Controller
public class ScopeController {
@Autowired
private Cat cat;
public void doScope() {
System.out.println("Do scope controller.");
System.out.println("原数据:" + cat.toString());
// 修改
Cat cat2 = new Cat();
cat2.setName("喵喵");
System.out.println("修改之后的数据: " + cat2.toString());
}
}
我们之后如果还要用这个 Bean:
@Controller
public class ScopeController2 {
@Resource
private Cat cat;
public void doSCope(){
System.out.println("Do scope controller 2.");
System.out.println(cat.toString());
}
}
测试:
public class App {
public static void main(String[] args) {
// 1.得到 Spring 上下文对象
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");
ScopeController scopeController =
context.getBean("scopeController", ScopeController.class);
scopeController.doScope();
System.out.println();
ScopeController2 scopeController2 =
context.getBean("scopeController2", ScopeController2.class);
scopeController2.doSCope();
System.out.println();
}
}
Spring 中 Bean 默认情况下是单例模式,即 cat 和 cat1 都指向了同一块区域,我们无论是修改 cat 还是 cat1 都会对这个 Bean 造成修改。
Bean 在 Spring 整个框架中的某种⾏为模式,⽐如 singleton 单例作⽤域,就表示 Bean 在整个 Spring 中只有⼀份。
Spring 容器在初始化⼀个 Bean 的实例时,同时会指定该实例的作⽤域。Spring有 6 种作⽤域,
最后四种是基于 Spring MVC ⽣效的(主要学习前四种 作用域):
下面是官方的资料:
我们可以使用 @Scope 标签来声明 Bean 的作用域,代码如下:
@Component
public class MyComponent {
// @Scope("prototype")
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Bean(name = "c1")
public void doComponent1() {
System.out.println("Do user component1.");
}
}
使用 @Scope 标签声明 Bean 作用域的两种方式:
注意:
通过刚刚的学习,我们知道了:可以用 @Scope 标签来声明 Bean 作用域。我们之前也分析过,出现问题的原因,即 Spring 中默认为 单例作用域(singleton),那我们只需要将公共的 Bean 的作用域修改为 多例作用域(prototype)即可,修改如下:
@Component
public class CatBeans {
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Bean
public Cat cat() {
Cat cat = new Cat();
cat.setId(1);
cat.setName("喵喵喵");
cat.setAge(8);
return cat;
}
}
Bean 执⾏流程(Spring 执⾏流程):
Bean 生命周期:
以买房为例:
//@Component
public class BeanLifeComponent implements BeanNameAware {
public void setBeanName(String s) {
System.out.println("执行了 Bean Name 通知:" +
s);
}
/**
* 方法名随意定义
* xml中 init-method 指定的方法
*/
public void initMethod(){
System.out.println("执行了 init-method 方法");
}
/**
* 方法名随意定义
*/
@PostConstruct
public void myPostConstruct(){
System.out.println("执行了 PostConstruct 方法");
}
/**
* 销毁前执行方法
*/
@PreDestroy
public void myPreDestroy(){
System.out.println("执行了 PreDestroy 方法");
}
public void run(){
System.out.println("执行了 run 方法");
}
}
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"
xmlns:content="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
https://www.springframework.org/schema/context/spring-context.xsd">
<content:component-scan base-package="com.wzr"></content:component-scan>
<bean id="beanlife" class="com.wzr.controller.BeanLifeComponent"
init-method="initMethod"></bean>
</beans>
调用类:
public class App {
public static void main(String[] args) {
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");
BeanLifeComponent component =
context.getBean("beanlife",BeanLifeComponent.class);
component.run();
context.destroy();
}
}
这就是因为,我们初始化过程中,有很多的方法,这些方法可能会调用某个属性,如果没有设置属性,就会报错(空指向异常)