如何獲取所有spring管理的bean
獲取所有spring管理的bean
本文我們探索使用不同的方式獲取spring容器中所有bean。
IOC容器
bean是基于spring應(yīng)用的基礎(chǔ),所有bean都駐留在ioc容器中,由容器負(fù)責(zé)管理bean生命周期
有兩種方式可以獲取容器中的bean:
- 使用ListableBeanFactory接口
- 使用Spring Boot Actuator
使用ListableBeanFactory接口
ListableBeanFactory接口提供了getBeanDefinitionNames() 方法,能夠返回所有定義bean的名稱。該接口被所有factory實(shí)現(xiàn),負(fù)責(zé)預(yù)加載bean定義去枚舉所有bean實(shí)例。官方文檔提供所有其子接口及其實(shí)現(xiàn)。
下面示例使用Spring Boot 構(gòu)建:
首先,我們創(chuàng)建一些spring bean,先定義簡(jiǎn)單的Controller FooController:
@Controller
public class FooController {
@Autowired
private FooService fooService;
@RequestMapping(value="/displayallbeans")
public String getHeaderAndBody(Map model){
model.put("header", fooService.getHeader());
model.put("message", fooService.getBody());
return "displayallbeans";
}
}
該Controller依賴另一個(gè)spring Bean FooService:
@Service
public class FooService {
public String getHeader() {
return "Display All Beans";
}
public String getBody() {
return "This is a sample application that displays all beans "
+ "in Spring IoC container using ListableBeanFactory interface "
+ "and Spring Boot Actuators.";
}
}
我們創(chuàng)建了兩個(gè)不同的bean:
1.fooController
2.fooService
現(xiàn)在我們運(yùn)行該應(yīng)用。使用applicationContext 對(duì)象調(diào)用其 getBeanDefinitionNames() 方法,負(fù)責(zé)返回applicationContext上下文中所有bean。
@SpringBootApplication
public class Application {
private static ApplicationContext applicationContext;
public static void main(String[] args) {
applicationContext = SpringApplication.run(Application.class, args);
displayAllBeans();
}
public static void displayAllBeans() {
String[] allBeanNames = applicationContext.getBeanDefinitionNames();
for(String beanName : allBeanNames) {
System.out.println(beanName);
}
}
}
會(huì)輸出applicationContext上下文中所有bean:
fooController
fooService
//other beans
需注意除了我們定義的bean外,它還將打印容器中所有其他bean。為了清晰起見,這里省略了很多。
使用Spring Boot Actuator
Spring Boot Actuator提供了用于監(jiān)視應(yīng)用程序統(tǒng)計(jì)信息的端點(diǎn)(endpoint)。除了/beans,還包括很多其他端點(diǎn),官方文檔有詳細(xì)說明。
現(xiàn)在我們?cè)L問url: http//
:/beans,如果沒有指定其他獨(dú)立管理端口,我們使用缺省端口,結(jié)果會(huì)返回json,包括容器所有定義的bean信息:
[
{
"context": "application:8080",
"parent": null,
"beans": [
{
"bean": "fooController",
"aliases": [],
"scope": "singleton",
"type": "com.baeldung.displayallbeans.controller.FooController",
"resource": "file [E:/Workspace/tutorials-master/spring-boot/target
/classes/com/baeldung/displayallbeans/controller/FooController.class]",
"dependencies": [
"fooService"
]
},
{
"bean": "fooService",
"aliases": [],
"scope": "singleton",
"type": "com.baeldung.displayallbeans.service.FooService",
"resource": "file [E:/Workspace/tutorials-master/spring-boot/target/
classes/com/baeldung/displayallbeans/service/FooService.class]",
"dependencies": []
},
// ...other beans
]
}
]
當(dāng)然,結(jié)果同樣包括很多其他的bean,為了簡(jiǎn)單起見,這里沒有列出。
小結(jié)一下
上面介紹了使用ListableBeanFactory 接口和 Spring Boot Actuators 返回spring 容器中所有定義的bean信息。
spring管理bean的原理
Spring容器默認(rèn)情況下,當(dāng)服務(wù)啟動(dòng)時(shí),解析配置文件,實(shí)例化文件中的所有類。
使用spring時(shí),獲取spring注入的bean是這樣
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");
MyService myService1 = (MyService) ctx.getBean("myService");
那下面我們模擬spring管理bean這個(gè)的過程
代碼如下:
1.第一步,創(chuàng)建java project,引入spring.jar
2.創(chuàng)建spring.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
</beans>
3.創(chuàng)建接口MyService,只需要一個(gè)測(cè)試方法save
4.創(chuàng)建實(shí)現(xiàn)類MyServiceImpl,控制臺(tái)輸出一句話
5.創(chuàng)建一個(gè)自己的解析類MyClassPathXmlApplicationContext
主要是構(gòu)造方法中的兩步
// 裝載實(shí)例化bean
private Map<String, Object> beanMap = new HashMap<String, Object>();
// 裝載配置文件的屬性和值
private List<MyBeans> beanlist = new ArrayList<MyBeans>();
public MyClassPathXmlApplicationContext(String filename) {
//第一步,解析spring配置文件
readXml(filename);
//第二步,通過反射,實(shí)例化所有注入bean
initBeans();
}
/**
* 通過反射機(jī)制,初始化配置文件中的bean
*/
private void initBeans() {
for (MyBeans bean : beanlist) {
try {
if (bean.getClassName() != null && !"".equals(bean.getClassName())) {
beanMap.put(bean.getId(), Class.forName(bean.getClassName()).newInstance());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 解析配置文件,把解析后的bean設(shè)置到實(shí)體中,并保持到list
*
* @param filename
*/
private void readXml(String filename) {
SAXReader reader = new SAXReader();
Document doc = null;
URL xmlpath = this.getClass().getClassLoader().getResource(filename);
try {
Map<String, String> nsMap = new HashMap<String, String>();
nsMap.put("ns", "http://www.springframework.org/schema/beans");
doc = reader.read(xmlpath);
XPath xpath = doc.createXPath("http://ns:beans//ns:bean");// 創(chuàng)建//ns:beans//ns:bean查詢路徑
xpath.setNamespaceURIs(nsMap);// 設(shè)置命名空間
List<Element> eles = xpath.selectNodes(doc);// 取得文檔下所有節(jié)點(diǎn)
for (Element element : eles) {
String id = element.attributeValue("id");
String cn = element.attributeValue("class");
//自定義實(shí)體bean,保存配置文件中id和class
MyBeans beans = new MyBeans(id, cn);
beanlist.add(beans);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public Object getBean(String beanId) {
return beanMap.get(beanId);
}
6.實(shí)體類
package com.mooing.service;
public class MyBeans {
private String id;
private String className;
public MyBeans(String id, String className) {
this.id = id;
this.className = className;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
}
7.測(cè)試
MyClassPathXmlApplicationContext ctx = new MyClassPathXmlApplicationContext("spring.xml");
MyService myService = (MyService) ctx.getBean("myService");
myService.save();
小結(jié)一下
自定義代碼同樣可以得到使用spring容器實(shí)例化的效果,也就是說,實(shí)際spring實(shí)例化管理bean時(shí),也是經(jīng)過兩大步:
第一:服務(wù)啟動(dòng)解析配置文件,并保存配置文件中的元素;
第二:實(shí)例化所有元素,并提供獲取實(shí)例方法。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java文件分級(jí)目錄打包下載zip的實(shí)例代碼
這篇文章主要介紹了Java文件分級(jí)目錄打包下載zip的實(shí)例代碼,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08
MyBatis-Plus非表字段的三種處理方法小結(jié)
這篇文章主要介紹了MyBatis-Plus非表字段的三種處理方法小結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08
springboot實(shí)現(xiàn)https雙向傳輸協(xié)議的示例代碼
本文主要介紹了springboot實(shí)現(xiàn)https雙向傳輸協(xié)議的示例代碼,包含配置證書和私鑰路徑、調(diào)用請(qǐng)求方法等步驟,具有一定的參考價(jià)值,感興趣的可以了解一下2025-03-03
如何應(yīng)對(duì)spring框架的HTTP ERROR 400 Bad Request錯(cuò)
這篇文章主要介紹了如何應(yīng)對(duì)spring框架的HTTP ERROR 400 Bad Request錯(cuò)誤返回問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08
SpringBoot接入釘釘自定義機(jī)器人預(yù)警通知
本文主要介紹了SpringBoot接入釘釘自定義機(jī)器人預(yù)警通知,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07
SpringBoot使用Validation校驗(yàn)參數(shù)的詳細(xì)過程
這篇文章主要介紹了SpringBoot使用Validation校驗(yàn)參數(shù),本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-09-09
解析探秘fescar分布式事務(wù)實(shí)現(xiàn)原理
這篇文章主要為大家解析探秘fescar分布式事務(wù)的實(shí)現(xiàn)原理,fescar的txc模型實(shí)現(xiàn)非常有研究的價(jià)值,所以今天我們來好好翻一翻fescar項(xiàng)目的代碼2022-02-02

