获取所有spring管理的bean
本文我们探索使用不同的方式获取spring容器中所有bean。
IOC容器
bean是基于spring应用的基础,所有bean都驻留在ioc容器中,由容器负责管理bean生命周期
有两种方式可以获取容器中的bean:
- 使用ListableBeanFactory接口
- 使用Spring Boot Actuator
使用ListableBeanFactory接口
ListableBeanFactory接口提供了getBeanDefinitionNames() 方法,能够返回所有定义bean的名称。该接口被所有factory实现,负责预加载bean定义去枚举所有bean实例。官方文档提供所有其子接口及其实现。
下面示例使用Spring Boot 构建:
首先,我们创建一些spring bean,先定义简单的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依赖另一个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."; } }
我们创建了两个不同的bean:
1.fooController
2.fooService
现在我们运行该应用。使用applicationContext 对象调用其 getBeanDefinitionNames() 方法,负责返回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); } } }
会输出applicationContext上下文中所有bean:
fooController
fooService
//other beans
需注意除了我们定义的bean外,它还将打印容器中所有其他bean。为了清晰起见,这里省略了很多。
使用Spring Boot Actuator
Spring Boot Actuator提供了用于监视应用程序统计信息的端点(endpoint)。除了/beans,还包括很多其他端点,官方文档有详细说明。
现在我们访问url: http//
:/beans,如果没有指定其他独立管理端口,我们使用缺省端口,结果会返回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 ] } ]
当然,结果同样包括很多其他的bean,为了简单起见,这里没有列出。
小结一下
上面介绍了使用ListableBeanFactory 接口和 Spring Boot Actuators 返回spring 容器中所有定义的bean信息。
spring管理bean的原理
Spring容器默认情况下,当服务启动时,解析配置文件,实例化文件中的所有类。
使用spring时,获取spring注入的bean是这样
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml"); MyService myService1 = (MyService) ctx.getBean("myService");
那下面我们模拟spring管理bean这个的过程
代码如下:
1.第一步,创建java project,引入spring.jar
2.创建spring.xml配置文件
3.创建接口MyService,只需要一个测试方法save
4.创建实现类MyServiceImpl,控制台输出一句话
5.创建一个自己的解析类MyClassPathXmlApplicationContext
主要是构造方法中的两步
// 装载实例化bean private MapbeanMap = new HashMap (); // 装载配置文件的属性和值 private List beanlist = new ArrayList (); public MyClassPathXmlApplicationContext(String filename) { //第一步,解析spring配置文件 readXml(filename); //第二步,通过反射,实例化所有注入bean initBeans(); } /** * 通过反射机制,初始化配置文件中的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设置到实体中,并保持到list * * @param filename */ private void readXml(String filename) { SAXReader reader = new SAXReader(); Document doc = null; URL xmlpath = this.getClass().getClassLoader().getResource(filename); try { Map nsMap = new HashMap (); nsMap.put("ns", "http://www.springframework.org/schema/beans"); doc = reader.read(xmlpath); XPath xpath = doc.createXPath("//ns:beans//ns:bean");// 创建//ns:beans//ns:bean查询路径 xpath.setNamespaceURIs(nsMap);// 设置命名空间 List eles = xpath.selectNodes(doc);// 取得文档下所有节点 for (Element element : eles) { String id = element.attributeValue("id"); String cn = element.attributeValue("class"); //自定义实体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.实体类
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.测试
MyClassPathXmlApplicationContext ctx = new MyClassPathXmlApplicationContext("spring.xml"); MyService myService = (MyService) ctx.getBean("myService"); myService.save();
小结一下
自定义代码同样可以得到使用spring容器实例化的效果,也就是说,实际spring实例化管理bean时,也是经过两大步:
第一:服务启动解析配置文件,并保存配置文件中的元素;
第二:实例化所有元素,并提供获取实例方法。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。