1.如何在spring中,为bean初始化属性???
答:spring中的BeanPostProcessor能够完成对bean的初始化加工.
2.我应该从哪里获取到我在配置文件中配置的属性呢?
答:可以在Environment对象的属性中获取,我们可以通过ApplicationContextAware让spring给我注入context,进一步获取该对象.
现在我们已经可以完成对一个bean进行属性注入了,来看一下实现吧:
public class PropBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware, PriorityOrdered {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
UserProperties annotation = bean.getClass().getAnnotation(UserProperties.class);//等同于@ConfigurationProperties注解
if(annotation != null) {
String prefix = annotation.prefix();
Environment environment = this.applicationContext.getEnvironment();
if (environment instanceof ConfigurableEnvironment) {
MutablePropertySources propertySources = ((ConfigurableEnvironment) environment).getPropertySources();
for (PropertySource<?> propertySource : propertySources) {
Object property = propertySource.getProperty(prefix);
if (property != null) {
System.out.println(property);//简单打印,可自行解析,我这里直使用值,简化不必要操作
try {
Class<?> clazz = bean.getClass();//通过反射注入值
Field name = clazz.getDeclaredField("name");
name.setAccessible(true);
name.set(bean,"my_name");
Field age = clazz.getDeclaredField("age");
age.setAccessible(true);
age.set(bean,18);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE + 2;
}
}
3.我自定义的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(UserImportSelector.class)//我们通过import导入了一个ImpoetSelector的实现,用于注入启用功能所需要的功能类
public @interface EnableProp {
Class value();
}
这样使用
@SpringBootApplication
@EnableProp(User.class)//启用User的属性注入
public class Demo2Application {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(Demo2Application.class, args);
User bean = context.getBean(User.class);
System.out.println(bean);
}
}
启用功能苏需要的功能类:
public class UserImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{UserImportBeanDefinitionRegistrar.class.getName(),//实现对User的定义注入
PropBeanPostProcessor.class.getName()};//实现对bean属性的注入
}
}
看一下如何对user类注入spring:
public class UserImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
Set<String> annotationTypes = importingClassMetadata.getAnnotationTypes();
for (String annotationType : annotationTypes) {
if(annotationType.equals(EnableProp.class.getName())){
MultiValueMap<String, Object> allAnnotationAttributes = importingClassMetadata.getAllAnnotationAttributes(annotationType);
List<Object> value = allAnnotationAttributes.get("value");
Class beanClass = (Class) value.get(0);
GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
genericBeanDefinition.setBeanClass(beanClass);
registry.registerBeanDefinition(beanClass.getName(),genericBeanDefinition);
}
}
}
}
此处,@EnableProp加在那里,importingClassMetadata就是那个类的注解元数据,此处是Demo2Application的注解;在上文中我们获取到EnableProp注解,检查他的value类型,并初始化一个bean定义,注入到文件中
4.再看一下配置文件吧
user:
name:my_name
age:18
5.再来看一下运行结果:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.5.RELEASE)
2019-06-10 17:52:21.511 INFO 17032 --- [ restartedMain] com.example.demo2.Demo2Application : Starting Demo2Application on Think-PC with PID 17032 (E:\idea\damo\demo2\out\production\classes started by Think in E:\idea\damo\demo2)
2019-06-10 17:52:21.516 INFO 17032 --- [ restartedMain] com.example.demo2.Demo2Application : No active profile set, falling back to default profiles: default
2019-06-10 17:52:21.600 INFO 17032 --- [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable
name:my_name age:18
name:my_name age:18
2019-06-10 17:52:22.451 INFO 17032 --- [ restartedMain] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729
2019-06-10 17:52:22.485 INFO 17032 --- [ restartedMain] com.example.demo2.Demo2Application : Started Demo2Application in 1.719 seconds (JVM running for 6.084)
User{name='my_name', age=18}