先定义一个 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;}@Overridepublic String toString() {return "Cat{" +"id=" + id +", name='" + name + '\'' +", age=" + age +'}';}
}
定义一个公共的 Bean:
@Component
public class CatBeans {@Beanpublic Cat cat() {Cat cat = new Cat();cat.setId(1);cat.setName("喵喵喵");cat.setAge(8);return cat;}
}
小明 在使用时,修改了 Bean:
@Controller
public class ScopeController {@Autowiredprivate 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 {@Resourceprivate 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)@Beanpublic 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 方法");}/*** 方法名随意定义*/@PostConstructpublic void myPostConstruct(){System.out.println("执行了 PostConstruct 方法");}/*** 销毁前执行方法*/@PreDestroypublic void myPreDestroy(){System.out.println("执行了 PreDestroy 方法");}public void run(){System.out.println("执行了 run 方法");}
}
xml配置:
调用类:
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();}
}
这就是因为,我们初始化过程中,有很多的方法,这些方法可能会调用某个属性,如果没有设置属性,就会报错(空指向异常)