目錄
一. @Autowired 和 @Resource 注解
二. Bean的作用域?
1.?singleton(單例模式)
2.?prototype(原型模式)(多例模式)
3. 請求作用域:request
4. 會話作用域:session
三. Spring 的執(zhí)行流程
四. Bean 的生命周期?
?1. 實例化
?2. 設置屬性?
3. Bean 初始化??
? ?3.1 執(zhí)行各種各種 Aware 通知;?
? ?3.2 執(zhí)行初始化前置方法;
? ?3.3 執(zhí)行初始化方法;
? ?3.4 執(zhí)行初始化后置方法;?
4. 使用 Bean 對象
5. 銷毀 Bean 對象?
6. 代碼演示?
一. @Autowired 和 @Resource 注解
在前面的文章中,我們介紹了通過 @Autowired 注解的方式來獲取到Spring容器中的Bean對象,實際上,還有另一個注解:@Resource,它的功能也是差不多的,也可以從 Spring容器中獲取到Bean對象,但也是存在一定的差別的。?
- @Resource 來自于 jdk,而 @Autowired 來自于 Spring;
-
使?時設置的參數(shù)不同:相?于 @Autowired 來說,@Resource ?持更多的參數(shù)設置,例如name 設置,根據(jù)名稱獲取 Bean;
-
@Autowired 可?于 Setter 注?、構造函數(shù)注?和屬性注?,? @Resource 只能?于 Setter 注?和屬性注?,不能?于構造函數(shù)注?;
-
@Autowired在獲取Bean對象的時候,先根據(jù)類型查找,之后再根據(jù)名稱查找;而@Resource先根據(jù)名稱查找,之后再根據(jù)類型查找;
問題分析:當在 Spring 中存放多個同一類型 Bean 對象的時候,使用 @Autowired 去獲取 Bean對象會出錯。
@Component
public class UserBeans {
@Bean
public User user1(){
User user = new User();
user.setAge(20);
user.setId(1);
user.setName("張三");
return user;
}
@Bean
public User user2(){
User user = new User();
user.setAge(22);
user.setId(11);
user.setName("李四");
return user;
}
}
@Controller
public class UserController2 {
@Autowired
private User user;
public void sayHi(){
System.out.println("do UserController2");
System.out.println(user.getName());
}
}
public class App {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
UserController2 userController2 = context.getBean("userController2",UserController2.class);
userController2.sayHi();
}
}
此時執(zhí)行是會報錯的,因為 @Autowired 注解先通過類型去查找,得到了 user1 和 user2 兩個 Bean對象,但是根據(jù) user 名稱來去查找的話,是沒有找到對應的 Bean 對象的,因此會報錯。(查找 Bean 對象的默認名稱為 添加 @Autowired 注解的對應屬性名稱,也就是上述第二段代碼的private User user)?
?解決辦法1:修改 @Autowired 注解的對應屬性名稱
@Controller
public class UserController2 {
@Autowired
private User user1;
public void sayHi(){
System.out.println("do UserController2");
System.out.println(user1.getName());
}
}
此時運行代碼就會獲取到對應的 Bean對象,也就是存儲的 user1 對象。
?
解決辦法2:配合使? @Qualifier 注解定義名稱
@Qualifier(value = "Bean對象的名稱")?
@Controller
public class UserController2 {
@Autowired
@Qualifier(value="user1")
private User user;
public void sayHi(){
System.out.println("do UserController2");
System.out.println(user.getName());
}
}
也可以得到預期的結果。?
?
解決辦法3:使? @Resource(name="Bean對象名稱") 定義
@Controller
public class UserController2 {
@Resource(name="user1")
private User user;
public void sayHi(){
System.out.println("do UserController2");
System.out.println(user.getName());
}
}
?同樣是可以得到預期結果的。
?
二. Bean的作用域?
限定程序中變量的可?范圍叫做作用域,或者說在源代碼中定義變量的某個區(qū)域就叫做作用域。而?Bean 的作?域是指 Bean 在 Spring 整個框架中的某種行為模式。
1.?singleton(單例模式)
singleton 表示的是單例作用域,類似于之前講過的單例模式。這也是默認情況下的行為模式。在該作用域下的 Bean 在 IoC容器中只存在一個實例,獲取到的 Bean 以及對 Bean 進行修改,都是針對同一個 Bean 對象。
代碼演示:?
1. 往 Spring 容器中注入一個 User 對象?
@Component
public class UserBeans {
@Bean
public User user(){
User user = new User();
user.setId(1);
user.setName("張三");
return user;
}
}
2.? 通過@Autowired獲取到Bean對象,并對其進行修改
@Controller
public class UserController {
@Autowired
private User user;
public void printUser(){
System.out.println(user);
// 修改 User
User myUser = user; // 給引用對象賦值,其實就是共享對象?。?!這兩個變量指向了同一個地址
myUser.setName("李四");
System.out.println("myUser -> " + myUser);
System.out.println("User -> " + user);
}
}
3. 再新建一個類,通過 @Autowired 獲取到Bean對象?
@Controller
public class UserController2 {
@Resource
private User user;
public void printUser2(){
System.out.println("user -> " + user);
// Bean 作用域 -> 默認是單例模式 = 此 Bean 在整個框架(Spring 容器)中只有一份
}
}
?4. 最后輸出觀察結果
public class App {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");
UserController userController = context.getBean("userController",UserController.class);
userController.printUser();
UserController2 userController2 = context.getBean("userController2",UserController2.class);
userController2.printUser2();
}
}
因此也可以得出結論:singleton 單例作用域,他們使用的 Bean 都是 Spring 容器中的同一個對象。這個 Bean 在整個 Spring 中只有一份,是全局共享的,當其他人修改了這個值之后,那么另一個人讀到的就是被修改后的值了。
2.?prototype(原型模式)(多例模式)
?在原型模式下,每次對該作用域下的 Bean 的請求都會創(chuàng)建新的實例,也就是說每次獲取 Bean 對象和修改 Bean 對象都是針對新的 Bean 對象實例而言的。
需要添加注解 @Scope("prototype") 或者@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
代碼演示:?
@Component
public class UserBeans {
@Bean
@Scope("prototype")
//@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public User user(){
User user = new User();
user.setId(1);
user.setName("張三");
return user;
}
}
?再次運行得到結果:
可以看出,在第二次通過 @Autowired 獲取到 Bean 對象的時候,得到的是一個新的實例對象了。
3. 請求作用域:request
?每次 http 請求會創(chuàng)建新的 Bean 實例。適用于?次 http 的請求和響應的共享 Bean 的情況。
?限定SpringMVC中使?。
4. 會話作用域:session
在?個http session中,定義?個 Bean 實例。每次 Session 會話共享一個 Bean 對象。限定SpringMVC中使?。
?文章來源地址http://www.zghlxwxcb.cn/news/detail-439344.html
三. Spring 的執(zhí)行流程
?
?
四. Bean 的生命周期?
?1. 實例化
給 Bean 對象分配內(nèi)存空間。?
此處要注意:初始化不等于實例化?。?!
類的初始化是完成程序前的準備工作,在這個階段,靜態(tài)的會被執(zhí)行,同時會開辟一塊存儲空間用來存放靜態(tài)的數(shù)據(jù),初始化只在類加載的時候執(zhí)行一次,也可以理解為給對象賦值的過程。
類的實例化,是指創(chuàng)建一個對象的過程,這個過程會在堆中開辟內(nèi)存,將一些非靜態(tài)的方法,變量存放在里面,在程序執(zhí)行的過程中,可以創(chuàng)建多個對象,即多次實例化,每次實例化都會開辟一塊新的內(nèi)存。?
?2. 設置屬性?
看需求,有的 Bean 對象需要被注入屬性,這個屬性也會是已經(jīng)在 Spring 容器中的 Bean,如果該屬性還不存在于 Spring 中,那么會先去將該屬性 Bean 存儲到 Spring 中。?
3. Bean 初始化??
? ?3.1 執(zhí)行各種各種 Aware 通知;?
實現(xiàn)了各種 Aware 通知的?法,如 BeanNameAware、BeanFactoryAware、ApplicationContextAware 的接??法;
? ?3.2 執(zhí)行初始化前置方法;
? ?3.3 執(zhí)行初始化方法;
有兩種方式,第一種是通過注解?@PostConstruct?,依賴注?操作之后執(zhí)行注解修飾的方法;第二種是通過 xml 的方式,執(zhí)行自己指定的 init-method ?法。如果兩者都存在,那么先執(zhí)行注解的初始化方法。
?
? ?3.4 執(zhí)行初始化后置方法;?
?
4. 使用 Bean 對象
通過 getBean() 方法來獲取容器中的 Bean 對象并使用。?
5. 銷毀 Bean 對象?
銷毀容器的各種?法,如 @PreDestroy、DisposableBean 接??法、destroy-method(XML的方式)。 ?
6. 代碼演示?
public class App {
public static void main(String[] args) {
// 此時要使用 ApplicationContext 的子類,因為它本身是沒有銷毀方法的
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
BeanComponent beanComponent = context.getBean("beanComponent",BeanComponent.class);
beanComponent.sayHi();
context.close();
}
}
public class BeanComponent implements BeanNameAware {
@Override
public void setBeanName(String s) {
System.out.println("執(zhí)行了通知 BeanName -> " + s);
}
/**
* xml 方式的初始化方法
*/
public void myInit(){
System.out.println("XML 方式初始化");
}
@PostConstruct
public void doPostConstruct(){
System.out.println("注解的初始化方法");
}
public void sayHi(){
System.out.println("執(zhí)行 sayHi()");
}
// 銷毀的方法,銷毀的時候執(zhí)行的一個方法
@PreDestroy
public void doPreDestroy(){
System.out.println("do PreDestroy");
}
}
?文章來源:http://www.zghlxwxcb.cn/news/detail-439344.html
?
到了這里,關于@Autowired和@Resource注解之間的關系區(qū)別,Bean的作用域和生命周期,Spring的執(zhí)行流程的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!