網站建設崗位工作范圍怎樣注冊網站建立網頁
作者:~小明學編程?
文章專欄:Spring框架
格言:熱愛編程的,終將被編程所厚愛。
目錄
Spring更加高效的讀取和存儲對象
存儲bean對象
五大注解
關于五大類注解
對象的注入
屬性注入
構造方法注入
Setter注入
三種注入方式的區(qū)別
@Resource 和 @Autowired 的區(qū)別
Bean的作用域和生命周期
Spring的執(zhí)行流程
Bean的生命周期
Spring更加高效的讀取和存儲對象
存儲bean對象
前面我們所介紹的方法過于的繁瑣,我們可以通過注解來快速實現上述的功能。
<?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.beans"></content:component-scan>
</beans>
首先是我們所依賴的資源,其中com.beans是我們所要掃描的類的包。
五大注解
- Controller 控制器
- Service 服務
- Repository 倉庫
- Configuration 配置
- Component 組件
利用上面這五大注解都可以完成我們對象的注入。
@Service
public class UserService {public void sayHi() {System.out.println("hi Service");}
}
@Repository
public class UserRepository {public void sayHi() {System.out.println("Hi Res");}
}
@Controller
public class UserController {public void sayHi() {System.out.println("hello");}
}
@Configuration
public class UserConfig {public void sayHi() {System.out.println("Hi Con");}
}
@Component
public class UserComponent {public void sayHi() {System.out.println("Hi Com");}
}
獲取:
public static void main1(String[] args) {//1.獲取上下文ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");//2.得到beanUserController userController = context.getBean("userController",UserController.class);userController.sayHi();UserService userService = context.getBean("userService",UserService.class);userService.sayHi();UserRepository userRepository = context.getBean("userRepository",UserRepository.class);userRepository.sayHi();UserConfig userConfig = context.getBean("userConfig",UserConfig.class);userConfig.sayHi();UserComponent userComponent = context.getBean("userComponent",UserComponent.class);userComponent.sayHi();}
獲取的時候我們需要注意這個beanname,這個beanname是根據如下的邏輯。
關于五大類注解
既然我們五種注解的隨便一種都能完成我們的對象的注入,那么我們?yōu)槭裁催€是需要五種注解呢
?因為我們一個軟件是分為多個層面的,分為多層有助于我們的管理和控制。
Configuration 就是配置層:關于當前項目中的所有配置,都會寫在這個文件夾里。
Controller 就是控制層:就是前端參數校驗,主要就是校驗前端數據的合理性和正確性。
Service 就是服務層,負責數據的組裝和接口調用。更直白的說,服務器九四 “牽線搭橋” 讓程序去調用對應的功能/接口/服務。
Repository 叫做倉庫,但其實是 數據持久層,也叫做 Dao 層,就是對數據進行持久化操作(對數據庫進行增刪改查操作)。
我們使用不同的注解便于我們了解不同的代碼的功能同時也方便我們對代碼進行一個管理。
當然這五大類注解之間是有一定的關系的:
?可以看到我們的configuration注解是調用了我們的component注解的,其它幾個注解的實現方法也是如此,可以說我們的component注解是我們其它四大注解的一個父類。
對象的注入
前面我們了解了怎么樣將對象給存儲起來,也就是使用五大注解可以高效方便的將我們的對象給放在spring中,但是當我們想要使用的時候有沒有什么方式可以比較高效的來使用呢,下面就介紹三種方式來實現我們對象的一個注入。
屬性注入
通過 @Autowired 注入:
@Controller
public class UserController {@Autowiredprivate UserService userService;public void sayHi() {userService.sayHi();}
}
這里我們就通過關鍵字Autoeired的關鍵字來直接實現我們對象的一個注入,然在下面的方法之中我們就可以直接調用我們注入好的對象的方法了。
public static void main(String[] args) {//1.獲取上下文ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");UserController userController = context.getBean(UserController.class);userController.sayHi();//hi Service}
構造方法注入
@Controller
public class UserController {
// @Autowiredprivate UserService userService;public UserController(UserService userService) {this.userService = userService;}public void sayHi() {userService.sayHi();}
}
這里我們可以直接通過構造方法的方式來進行對象的一個注入,但是值得我們注意的是,當我們的構造方法不止一個的時候就必須要使用Autowired關鍵字了,不然會報錯。
@Controller
public class UserController {
// @Autowiredprivate UserService userService;@Autowiredpublic UserController(UserService userService) {this.userService = userService;}public UserController(UserService userService,int num) {this.userService = userService;}public void sayHi() {userService.sayHi();}
}
Setter注入
@Controller
public class UserController {private UserService userService;@Autowiredpublic void setUserService(UserService userService) {this.userService = userService;}public void sayHi() {userService.sayHi();}
}
同樣我們也可以使用Setter這樣一個方法來進行一個注入。
三種注入方式的區(qū)別
- 屬性注入特點是寫法簡單,但是通用性不好,只能運行在 IoC 容器下,如果是 非 IoC 容器的話,就會出現問題。
- 構造方法注入,通用性更好。因為構造方法的優(yōu)先級是最高的。確保使用注入對象之前,對象一定初始化過了。當構造方法注入參數太多時,就需要檢查自己的代碼是否符合單一設計原則的規(guī)范了。構造方法注入,也是 Spring 推薦的注入方法。
- Setter 注入是早期 Spring 版本推薦的寫法,但是通用性沒有構造方法注入通用,因為只有一個參數。
@Resource 和 @Autowired 的區(qū)別
相同點:都可以完成對象的注入。
不同點:
- 出身不同,@Resource 來自于 JDK,@Autowired 是由 Spring 框架提供的。
- @Autowired 支持屬性注入,構造方法注入 和 Setter 注入,而 @Resource 不支持構造方法注入。
- 支持的參數不同:@Resource 支持更多的參數設置,比如 name、type 設置。而 @Autowired 只支持 required 參數設置。
Bean的作用域和生命周期
在我們使用bean的時候其實默認是用的同一個bean也就是說如果我們對其中的bean進行一個更改的話,那么當我們再次去使用這個bean此時依然是更改之后的bean。
@Component
public class UserBean {@Bean(name = {"user","user1"})
// @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)public User user2() {User user = new User(15,"lisi");return user;}@Bean(name = {"user2"})public User user1() {User user = new User(12,"zhangsan");return user;}
}
@Component
public class BeanScope1 {@Autowiredprivate User user2;public User getUser() {user2.setStr("aaa");return user2;}
}
@Component
public class BeanScope2 {@Autowiredprivate User user2;//user2必須事被注入過的public User getUser() {return user2;}
}
這個時候我們注入了兩次bean對象,此時查看輸入的結果:
public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");BeanScope1 beanScope1 = context.getBean(BeanScope1.class);System.out.println(beanScope1.getUser());BeanScope2 beanScope2 = context.getBean(BeanScope2.class);System.out.println(beanScope2.getUser());}
?可以看到我們在對其進行更改之后,再次注入仍然是更改之后的User。
產生這樣的原因是因為 Bean 在 Spring 中,默認情況下是單例狀態(tài),也就是所有人的使用都是同一個對像。這樣可以很好的節(jié)約資源,避免資源的浪費。
Bean 的六種作用域
singleton:單例作用域(默認)在這種模式下的 Bean 在 IoC 容器里面,只存在一個實例。
prototype:原型作用域(多例模式)每次對作用域下的 Bean 請求,都會創(chuàng)建新的實例,然后再去獲取 Bean。
request:請求作用域(Spring MVC)每次 Http 請求會創(chuàng)建新的 Bean 實例,類似于 prototype。
session:會話作用域(Spring MVC)在一個 http session 中,定義一個 Bean 實例。記錄用戶的登錄信息。
application:全局作用域(Spring MVC)更多人使用的時候,就用 application。也是單例模式,應用在 Web 應用的上下文信息。
websocket:Http WebSocket 作用域(Spring WebSocket)在 WebSocket 會話中使用。
?
當我們想要改變其作用域的時候可以通過@Scope?的注解來進行改變
可以看到此時我們 所注入的對象就都是新的對象了。
設置作用域的時候,只需要通過 @Scope 注解就可以了:
- 直接設置值:@Scope(“prototype”)
- 使用枚舉設置:@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
Spring的執(zhí)行流程
1.我們首先是要啟動我們的容器,去加載我們的配置文件。
也就是我們上面的這段代碼。
2.接著就是根據我們的配置來完成我們的bean初始化。
?通過掃描包中的spring注解。
3.注冊 Bean 對象到容器中,只有在包掃描的路徑上的類,且使用 Spring 的注解才可以被注冊到容器當中。
?4.裝配 Bean 屬性,也就是把 Bean 注冊到其他類當中:
Bean的生命周期
Bean的生命周期就是Baen從誕生到銷毀的一個過程 。
- 實例化 Bean(為 Bean 分配內存空間)
- 設置屬性(Bean 注入和裝配)
- Bean 初始化? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?a)執(zhí)行各種通知(各種Aware)如:BeanNameAware,BeanFactoryAware,ApplicationContextAware 的接口方法。
b)執(zhí)行 BeanPostProcessor 初始化前置方法。
c)執(zhí)行 @PostConstruct 初始化方法,依賴注入操作之后被執(zhí)行。
d)執(zhí)行自己指定的 init-method 方法(如果有指定的話
e)執(zhí)行 BeanPostProcessor 初始化后置方法。 - 使用 Bean
- 銷毀 Bean,通過方法來銷毀容器:如 @PreDestroy、DisposableBean、destroy-method
其大概的流程圖就是這樣的。
<?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.beans"></content:component-scan><bean id="beanLife"class="com.beans.BeanLife" init-method="init"></bean>
</beans>
package com.beans;import org.springframework.beans.factory.BeanNameAware;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;/*** Created with IntelliJ IDEA.* Description:* User: 86184* Date: 2023-03-06* Time: 22:07*/
@Component
public class BeanLife implements BeanNameAware {@PostConstructpublic void Post() {System.out.println("PostConstruct");}@PreDestroypublic void Pre() {System.out.println("pre");}public void use() {System.out.println("use");}public void init() {System.out.println("init");}public void setBeanName(String s) {System.out.println("通知");}
}
?執(zhí)行流程如上。