BeanDefinition表示Bean定义,有很多属性用来描述Bean的特点:
class,表示Bean类型
scope,表示Bean作用域,单例或原型等
lazyInit:表示Bean是否是懒加载
initMethodName:表示Bean初始化时要执行的方法
destroyMethodName:表示Bean销毁时要执行的方法
还有很多...
定义Bean的方式主要分为两种:
申明式定义
- 1、
- 2、@Bean
- 3、@Component(@Service,@Controller)
编程式定义
- AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
-
- // 生成一个BeanDefinition对象,并设置beanClass为User.class,并注册到ApplicationContext中
- AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
- beanDefinition.setBeanClass(User.class);
- beanDefinition.setScope("prototype"); // 设置作用域
- beanDefinition.setInitMethodName("init"); // 设置初始化方法
- beanDefinition.setLazyInit(true); // 设置懒加载
-
- context.registerBeanDefinition("user", beanDefinition);
- System.out.println(context.getBean("user"));
BeanDefinition读取器,虽然开发中用的很少,但是源码中用得很多
把某个类转换为BeanDefinition,并且解析类上的注解
- AnnotationConfigApplicationContext context = new
- AnnotationConfigApplicationContext(AppConfig.class);
- AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(context);
- // 将User.class解析为BeanDefinition
- annotatedBeanDefinitionReader.register(User.class);
- System.out.println(context.getBean("user"));
可以解析的注解:@Conditional、@Scope、@Lazy、@Primary、@DependsOn、 @Role、@Description
解析标签
- AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
- XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(context);
- int i = xmlBeanDefinitionReader.loadBeanDefinitions("spring.xml");
- System.out.println(context.getBean("user"));
扫描器,可以进行扫描,扫描某个包路径,对扫描到的类进行解析
- AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
- context.refresh();
- ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
- scanner.scan("com.gax");
- System.out.println(context.getBean("userService"));
Bean工厂,负责创建Bean,并且提供获取Bean的 API
ApplicationContext就是BeanFactory的一种
- public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory,
- HierarchicalBeanFactory,
- MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
- ...
- }
-
- HierarchicalBeanFactory: 支持父子Bean工厂,子Bean工厂获取不到时,可以到父Bean工厂去获取
- ListableBeanFactory: 展示Bean的名字、展示Bean的数量、统计的信息、拿某一个类型的Bean,类似列表的功能
- EnvironmentCapable: 获取环境变量的功能
- ApplicationEventPublisher: 事件发布的功能
- MessageSource: 国际化的功能
- ResourcePatternResolver: 获取某些资源、解析某些资源的功能
Spring源码中,BeanFactory接口非常重要的实现类: DefaultListableBeanFactory
ApplicationContext.getBean() 调用的就是 DefaultListableBeanFactory 的getBean()方法
DefaultListableBeanFactory 可以单独使用:
- DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
- AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
- beanDefinition.setBeanClass(User.class);
- beanFactory.registerBeanDefinition("user", beanDefinition);
- System.out.println(beanFactory.getBean("user"));
ApplicationContext是个接口,实际上也是一个BeanFactory,不过比BeanFactory 更加强大:
1、HierarchicalBeanFactory:拥有获取父BeanFactory的功能
2、ListableBeanFactory:拥有获取beanNames的功能
3、ResourcePatternResolver:资源加载器,可以一次性获取多个资源(文件资源等等)
4、EnvironmentCapable:可以获取运行时环境(没有设置运行时环境功能)
5、ApplicationEventPublisher:拥有广播事件的功能(没有添加事件监听器的功能)
6、MessageSource:拥有国际化功能
ApplicationContext两个重要的实现类:
1、AnnotationConfigApplicationContext
2、ClassPathXmlApplicationContext
定义一个MessageSource
- @Bean
- public MessageSource messageSource() {
- ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
- messageSource.setBasename("messages");
- return messageSource;
- }
ApplicationContext拥有国际化的功能,可以直接用
context.getMessage("test", null, new Locale("en_CN"))
可以利用ApplicationContext获取某个文件的内容
- AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
-
- Resource resource = context.getResource("file://D:\\UserService.java");
- System.out.println(resource.contentLength());
- System.out.println(resource.getFilename());
-
- Resource resource1 = context.getResource("https://www.baidu.com");
- System.out.println(resource1.contentLength());
- System.out.println(resource1.getURL());
-
- Resource resource2 = context.getResource("classpath:spring.xml");
- System.out.println(resource2.contentLength());
- System.out.println(resource2.getURL());
-
- Resource[] resources = context.getResources("classpath:com/gax/*.class");
- for (Resource resource : resources) {
- System.out.println(resource.contentLength());
- System.out.println(resource.getFilename());
- }
- AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
-
- Map
systemEnvironment = context.getEnvironment().getSystemEnvironment(); - System.out.println(systemEnvironment); //操作系统层面的环境变量
-
- Map
systemProperties = context.getEnvironment().getSystemProperties(); - System.out.println(systemProperties); //运行java通过-D指定的环境变量
-
- MutablePropertySources propertySources = context.getEnvironment().getPropertySources();
- System.out.println(propertySources); //最强大的,包含上面两种和PropertySources注解的变量
-
- System.out.println(context.getEnvironment().getProperty("NO_PROXY")); //操作系统
- System.out.println(context.getEnvironment().getProperty("sun.jnu.encoding")); //jvm -D指定
- System.out.println(context.getEnvironment().getProperty("gax")); //property里面的
定义一个事件监听器
- @Bean
- public ApplicationListener applicationListener() {
- return new ApplicationListener() {
- @Override
- public void onApplicationEvent(ApplicationEvent event) {
- System.out.println("接收到了一个事件");
- }
- };
- }
发布一个事件
context.publishEvent("yeah");
Spring提供了一些方便类型转化的技术
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);
- }
-
- // 单独使用示例
- public static void main(String[] args)
- {
- StringToUserPropertyEditor propertyEditor = new StringToUserPropertyEditor();
-
- propertyEditor.setAsText("11");
- User value = (User)propertyEditor.getValue();
- System.out.println(value);
- System.out.println(value.getName());
- }
- }
-
- 输出:
- com.gax.service.User@5a07e868
- 11
向Spring中注册PropertyEditor:
- @Bean
- public CustomEditorConfigurer customEditorConfigurer()
- {
- CustomEditorConfigurer customEditorConfigurer = new CustomEditorConfigurer();
- Map
, Class extends PropertyEditor>> propertyEditorMap = new HashMap<>(); - // StringToUserPropertyEditor可以将String转化成User类型,
- // 在Spring源码中,如果当前对象是String,而需要的类型是User,就会用该PropertyEditor做类型转化
- propertyEditorMap.put(User.class, StringToUserPropertyEditor.class);
- customEditorConfigurer.setCustomEditors(propertyEditorMap);
- return customEditorConfigurer;
- }
-
- // 示例代码
- @Component
- public class UserService
- {
- @Value("ccc")
- private User user; //这里需要类型转换
-
- public void test()
- {
- System.out.println(user);
- }
- }
-
- // 测试
- public class Test
- {
- public static void main(String[] args)
- {
-
- // 创建一个Spring容器
- AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
-
- UserService userService = (UserService) applicationContext.getBean("userService");
- userService.test();
- }
- }
-
- 输出:(输出的是一个User,转换成功)
- com.gax.service.User@17ed40e0
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 Set
getConvertibleTypes() - {
- return Collections.singleton(new GenericConverter.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;
- }
- }
-
- // 单独使用
- public class Test
- {
- public static void main(String[] args)
- {
- DefaultConversionService conversionService = new DefaultConversionService();
- conversionService.addConverter(new StringToUserConverter());
- User value = conversionService.convert("1", User.class);
- System.out.println(value);
- }
- }
向Spring中注册ConversionService:
- @Bean
- public ConversionServiceFactoryBean conversionService()
- {
- ConversionServiceFactoryBean conversionServiceFactoryBean = new ConversionServiceFactoryBean();
- conversionServiceFactoryBean.setConverters(Collections.singleton(new StringToUserConverter()));
- return conversionServiceFactoryBean;
- }
Spring提供更高级的转换类SimpleTypeConverter,可以支持上面两种
- public class Test
- {
- public static void main(String[] args)
- {
- SimpleTypeConverter typeConverter = new SimpleTypeConverter();
- typeConverter.registerCustomEditor(User.class, new StringToUserPropertyEditor());
- // DefaultConversionService conversionService = new DefaultConversionService();
- // conversionService.addConverter(new StringToUserConverter());
- // typeConverter.setConversionService(conversionService);
- User value = typeConverter.convertIfNecessary("1", User.class);
- System.out.println(value);
- }
- }
扩展:
- // getBean指定类型转换
- AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
- UserService userService = applicationContext.getBean("userService", UserService.class);
-
- // 可以对应到Spring源码:AbstractBeanFactory#adaptBeanInstance
T adaptBeanInstance(String name, Object bean, @Nullable Class> requiredType) { - // Check if required type matches the type of the actual bean instance.
- if (requiredType != null && !requiredType.isInstance(bean)) {
- try {
- // SimpleTypeConverter
- Object convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
- if (convertedBean == null) { // 已经转换过了返回,没转换报错
- throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
- }
- return (T) convertedBean;
- }
- catch (TypeMismatchException ex) {
- if (logger.isTraceEnabled()) {
- logger.trace("Failed to convert bean '" + name + "' to required type '" +
- ClassUtils.getQualifiedName(requiredType) + "'", ex);
- }
- throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
- }
- }
- return (T) bean;
- }
Spring所提供的一种比较器,有@Order注解、实现Ordered接口两种使用方式,通过指定的值进行比较或排序。
实现Ordered接口示例代码:
- public class A implements Ordered
- {
- @Override
- public int getOrder()
- {
- return 3;
- }
-
- @Override
- public String toString()
- {
- return this.getClass().getSimpleName();
- }
- }
-
- public class B implements Ordered
- {
- @Override
- public int getOrder()
- {
- return 2;
- }
-
- @Override
- public String toString()
- {
- return this.getClass().getSimpleName();
- }
- }
-
- public class Main
- {
- public static void main(String[] args)
- {
- A a = new A(); // order=3
- B b = new B(); // order=2
- OrderComparator comparator = new OrderComparator();
- System.out.println(comparator.compare(a, b)); // 1 (a>b,a
- List list = new ArrayList<>();
- list.add(a);
- list.add(b);
- // 按order值升序排序
- list.sort(comparator);
- System.out.println(list); // B,A
- }
- }
-
- 输出:
- 1
- [B, A]
Spring还提供了一个OrderComparator的子类: AnnotationAwareOrderComparator,它支持用@Order来指定order值
- @Order(3)
- public class A
- {
- @Override
- public String toString()
- {
- return this.getClass().getSimpleName();
- }
- }
-
- @Order(2)
- public class B
- {
- @Override
- public String toString()
- {
- return this.getClass().getSimpleName();
- }
- }
-
- public class Main
- {
- public static void main(String[] args)
- {
- A a = new A(); // order=3
- B b = new B(); // order=2
- AnnotationAwareOrderComparator comparator = new AnnotationAwareOrderComparator();
- System.out.println(comparator.compare(a, b)); // 1
- List list = new ArrayList<>();
- list.add(a);
- list.add(b);
- // 按order值升序排序
- list.sort(comparator);
- System.out.println(list); // B,A
- }
- }
-
- 输出:
- 1
- [B, A]
-
-
- // 关键源码:AnnotationAwareOrderComparator#findOrder
- protected Integer findOrder(Object obj) {
- // 先获取Ordered接口中getOrder()方法返回的数值
- Integer order = super.findOrder(obj);
- if (order != null) {
- return order;
- }
- // 如果没有实现Ordered接口,则获取@Order注解中指定的值
- return findOrderFromAnnotation(obj);
- }
BeanPostProcessor
BeanPostProcess表示Bean的后置处理器,可以定义一个或多个BeanPostProcessor
- @Component
- public class GaxBeanPostProcessor implements BeanPostProcessor
- {
- @Override
- public Object postProcessBeforeInitialization(Object bean, String beanName)
- {
- if ("userService".equals(beanName))
- {
- System.out.println("初始化前");
- }
- return bean;
- }
-
- @Override
- public Object postProcessAfterInitialization(Object bean, String beanName)
- {
- if ("userService".equals(beanName))
- {
- System.out.println("初始化后");
- }
- return bean;
- }
- }
BeanPostProcessor可以在任意一个Bean的初始化之前以及初始化之后去额外的做一些用户自定义的逻辑,当然还可以通过判断beanName来进行针对性处理(针对某个Bean,或某部分Bean)。
我们可以通过定义BeanPostProcessor来干涉Spring创建Bean的过程
BeanFactoryPostProcessor
Bean工厂的后置处理器,和BeanPostProcessor类似。
BeanPostProcessor是干涉Bean的创建过程,BeanFactoryPostProcessor是干涉BeanFactory的创建过程。
- @Component
- public class GaxBeanFactoryPostProcessor implements BeanFactoryPostProcessor
- {
- @Override
- public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
- {
- System.out.println("加工beanFactory");
- }
- }
FactoryBean
上面提到,可以通过BeanPostPorcessor来干涉Spring创建Bean的过程。但是如果我们想一个Bean完完全全由我们来创造,也是可以的,比如通过FactoryBean:
- @Component
- public class GaxFactoryBean implements FactoryBean
- {
- @Override
- public Object getObject()
- {
- return new UserService();
- }
-
- @Override
- public Class> getObjectType()
- {
- return UserService.class;
- }
- }
-
- // 测试
- public class Test
- {
- public static void main(String[] args) throws IOException
- {
- // 创建一个Spring容器
- AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
- Object gaxFactoryBean = applicationContext.getBean("gaxFactoryBean");
- Object gaxFactoryBean2 = applicationContext.getBean("&gaxFactoryBean");
- Object gaxFactoryBean3 = applicationContext.getBean("&&&&&&gaxFactoryBean");
- System.out.println(gaxFactoryBean);
- System.out.println(gaxFactoryBean2);
- System.out.println(gaxFactoryBean3);
- }
- }
-
- 输出:
- com.gax.service.UserService@6e3c1e69
- com.gax.GaxFactoryBean@5f150435
- com.gax.GaxFactoryBean@5f150435
注意:通过这种方式创造出来的UserService的Bean,只会经过初始化后,其他Spring的生命周期步骤是不会经过的,比如依赖注入。
通过@Bean也可以生成一个对象作为Bean,那么和FactoryBean的区别是什么呢?
其实在很多场景下他俩是可以替换的,但是站在原理层面来说的,区别很明显,@Bean定义的Bean是会经过完整的Bean生命周期的。
ExcludeFilter和IncludeFilter
ExcludeFilter表示排除过滤器,IncludeFilter表示包含过滤器
- // 扫描com.gax这个包下面的所有类,但是排除UserService类
- // 也就是就算类上面有@Component注解也不会成为Bean
- @ComponentScan(value = "com.gax", excludeFilters = {
- @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = UserService.class)})
- public class AppConfig {
- }
-
- // 就算UserService类上没有@Component注解,也会被扫描成为一个Bean
- @ComponentScan(value = "com.gax", includeFilters = {
- @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = UserService.class)})
- public class AppConfig {
- }
FilterType分为:
1、ANNOTATION:是否包含某个注解
2、ASSIGNABLE_TYPE:是否是某个类
3、ASPECTJ:是否符合某个Aspectj表达式
4、REGEX:是否符合某个正则表达式
5、CUSTOM:自定义
Spring内部怎么支持@Component注解扫描的?
在Spring的扫描逻辑中,默认会添加一个AnnotationTypeFilter给includeFilters,表示默认情况下 Spring扫描过程中会认为类上有@Component注解的就是Bean。
- // ClassPathScanningCandidateComponentProvider#registerDefaultFilters
- protected void registerDefaultFilters() {
-
- // 注册@Component对应的AnnotationTypeFilter
- this.includeFilters.add(new AnnotationTypeFilter(Component.class));
-
- ... ...
- }
MetadataReader、ClassMetadata、 AnnotationMetadata
在Spring中需要去解析类的信息,比如类名、类中的方法、类上的注解,这些都可以称之为类的元数 据,所以Spring中对类的元数据做了抽象,并提供了一些工具类。
- public interface MetadataReader {
-
- /**
- * Return the resource reference for the class file.
- */
- Resource getResource();
-
- /**
- * Read basic class metadata for the underlying class.
- */
- ClassMetadata getClassMetadata();
-
- /**
- * Read full annotation metadata for the underlying class,
- * including metadata for annotated methods.
- */
- AnnotationMetadata getAnnotationMetadata();
- }
-
- // 类的元数据
- public interface ClassMetadata {
-
- /**
- * Return the name of the underlying class.
- */
- String getClassName();
-
- /**
- * Return whether the underlying class represents an interface.
- */
- boolean isInterface();
-
- /**
- * Return whether the underlying class represents an annotation.
- * @since 4.1
- */
- boolean isAnnotation();
-
- /**
- * Return whether the underlying class is marked as abstract.
- */
- boolean isAbstract();
-
- /**
- * Return whether the underlying class represents a concrete class,
- * i.e. neither an interface nor an abstract class.
- */
- default boolean isConcrete() {
- return !(isInterface() || isAbstract());
- }
-
- ... ...
- }
-
- // 注解元数据
- public interface AnnotationMetadata extends ClassMetadata, AnnotatedTypeMetadata {
-
- /**
- * Get the fully qualified class names of all annotation types that
- * are present on the underlying class.
- * @return the annotation type names
- */
- default Set
getAnnotationTypes() { - return getAnnotations().stream()
- .filter(MergedAnnotation::isDirectlyPresent)
- .map(annotation -> annotation.getType().getName())
- .collect(Collectors.toCollection(LinkedHashSet::new));
- }
-
- /**
- * Determine whether an annotation of the given type is present on
- * the underlying class.
- * @param annotationName the fully qualified class name of the annotation
- * type to look for
- * @return {@code true} if a matching annotation is present
- */
- default boolean hasAnnotation(String annotationName) {
- return getAnnotations().isDirectlyPresent(annotationName);
- }
-
- /**
- * 可以判断类下面有没有指定注解,比如说判断一个类下面有没有@Bean修饰的方法
- * Determine whether the underlying class has an annotation that is itself
- * annotated with the meta-annotation of the given type.
- * @param metaAnnotationName the fully qualified class name of the
- * meta-annotation type to look for
- * @return {@code true} if a matching meta-annotation is present
- */
- default boolean hasMetaAnnotation(String metaAnnotationName) {
- return getAnnotations().get(metaAnnotationName,
- MergedAnnotation::isMetaPresent).isPresent();
- }
-
- ... ...
- }
MetadataReader表示类的元数据读取器,默认实现类为SimpleMetadataReader。
- public class Test
- {
- public static void main(String[] args) throws IOException
- {
- SimpleMetadataReaderFactory simpleMetadataReaderFactory = new SimpleMetadataReaderFactory();
- // 构造一个MetadataReader
- MetadataReader metadataReader = simpleMetadataReaderFactory.getMetadataReader("com.gax.service.UserService");
- // 得到一个ClassMetadata,并获取了类名
- ClassMetadata classMetadata = metadataReader.getClassMetadata();
- System.out.println(classMetadata.getClassName());
- // 获取一个AnnotationMetadata,并获取类上的注解信息
- AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
- for (String annotationType : annotationMetadata.getAnnotationTypes())
- {
- System.out.println(annotationType);
- }
- }
- }
-
- 输出:
- com.gax.service.UserService
- org.springframework.stereotype.Component
注意:SimpleMetadataReader去解析类时,使用的ASM技术。
ASM简述:把类当成普通文件,通过字节流读出来,如果符合字节码规范,就根据字节码的格式获取类的信息
为什么要使用ASM技术?
Spring启动的时候需要去扫描,如果指定的包路径比较宽泛,那么扫描的类是非常多的,那如果在Spring启动时就把这些类全部加载进JVM了,这样不太好,所以使用了 ASM技术