本文共 10284 字,大约阅读时间需要 34 分钟。
Bean的定义,在Spring中,我们可以如何去定义一个Bean?
还有就是可以通过BeanDefinition
比如,我们可以通过定义一个BeanDefinition对象来表示定义了一个Bean:
// 定义了一个BeanDefinitionAbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();// 当前Bean对象的类型beanDefinition.setBeanClass(User.class);// 将BeanDefinition注册到BeanFactory中DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();beanFactory.registerBeanDefinition("user", beanDefinition);// 获取BeanSystem.out.println(beanFactory.getBean("user"));
我们还可以通过BeanDefinition设置一个Bean的其他属性
beanDefinition.setScope("prototype"); // 设置作用域beanDefinition.setInitMethodName("init"); // 设置初始化方法beanDefinition.setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE); // 设置自动装配模型
等等
总之,我们通过<bean/>,@Bean,@Component等方式所定义的Bean,最终都会被解析为BeanDefinition对象。
BeanDefinition可以理解为底层源码级别的一个概念,也可以理解为Spring提供的一种API使用的方式。
BeanDefinitionReader分为几类:
可以直接把某个类转换为BeanDefinition,并且会解析该类上的注解
注意:它能解析的注解是:@Conditional,@Scope、@Lazy、@Primary、@DependsOn、@Role、@Description
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(beanFactory);// 将User.class解析为BeanDefinitionannotatedBeanDefinitionReader.register(User.class);System.out.println(beanFactory.getBean("user"));
可以解析<bean/>标签
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);int i = xmlBeanDefinitionReader.loadBeanDefinitions("spring.xml");System.out.println(beanFactory.getBean("user"));
这个并不是BeanDefinitionReader,但是它的作用和BeanDefinitionReader类似,它可以进行扫描,扫描某个包路径,对扫描到的类进行解析,比如,扫描到的类上如果存在@Component注解,那么就会把这个类解析为一个BeanDefinition
Spring中比较核心的是BeanFactory的实现类是DefaultListableBeanFactory
它实现了很多接口,表示,它拥有很多功能:
通过以上分析,我们可以知道,通过DefaultListableBeanFactory我们可以做很多事情,比如:
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();beanDefinition.setBeanClass(User.class);DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();// 注册BeanDefinitionbeanFactory.registerBeanDefinition("user", beanDefinition);// 注册别名beanFactory.registerAlias("user", "user1");// 注册BeanPostProcessorbeanFactory.addBeanPostProcessor(new LubanBeanPostProcessor());// 获取Bean对象System.out.println(beanFactory.getBean("user1"));// 根据类型获取beanNamesSystem.out.println(beanFactory.getBeanNamesForType(User.class));
首先ApplicationContext是个接口,可以把它理解为一个特殊的BeanFactory
又两个比较重要的实现类:
它也是继承了AbstractApplicationContext,但是相对于AnnotationConfigApplicationContext而言,功能没有AnnotationConfigApplicationContext强大,比如不能注册BeanDefinition
先定义一个MessageSource:
@Beanpublic MessageSource messageSource() { ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); messageSource.setBasename("messages"); return messageSource;}
有了这个Bean,你可以在你任意想要进行国际化的地方使用该MessageSource。
同时,因为ApplicationContext也拥有国家化的功能,所以可以直接这么用:
annotationConfigApplicationContext.getMessage("test", null, new Locale("en_CN"))
ApplicationContext还拥有资源加载的功能,比如,可以直接利用ApplicationContext获取某个文件的内容:
Resource resource = annotationConfigApplicationContext.getResource("file://D:\\IdeaProjects\\spring-framework\\luban\\src\\main\\java\\com\\luban\\entity\\User.java");System.out.println(resource.contentLength());
你可以想想,如果你不使用ApplicationContext,而是自己来实现这个功能,就比较费时间了。
还比如你可以:
Resource resource = annotationConfigApplicationContext.getResource("classpath:com/luban/entity/User.class");System.out.println(resource.contentLength());
还可以一次性获取多个:
Resource[] resources = annotationConfigApplicationContext.getResources("classpath:com/luban/service/*.class");for (Resource resource : resources) { System.out.println(resource.contentLength());}
这个功能用到了策略模式。
// 获取JVM所允许的操作系统的环境annotationConfigApplicationContext.getEnvironment().getSystemEnvironment();// 获取JVM本身的一些属性,包括-D所设置的annotationConfigApplicationContext.getEnvironment().getSystemProperties();// 还可以直接获取某个环境或properties文件中的属性annotationConfigApplicationContext.getEnvironment().getProperty("lubanyyy")
注意,可以利用
@PropertySource("classpath:application.properties")
来使得某个properties文件中的参数添加到运行时环境中
先定义一个事件监听器
@Beanpublic ApplicationListener applicationListener() { return new ApplicationListener() { @Override public void onApplicationEvent(ApplicationEvent event) { System.out.println("接收到了一个事件"); } };}
然后发布一个事件:
annotationConfigApplicationContext.publishEvent("kkk");
JDK中提供的类型转化工具类
public class StringToUserPropertyEditor extends PropertyEditorSupport implements PropertyEditor { @Override public void setAsText(String text) throws IllegalArgumentException { User user = new User(); user.setName(text); this.setValue(user); }}
StringToUserPropertyEditor propertyEditor = new StringToUserPropertyEditor();propertyEditor.setAsText("1");User value = (User) propertyEditor.getValue();System.out.println(value);
如何向Spring中注册PropertyEditor:
@Beanpublic CustomEditorConfigurer customEditorConfigurer() { CustomEditorConfigurer customEditorConfigurer = new CustomEditorConfigurer(); Map, Class > propertyEditorMap = new HashMap<>(); propertyEditorMap.put(User.class, StringToUserPropertyEditor.class); customEditorConfigurer.setCustomEditors(propertyEditorMap); return customEditorConfigurer;}
假设现在有如下Bean:
@Componentpublic class UserService { @Value("true") User test; public void test() { System.out.println(test); }}
那么test属性就能正常的完成属性赋值
Spring中提供的类型转化服务,它比PropertyEditor更强大
public class StringToUserConverter implements ConditionalGenericConverter { @Override public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) { return sourceType.getType().equals(String.class) && targetType.getType().equals(User.class); } @Override public SetgetConvertibleTypes() { return Collections.singleton(new ConvertiblePair(String.class, User.class)); } @Override public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { User user = new User(); user.setName((String)source); return user; }}
DefaultConversionService conversionService = new DefaultConversionService();conversionService.addConverter(new StringToUserConverter());User value = conversionService.convert("1", User.class);System.out.println(value);
如何向Spring中注册ConversionService:
@Beanpublic ConversionServiceFactoryBean conversionService() { ConversionServiceFactoryBean conversionServiceFactoryBean = new ConversionServiceFactoryBean(); conversionServiceFactoryBean.setConverters(Collections.singleton(new StringToUserConverter())); return conversionServiceFactoryBean;}
整合了PropertyEditor和ConversionService的功能,是Spring内部用的
SimpleTypeConverter typeConverter = new SimpleTypeConverter();typeConverter.registerCustomEditor(User.class, new StringToUserPropertyEditor());//typeConverter.setConversionService(conversionService);User value = typeConverter.convertIfNecessary("1", User.class);System.out.println(value);
Bean的后置处理器,可以在创建每个Bean的过程中进行干涉,是属于BeanFactory中一个属性,讲Bean的生命周期中详细讲。
Bean工厂的后置处理器,是属于ApplicationContext中的一个属性,是ApplicationContext在实例化一个BeanFactory后,可以利用BeanFactoryPostProcessor继续处理BeanFactory。
程序员可以通过BeanFactoryPostProcessor间接的设置BeanFactory,比如上文中的CustomEditorConfigurer就是一个BeanFactoryPostProcessor,我们可以通过它向BeanFactory中添加自定义的PropertyEditor。
允许程序员自定义一个对象通过FactoryBean间接的放到Spring容器中成为一个Bean。
那么它和@Bean的区别是什么?因为@Bean也可以自定义一个对象,让这个对象成为一个Bean。
区别在于利用FactoryBean可以更加强大,因为你通过定义一个XxFactoryBean的类,可以再去实现Spring中的其他接口,比如如果你实现了BeanFactoryAware接口,那么你可以在你的XxFactoryBean中获取到Bean工厂,从而使用Bean工厂做更多你想做的,而@Bean则不行。
转载地址:http://ibbnb.baihongyu.com/