在Web应用中,Spring容器通常采用声明式方式配置产生:开发者只要在web.xml中配置一个Listener,该Listener将会负责初始化Spring容器,MVC框架可以直接调用Spring容器中的Bean,无需访问Spring容器本身。在这种情况下,容器中的Bean处于容器管理下,无需主动访问容器,只需接受容器的依赖注入即可。
在某些的情况下,我们要获取IOC容器中指定注解、类型、名字的Bean,来实现某个功能
实现上,我们不用类似new ClassPathXmlApplicationContext()的方式,从已有的spring上下文取得已实例化的bean。通过ApplicationContextAware接口进行实现。
当一个类实现了这个接口(ApplicationContextAware)之后,这个类就可以方便获得ApplicationContext中的所有bean。换句话说,就是这个类可以直接获取spring配置文件中,所有有引用到的bean对象
以下实例采用SpringBoot + idea:
AppBeanUtil。java:
@Component("appBeanUtil")
public class AppBeanUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext = null;
/**
* 实现ApplicationContextAware接口, 注入Context到本类的静态变量中.
*/
public void setApplicationContext(ApplicationContext preapplicationContext) {
AppBeanUtil.applicationContext = preapplicationContext;
}
/**
* 获取静态变量中的ApplicationContext.
*/
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
/**
* 从静态变量applicationContext中得到指定名字的 Bean, 自动转型为所赋值对象的类型.
*/
public static <T> T getBean(String beanName) {
return (T)applicationContext.getBean(beanName);
}
/**
* 从静态变量applicationContext中得到指定名字、类型的 Bean, 自动转型为所赋值对象的类型.其中指定的类型可以是其父类或所实现的接口
*/
public static <T> T getBean(String beanName, Class<T> clz) {
return applicationContext.getBean(beanName, clz);
}
/**
* 根据传入的自定义注解的类,从Application获取有此注解的所有类
* @param cls
* @return
*/
public static Map<String, Object> getMapbeanwithAnnotion(Class<? extends Annotation> cls) {
Map<String, Object> map = new HashMap<String, Object>();
map = applicationContext.getBeansWithAnnotation(cls);
return map;
}
/**
* 根据类型获取spring容器中的实例
* @param clazz
* @param <T>
* @return
*/
public static <T> Map<String,T> getBeansOfType(Class<T> clazz){
assertContextInjected();
return applicationContext.getBeansOfType(clazz);
}
/**
* 检查ApplicationContext不为空.
*/
private static void assertContextInjected() {
Validate.validState(applicationContext != null,"applicaitonContext属性未注入!");
}
/**
* 清除SpringContextHolder中的ApplicationContext为Null.
*/
public static void clearHolder() {
applicationContext = null;
}
}
Spring容器会检测容器中的所有Bean,如果发现某个Bean实现了ApplicationContextAware接口,Spring容器会在创建该Bean之后,自动调用该Bean的setApplicationContextAware()方法,调用该方法时,会将容器本身作为参数传给该方法——该方法中的实现部分将Spring传入的参数(容器本身)赋给该类对象的applicationContext实例变量,因此接下来可以通过该applicationContext实例变量来访问容器本身
Person.java
public abstract class Person {
public abstract String getName(String name);
}
Stu.java
@Component
public class Stu extends Person {
@Override
public String getName(String name) {
System.out.println("Stu call...");
String result = "I am a Stu,username:" + name;
return result;
}
}
Tea.java
@Component
public class Tea extends Person {
@Override
public String getName(String name) {
System.out.println("Tea call...");
String result = "I am a Tea,username:" + name;
return result;
}
}
测试Demo
@Component
//@DependsOn(value = "appBeanUtil")
public class TestTask {
//@Scheduled(cron = "${cron.timer}")
@Scheduled(cron = "0/2 0/1 * * * ? ")
public void test(){
System.out.println("定时器运行了!!! start....");
Map<String, Person> beans = AppBeanUtil.getBeansOfType(Person.class);
if (MapUtils.isNotEmpty(beans)) {
for (Person bean : beans.values()) {
String userName = bean.getName("zhangsan");
System.out.println(userName);
}
}
System.out.println("定时器运行了!!! end....");
}
}
结果: