@DependsOn注解可以控制bean的加载顺序
当A依赖B时,因为并不知道A与B谁先优先加载,可以再A类上添加此注解去依赖B
这时当先加载了A 时,会先实例化B并且注入属性,但是B中的Bean并不会加载。
例子1:
实现@Value属性注入从数据库加载的数据。
1、从数据库拿配置
@Configuration
public class DbConfig {
/**
* 这个就是查询service
*/
@Autowired
private DbService dbService;
/**
* spring 所有的变量都存在这里面
* 解析${xxx}时用resolvePlaceholders
*/
@Autowired
private StandardEnvironment environment;
/**
* 注意这个注解@PostConstruct 执行完实例化后执行此注解标注方法
* 不能用@Bean代替
*/
@PostConstruct
public void getConfig() {
//获取配置实体
MyDbProperties dbConfig = dbService.getConfig();
Map<String, Object> properties = new HashMap<>();
//配置到properties
properties.put("user.name", dbConfig.getName());
properties.put("user.pwd", dbConfig.getPwd());
//构造MapPropertySource
MapPropertySource mailPropertySource = new MapPropertySource("user", properties);
//放入环境变量
environment.getPropertySources().addFirst(mailPropertySource);
}
}
2、用
@Component
@DependsOn("dbConfig")//这个注解表示需要依赖其他类,优先实例化其他类
public class OtherClass {
/**
* 直接用即可
*/
private String value;
@Value("${user.name}")
private void setValue(String value){
this.value=value;
}
}
总结:
1、DependsOn注解可以控制bean加载顺序
2、PostConstruct注解在实例化完成类之后就执行
例子2:
动态修改数据库配置,@Value注解动态加载属性
1、自定义scope注解
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Scope(MyBeanRefreshScope.SCOPE_REFRESH)
@Documented
public @interface MyRefreshScope {
/**
* TARGET_CLASS类型才能为标注此注解的类生成代理对象
*/
ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;
}
2、scope处理类
public class MyBeanRefreshScope extends GenericScope {
public static final String SCOPE_REFRESH = "MY";
private static final MyBeanRefreshScope INSTANCE = new MyBeanRefreshScope();
/**
* 和注解value要一致
*/
public MyBeanRefreshScope(){
super.setName(SCOPE_REFRESH);
}
public static MyBeanRefreshScope getInstance(){
return INSTANCE;
}
//重新加载dbConfig类,获取修改后的配置
public void clear() {
ConfigurableApplicationContext applicationContext = (ConfigurableApplicationContext) SpringContextUtils.getApplicationContext();
BeanDefinitionRegistry beanFactory = (BeanDefinitionRegistry)applicationContext.getBeanFactory();
beanFactory.removeBeanDefinition("dbConfig");
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(DbConfig.class);
BeanDefinition beanDefinition = beanDefinitionBuilder.getRawBeanDefinition();
beanFactory.registerBeanDefinition("dbConfig",beanDefinition);
applicationContext.getBean("dbConfig", DbConfig.class);
}
@Override
public Object get(String name, ObjectFactory<?> objectFactory) {
this.clear();
//把标注注解的类重新加载,这样就会重新赋值@Value值
super.destroy();
return super.get(name,objectFactory);
}
}
3、注册自定义scope
@Component
public class ScopeBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
beanFactory.registerScope(MyBeanRefreshScope.SCOPE_REFRESH,MyBeanRefreshScope.getInstance());
}
}
4、用
@Component
@DependsOn("dbConfig")//这个注解表示需要依赖其他类,优先实例化其他类
public class OtherClass {
/**
* 直接用即可
*/
private String value;
@Value("${user.name}")
private void setValue(String value){
this.value=value;
}
}