1.简单的示例:
1 @Configuration 2 @EnableConfigurationProperties({DemoProperties.class}) 3 public class DemoConfiguration { 4 5 @Bean 6 public Book getBook(){ 7 return new Book(); 8 } 9 }
1 @Autowired Book book; 2 3 @Test 4 public void testBook(){ 5 System.out.println(book.toString()); 6 }
结果打印出book对象,证明Book已经被注入到Spring 容器中了。
2.@Configuration配置的bean是如何注入到Spring容器中的呢?
首先先来简单介绍下通过BeanDefinitionRegistry注入bean
1 @Autowired 2 public void registBeanDefinition(BeanFactory factory){ 3 if(factory instanceof BeanDefinitionRegistry) { 4 BeanDefinitionRegistry registry = (BeanDefinitionRegistry)factory; 5 BeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Book.class).getBeanDefinition(); 6 registry.registerBeanDefinition("mybook", beanDefinition); 7 } 8 }
1 @Autowired @Qualifier("mybook") Book book2; 2 @Test 3 public void testBook2(){ 4 System.out.println(book2); 5 }
结果同样打印出book对象,这里,笔者将beanFactory强转为BenDefinitionRegistry,因为笔者的Demo中使用的是默认BeanFactory,----DefaultListableBeanFactory,他实现了BeanDefinitionRegistry接口。
3.入口,下图为ApplicaitonContext refresh方法的简化,只保留了BeandefinitionRegistry注册bean部分功能。
然,似乎并没什么用?此处会调用BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法。要解决的一个问题是,BeanDefinitionRegistryPostProcessor类型的bean是如何注入的。以SpringBoot初始化为例。
注意到,ApplicationContext的构造方法:
1 public AnnotationConfigEmbeddedWebApplicationContext() { 2 this.reader = new AnnotatedBeanDefinitionReader(this); 3 this.scanner = new ClassPathBeanDefinitionScanner(this); 4 }
1 public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) { 2 this(registry, getOrCreateEnvironment(registry)); 3 }
1 public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) { 2 Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); 3 Assert.notNull(environment, "Environment must not be null"); 4 this.registry = registry; 5 this.conditionEvaluator = new ConditionEvaluator(registry, environment, null); 6 AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); 7 }
1 public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors( 2 BeanDefinitionRegistry registry, Object source) { 3 4 DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry); 5 if (beanFactory != null) { 6 if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) { 7 beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE); 8 } 9 if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) { 10 beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver()); 11 } 12 } 13 14 Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<BeanDefinitionHolder>(4); 15 //注解@Configuration处理 16 if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) { 17 RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class); 18 def.setSource(source); 19 beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)); 20 } 21 22 .......//省略部分代码 23 24 return beanDefs; 25 }
注意到对@Configuration的处理为ConfigurationClassPostProcessor。
注意到ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessor接口,显然关键方法为postProcessBeanDefinitionRegistry。ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry会调用ConfirgurationClassParser的parse方法。会依次解析注解,我们一步一步查看对各个注解的解析。
(1)@PropertySources和@PropertySource
1 @Target(ElementType.TYPE) 2 @Retention(RetentionPolicy.RUNTIME) 3 @Documented 4 public @interface PropertySources { 5 6 PropertySource[] value(); 7 8 }
最终都是处理@PropertySource,@PropertySources仅仅只是包含多个@PropertySource,@PropertySource注解的主要功能是引入配置文件,将配置的属性键值对与环境变量中的配置合并。其中最关键的类为MutablePropertySources
1 public class MutablePropertySources implements PropertySources { 2 3 private final Log logger; 4 5 private final List<PropertySource<?>> propertySourceList = new CopyOnWriteArrayList<PropertySource<?>>(); 6 ...... 7 }
显然MutablePropertySources中包含有一个PropertySource列表。MutablePropertySources仅仅是封装了迭代器功能。可以理解成PropertySources是PropertySource的集合,增加了常用的集合操作。
(2)@ComponentScan
定义自动扫描的包。简化的序列图如下:
其最关键的方法为doScan方法,会注册BeanDefinition到容器中。
1 protected Set<BeanDefinitionHolder> doScan(String... basePackages) { 2 Assert.notEmpty(basePackages, "At least one base package must be specified"); 3 Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>(); 4 for (String basePackage : basePackages) { 5 Set<BeanDefinition> candidates = findCandidateComponents(basePackage); 6 for (BeanDefinition candidate : candidates) { 7 ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate); 8 candidate.setScope(scopeMetadata.getScopeName()); 9 String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry); 10 if (candidate instanceof AbstractBeanDefinition) { 11 postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName); 12 } 13 if (candidate instanceof AnnotatedBeanDefinition) { 14 AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate); 15 } 16 if (checkCandidate(beanName, candidate)) { 17 BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName); 18 definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); 19 beanDefinitions.add(definitionHolder); 20 registerBeanDefinition(definitionHolder, this.registry); 21 } 22 } 23 } 24 return beanDefinitions; 25 }
registerBeanDefinition(definitionHolder, this.registry);能说明一切。
(3)@Import
@Import注解可以配置需要引入的class(假设配置为A,可以是数组),有三种方式。其流程图如下:
如果A为ImportSelector的子类,调用selectImports()方法,返回class类名数组,循环解析每一个import的类,如果A为BeanDefinitionRegistrar则直接调用registerBeanDefinition直接注入bean到容器中。如果A为普通的类(非前面提到的两种类型),则将A当做@Configuration配置的类,重新解析Configuration.
(4)@ImportSource
主要功能为引入资源文件。
(5)@Bean,比较简单,童FactoryMethod一样
1 // Process individual @Bean methods 2 Set<MethodMetadata> beanMethods = sourceClass.getMetadata().getAnnotatedMethods(Bean.class.getName()); 3 for (MethodMetadata methodMetadata : beanMethods) { 4 configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass)); 5 } 6 7 // Process default methods on interfaces 8 for (SourceClass ifc : sourceClass.getInterfaces()) { 9 beanMethods = ifc.getMetadata().getAnnotatedMethods(Bean.class.getName()); 10 for (MethodMetadata methodMetadata : beanMethods) { 11 if (!methodMetadata.isAbstract()) { 12 // A default method or other concrete method on a Java 8+ interface... 13 configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass)); 14 } 15 } 16 }
最后真实加载beanDefinition是loadBeanDefinitionsForConfigurationClass方法:
1 private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass, 2 TrackedConditionEvaluator trackedConditionEvaluator) { 3 4 if (trackedConditionEvaluator.shouldSkip(configClass)) { 5 String beanName = configClass.getBeanName(); 6 if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) { 7 this.registry.removeBeanDefinition(beanName); 8 } 9 this.importRegistry.removeImportingClassFor(configClass.getMetadata().getClassName()); 10 return; 11 } 12 13 if (configClass.isImported()) { 14 registerBeanDefinitionForImportedConfigurationClass(configClass); 15 } 16 for (BeanMethod beanMethod : configClass.getBeanMethods()) { 17 loadBeanDefinitionsForBeanMethod(beanMethod); 18 } 19 loadBeanDefinitionsFromImportedResources(configClass.getImportedResources()); 20 loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars()); 21 }
相关推荐
@Configuration 和 @Bean 注解用于Java配置,允许开发者用程序的方式定义Spring容器中的bean,取代传统的XML配置文件。 @Value 提供了一种方便的方式来注入简单类型的属性,支持SpEL表达式和外部配置。
6.8.3. 使用Spring IoC来配置AspectJ的切面 6.8.4. 在Spring应用中使用AspectJ Load-time weaving(LTW) 6.9. 其它资源 7. Spring AOP APIs 7.1. 简介 7.2. Spring中的切入点API 7.2.1. 概念 7.2.2. 切入点实施 ...
@Configuration声明当前类是一个配置类 @Bean注解在方法上,声明当前方法的返回值为一个Bean AOP @Aspect 声明是一个切面 拦截规则@After @Before @Around PointCut JoinPoint Spring...
spring-boot-configuration-sample配置模块 spring-boot-import-sample导入实现模块 spring-boot-alias-annotation-sample注解属性别名模块 spring-boot-actuator-sample监控组件模块 spring-boot-enable-sample自动...
6.8.3. 使用Spring IoC来配置AspectJ的切面 6.8.4. 在Spring应用中使用AspectJ Load-time weaving(LTW) 6.9. 其它资源 7. Spring AOP APIs 7.1. 简介 7.2. Spring中的切入点API 7.2.1. 概念 7.2.2. 切入点...
6.8.3. 使用Spring IoC来配置AspectJ的切面 6.8.4. 在Spring应用中使用AspectJ加载时织入(LTW) 6.9. 更多资源 7. Spring AOP APIs 7.1. 简介 7.2. Spring中的切入点API 7.2.1. 概念 7.2.2. 切入点运算 ...
6.8.3. 使用Spring IoC来配置AspectJ的切面 6.8.4. 在Spring应用中使用AspectJ Load-time weaving(LTW) 6.9. 其它资源 7. Spring AOP APIs 7.1. 简介 7.2. Spring中的切入点API 7.2.1. 概念 7.2.2. 切入点...
6.8.3. 使用Spring IoC来配置AspectJ的切面 6.8.4. 在Spring应用中使用AspectJ加载时织入(LTW) 6.9. 更多资源 7. Spring AOP APIs 7.1. 简介 7.2. Spring中的切入点API 7.2.1. 概念 7.2.2. 切入点运算 ...
├─02、基础入门-Spring生态圈.mp4 ├─03、基础入门-SpringBoot的大时代背景.mp4 ├─04、基础入门-SpringBoot官方文档架构.mp4 ├─05、基础入门-SpringBoot-HelloWorld.mp4 ├─06、基础入门-SpringBoot-依赖...
我们首先要能够解析配置文件中的信息,然后建立包含相关信息的对象。最后根据这些信息利用反射机制完成对象的创建。首先我们看一下配置文件所包含的内容: <configuration> , MainApp" /> ...
Spring.NET是一个应用程序框架,其目的是协助开发人员创建企业级的.NET应用程序。它提供了很多方面的功能,比如依赖注入、面向方面编程(AOP)、数据访问抽象及ASP.NET扩展等等。Spring.NET以Java版的Spring框架为...
12.2.1 Configuration(配置Connection) 12.2.2 SessionFactory(Connection工厂) 12.2.3 Session(提供Connection) 12.3 使用Hibernate操作数据库的示例 12.3.1 创建数据库表 12.3.2 编写表对应的JavaBean ...
12.2.1 Configuration(配置Connection) 12.2.2 SessionFactory(Connection工厂) 12.2.3 Session(提供Connection) 12.3 使用Hibernate操作数据库的示例 12.3.1 创建数据库表 12.3.2 编写表对应的JavaBean ...
其中@ComponentScan让Spring Boot扫描到Configuration类并把它加入到程序上下文。 2、@ComponentScan 组件扫描,可自动发现和装配一些Bean。 3、@Configuration 等同于Spring的XML配置文件;使用Java代码可以检查...
12.2.1 Configuration(配置Connection) 12.2.2 SessionFactory(Connection工厂) 12.2.3 Session(提供Connection) 12.3 使用Hibernate操作数据库的示例 12.3.1 创建数据库表 12.3.2 编写表对应的JavaBean ...
专为multipart请求信息使用的org.apache.struts2.dispatcher.multipart.MultiPartRequest解析器接口(文件上传用) struts.multipart.saveDir The directory to use for storing uploaded files 设置存储上传...
使用IDEA搭建了一个springmvc框架 配置了视图解析jsp&freemaker视图解析 可以导入就用接口项目或者web项目都可以使用 配置文件需要修改一下 <!-- 使用SqlSessionFactoryBean工厂产生SqlSession对象,方便后期注入...
12.2.1 Configuration(配置Connection) 12.2.2 SessionFactory(Connection工厂) 12.2.3 Session(提供Connection) 12.3 使用Hibernate操作数据库的示例 12.3.1 创建数据库表 12.3.2 编写表对应的JavaBean ...
SFAF 该SFAF存储库是用于处理MCEB Pub 7或... 类似于基于Configuration over Code的Spring Configuration over Code方法,该方法侧重于外部化代码之外的所有配置,以仅使用配置来重用/重新部署。 此外,与“ Convent
读取并解析hibernate.cfg.xml配置文件 2.由hibernate.cfg.xml中的读取并解析映射信息 3.通过config.buildSessionFactory();//创建SessionFactory 4.sessionFactory.openSession();//打开Sesssion 5.session....