一文帶你了解Spring中存入Bean和獲取Bean的方式
0. Spring中的五大注解
上圖中就是五大類注解對應的層,通過源碼可以看到其他四個注解都基于@Conponent
1. 存入 Bean
Spring既然是一個包含眾多工具方法的IoC容器,它是一個控制反轉(zhuǎn)的容器,所以就需要將Bean對象存入到容器中,需要用的時候從容器中獲取Bean對象,下面我們來介紹下存入Bean對象。
1.1 在 xml 中存入 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"> // 這句代碼中, id 就是給 這個要注入的對象取個名字, class就是 要存入的 Bean 的類型是哪一個 <bean id = "user" class="com.java.demo.User"></bean> </beans>
1.2 通過配置 Bean 掃描路徑 + 類注解 實現(xiàn) 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.java.demo"></content:component-scan> </beans>
配置了 Bean 的掃描路徑,只有當前目錄下的類才會被掃描是否加了類注解,如果加了類注解后,就會將 所有加了類注解的類 存入到 IoC容器中。
@Component public class User { public void say(){ System.out.println("Hello User..."); } }
類注解存Bean需要注意幾點
- 如果類名為大駝峰命名規(guī)則,那么獲取 Bean 的默認名稱,就是 類名首字母小寫
- 如果不滿足首字母大寫,第二個字母小寫,那么 Bean 的名稱,就是原類名,這點可以看源碼知道
1.3 通過配置 Bean 掃描路徑 + 方法注解 實現(xiàn) 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.java.demo"></content:component-scan> </beans>
public class Student { private String name; private Integer age; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
@Component public class User { @Bean public Student student(){ Student student = new Student(); student.setName("張三"); student.setAge(18); return student; } public void say(){ System.out.println("Hello User..."); } }
在上述代碼中,我們可以通過 在方法上 加上 @Bean 注解 將該方法存入到 IoC 容器中,并且可以直接獲取到該對象。
在使用 @Bean 注解的時候,需要注意幾點
- @Bean 注解必須配合 五大類注解一塊使用
- @Bean 注解的默認命名 = 方法名稱
- 如果使用 @Bean(“xxxx”)方式,那么名稱就是 xxxx, 并且 @Bean({“xxx”,“xxxxx”,“xxxxxx”}),里面可以類似和數(shù)組一樣多個名稱
- 如果@Bean重命名后,那么默認的方法名就沒用,獲取Bean的時候就不能寫默認方法名
- 如果多個 Bean 使用相同的名稱,則不會報錯,只會存儲第一個 Bean對象,之后相同名稱的不會存入,會自動忽略
2. 獲取 Bean
2.1 依賴查找(DF)
依賴查找(依賴Bean的名稱),有兩種方式,一種是 ApplicationContext, 一種是 BeanFactory。這兩種都是容器管理對象,都可以獲取到 Bean對象
2.1.1 ApplicationContext
public class App { public static void main(String[] args) { // 1. 獲取 Spring 上下文對象 ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml"); // 2。獲取 Bean 對象 Student student = (Student) context.getBean("student"); System.out.println(student); } }
2.1.2 BeanFactory
public static void main(String[] args) { // 1. 得到 spring 上下文對象 BeanFactory context = new XmlBeanFactory(new ClassPathResource("spring-config.xml")); // 2. 獲取 Bean 對象 //Student student = (Student)context.getBean("user"); Student student = (Student)context.getBean("student"); System.out.println(student.toString()); }
2.1.3 Application VS BeanFactory
ApplicationContext | BeanFactory |
---|---|
ApplicationContext是BeanFactory的子類,其擁有更多功能(國際化支持、資源訪問支持、事件傳播) | BeanFactory是ApplicationContext的父類 |
ApplicationContext加載Bean:一次性加載所有Bean對象 | BeanFactory加載Bean:懶加載,按需加載(使用一個加載一個) |
2.2 依賴注入(DI)
在 spring 中實現(xiàn)依賴注入的常見方式有3種:
- 1.屬性注入
- 2.setter注入
- 3.構(gòu)造方法注入
2.2.1 屬性注入
@Controller public class UserController { /** * 屬性注入 */ @Autowired private UserService userService; // 此處 main方法里面,必須使用依賴查找的方式,先獲取到UserController public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml"); UserController userController = (UserController) context.getBean("userController"); userController.userService.say(); } }
屬性注入:
優(yōu)點: 實現(xiàn)簡單、使用簡單,只需要在屬性上加一個注解@Autowired,就不需要自己new一個對象,直接獲得注入的對象。
缺點:
- 無法注入一個用 final 修飾的對象
- 因為在Java語法中,final修飾的對象(不可變),要么一開始就賦值,要么在構(gòu)造方法里面賦值。而上述使用屬性注入,注入final修飾的對象,就不符合規(guī)范,所以不行。
- 只能適用于 IoC 容器:如果將這些代碼放到其他非IoC容器中,那么代碼就會失效
- 設(shè)計原則:更容易違背單一原則,因為屬性注入比較簡單,那么可能就會在一個類中注入多個對象,這就可能不符合程序的單一職責問題。
2.2.2 Setter注入
@Controller public class UserController2 { private UserService userService; /** * setter注入 */ @Autowired public void setUserService(UserService userService) { this.userService = userService; } public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml"); UserController2 userController2 = (UserController2) context.getBean("userController2"); userController2.userService.say(); } }
優(yōu)點:似乎沒什么優(yōu)點,而且比屬性注入更加麻煩,要說唯一可能有用的就是,完全符合單一職責設(shè)計原則,每個 setter 只針對一個對象。Setter注入 也適用于非IoC容器
缺點:
- 不能注入 final 對象
- 由于是 Setter 注入,提供了 set 方法,那么注入的對象可以隨時被更改
2.2.3 構(gòu)造方法注入(Spring4.x之后推薦的)
@Controller public class UserController3 { private final UserService userService; /** * 構(gòu)造方法注入 */ // @Autowired 此處如果構(gòu)造方法參數(shù)只有一個的時候,該注解可有可無 public UserController3(UserService userService) { this.userService = userService; } public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml"); UserController3 userController3 = (UserController3) context.getBean("userController3"); userController3.userService.say(); } }
優(yōu)點:
- 可以注入 被final 修飾的對象
注入對象不會被更改,因為是在構(gòu)造方法注入的,構(gòu)造方法在對象創(chuàng)建的時候只會創(chuàng)建一次
注入的對象會被完全初始化
通用性會更好,無論在 IoC容器 還是 非 IoC容器中都能用
缺點:
- 寫法更加復雜
- 使用構(gòu)造方法,無法解決循環(huán)依賴的問題
Spring官方推薦的是構(gòu)造方法的注入,可以注入不可變對象,通用性更好;如果想要注入可變對象,那么可以使用 Setter 注入。
3. 解決同一類型多個 Bean 的報錯問題
上述代碼,可以看到報錯,出現(xiàn)了多個同一類型的多個Bean報錯,需要1個,找到了2個。如何解決呢
- 1.@Autowired 配合 @Qualifier(value = “xxx”)一起使用,里面參數(shù)加方法名字
- 2.使用@Resource(name = “xxxx”)
4. @Resource 和 @Autowired
出身不同:@Resource來自于JDK,@Resource來自于Spring
支持參數(shù)不同:@Resource支持更多的參數(shù)
@Autowired只支持一個參數(shù)設(shè)置
使用上的區(qū)別:@Resource不支持構(gòu)造方法的注入
兼容性問題:@Autowired在社區(qū)版 IDEA可能會誤報;
以上就是一文帶你了解Spring中存入Bean和獲取Bean的方式的詳細內(nèi)容,更多關(guān)于Spring存入和獲取Bean方式的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java異常鏈表throw結(jié)構(gòu)assert詳細解讀
這篇文章主要給大家介紹了關(guān)于Java中方法使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-08-08SpringBoot項目打包發(fā)布到外部tomcat(出現(xiàn)各種異常的解決)
這篇文章主要介紹了SpringBoot項目打包發(fā)布到外部tomcat(出現(xiàn)各種異常的解決),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-09-09