spring源码分析之@Conditional
根源在AnnotationConfigApplicationContext和AnnotationConfigWebApplicationContext,以AnnotationConfigApplicationContext為例:
1.構(gòu)造方法
/*** Create a new AnnotationConfigApplicationContext, deriving bean definitions* from the given annotated classes and automatically refreshing the context.* @param annotatedClasses one or more annotated classes,* e.g. {@link Configuration @Configuration} classes*/public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {this(); register(annotatedClasses);refresh();}/*** Create a new AnnotationConfigApplicationContext, scanning for bean definitions* in the given packages and automatically refreshing the context.* @param basePackages the packages to check for annotated classes*/public AnnotationConfigApplicationContext(String... basePackages) {this();scan(basePackages);refresh();}一種是注解類方式,一種是掃描方式,殊途同歸。以注解類來(lái)分析:
/*** Register one or more annotated classes to be processed.* <p>Note that {@link #refresh()} must be called in order for the context* to fully process the new classes.* @param annotatedClasses one or more annotated classes,* e.g. {@link Configuration @Configuration} classes* @see #scan(String...)* @see #refresh()*/public void register(Class<?>... annotatedClasses) {Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");this.reader.register(annotatedClasses);}2. 實(shí)現(xiàn)方法AnnotatedBeanDefinitionReader
public void register(Class<?>... annotatedClasses) {for (Class<?> annotatedClass : annotatedClasses) {registerBean(annotatedClass);}}具體邏輯還是在該類內(nèi)部:
@SuppressWarnings("unchecked")public void registerBean(Class<?> annotatedClass, Class<? extends Annotation>... qualifiers) {registerBean(annotatedClass, null, qualifiers);}@SuppressWarnings("unchecked")public void registerBean(Class<?> annotatedClass, String name, Class<? extends Annotation>... qualifiers) {AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {return;}ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);abd.setScope(scopeMetadata.getScopeName());String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);if (qualifiers != null) {for (Class<? extends Annotation> qualifier : qualifiers) {if (Primary.class == qualifier) {abd.setPrimary(true);}else if (Lazy.class == qualifier) {abd.setLazyInit(true);}else {abd.addQualifier(new AutowireCandidateQualifier(qualifier));}}}BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);}3.分析邏輯
3.1?ConditionEvaluator
/*** Determine if an item should be skipped based on {@code @Conditional} annotations.* @param metadata the meta data* @param phase the phase of the call* @return if the item should be skipped*/public boolean shouldSkip(AnnotatedTypeMetadata metadata, ConfigurationPhase phase) {if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {return false;}if (phase == null) {if (metadata instanceof AnnotationMetadata &&ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);}return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);}List<Condition> conditions = new ArrayList<>();for (String[] conditionClasses : getConditionClasses(metadata)) {for (String conditionClass : conditionClasses) {Condition condition = getCondition(conditionClass, this.context.getClassLoader());conditions.add(condition);}}AnnotationAwareOrderComparator.sort(conditions);for (Condition condition : conditions) {ConfigurationPhase requiredPhase = null;if (condition instanceof ConfigurationCondition) {requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();}if (requiredPhase == null || requiredPhase == phase) {if (!condition.matches(this.context, metadata)) {return true;}}}3.2 大魚AnnotationConfigUtils來(lái)了
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);if (qualifiers != null) {for (Class<? extends Annotation> qualifier : qualifiers) {if (Primary.class == qualifier) {abd.setPrimary(true);}else if (Lazy.class == qualifier) {abd.setLazyInit(true);}else {abd.addQualifier(new AutowireCandidateQualifier(qualifier));}}}通用注解(lazy、primary、DependsOn、role、description)實(shí)現(xiàn):
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {if (metadata.isAnnotated(Lazy.class.getName())) {abd.setLazyInit(attributesFor(metadata, Lazy.class).getBoolean("value"));}else if (abd.getMetadata() != metadata && abd.getMetadata().isAnnotated(Lazy.class.getName())) {abd.setLazyInit(attributesFor(abd.getMetadata(), Lazy.class).getBoolean("value"));}if (metadata.isAnnotated(Primary.class.getName())) {abd.setPrimary(true);}if (metadata.isAnnotated(DependsOn.class.getName())) {abd.setDependsOn(attributesFor(metadata, DependsOn.class).getStringArray("value"));}if (abd instanceof AbstractBeanDefinition) {AbstractBeanDefinition absBd = (AbstractBeanDefinition) abd;if (metadata.isAnnotated(Role.class.getName())) {absBd.setRole(attributesFor(metadata, Role.class).getNumber("value").intValue());}if (metadata.isAnnotated(Description.class.getName())) {absBd.setDescription(attributesFor(metadata, Description.class).getString("value"));}}}3.3 釣上大魚,處理注解的相關(guān)processor在這里注冊(cè):
/*** Register all relevant annotation post processors in the given registry.* @param registry the registry to operate on* @param source the configuration source element (already extracted)* that this registration was triggered from. May be {@code null}.* @return a Set of BeanDefinitionHolders, containing all bean definitions* that have actually been registered by this call*/public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, Object source) {DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);if (beanFactory != null) {if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);}if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());}}Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(4);if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));}if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));}if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));}// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));}// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition();try {def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,AnnotationConfigUtils.class.getClassLoader()));}catch (ClassNotFoundException ex) {throw new IllegalStateException("Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);}def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));}if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));}if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));}return beanDefs;}private static BeanDefinitionHolder registerPostProcessor(BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);registry.registerBeanDefinition(beanName, definition);return new BeanDefinitionHolder(definition, beanName);}3.3.1?ConfigurationClassPostProcessor
/*** {@link BeanFactoryPostProcessor} used for bootstrapping processing of* {@link Configuration @Configuration} classes.** <p>Registered by default when using {@code <context:annotation-config/>} or* {@code <context:component-scan/>}. Otherwise, may be declared manually as* with any other BeanFactoryPostProcessor.** <p>This post processor is {@link Ordered#HIGHEST_PRECEDENCE} as it is important* that any {@link Bean} methods declared in Configuration classes have their* respective bean definitions registered before any other BeanFactoryPostProcessor* executes.** @author Chris Beams* @author Juergen Hoeller* @author Phillip Webb* @since 3.0*/ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware { }3.3.2?AutowiredAnnotationBeanPostProcessor
/*** {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation* that autowires annotated fields, setter methods and arbitrary config methods.* Such members to be injected are detected through a Java 5 annotation: by default,* Spring's {@link Autowired @Autowired} and {@link Value @Value} annotations.** <p>Also supports JSR-330's {@link javax.inject.Inject @Inject} annotation,* if available, as a direct alternative to Spring's own {@code @Autowired}.** <p>Only one constructor (at max) of any given bean class may carry this* annotation with the 'required' parameter set to {@code true},* indicating <i>the</i> constructor to autowire when used as a Spring bean.* If multiple <i>non-required</i> constructors carry the annotation, they* will be considered as candidates for autowiring. The constructor with* the greatest number of dependencies that can be satisfied by matching* beans in the Spring container will be chosen. If none of the candidates* can be satisfied, then a default constructor (if present) will be used.* An annotated constructor does not have to be public.** <p>Fields are injected right after construction of a bean, before any* config methods are invoked. Such a config field does not have to be public.** <p>Config methods may have an arbitrary name and any number of arguments; each of* those arguments will be autowired with a matching bean in the Spring container.* Bean property setter methods are effectively just a special case of such a* general config method. Config methods do not have to be public.** <p>Note: A default AutowiredAnnotationBeanPostProcessor will be registered* by the "context:annotation-config" and "context:component-scan" XML tags.* Remove or turn off the default annotation configuration there if you intend* to specify a custom AutowiredAnnotationBeanPostProcessor bean definition.* <p><b>NOTE:</b> Annotation injection will be performed <i>before</i> XML injection;* thus the latter configuration will override the former for properties wired through* both approaches.** <p>In addition to regular injection points as discussed above, this post-processor* also handles Spring's {@link Lookup @Lookup} annotation which identifies lookup* methods to be replaced by the container at runtime. This is essentially a type-safe* version of {@code getBean(Class, args)} and {@code getBean(String, args)},* See {@link Lookup @Lookup's javadoc} for details.** @author Juergen Hoeller* @author Mark Fisher* @author Stephane Nicoll* @since 2.5* @see #setAutowiredAnnotationType* @see Autowired* @see Value*/ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapterimplements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware { }3.3.3?RequiredAnnotationBeanPostProcessor
/*** {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation* that enforces required JavaBean properties to have been configured.* Required bean properties are detected through a Java 5 annotation:* by default, Spring's {@link Required} annotation.** <p>The motivation for the existence of this BeanPostProcessor is to allow* developers to annotate the setter properties of their own classes with an* arbitrary JDK 1.5 annotation to indicate that the container must check* for the configuration of a dependency injected value. This neatly pushes* responsibility for such checking onto the container (where it arguably belongs),* and obviates the need (<b>in part</b>) for a developer to code a method that* simply checks that all required properties have actually been set.** <p>Please note that an 'init' method may still need to implemented (and may* still be desirable), because all that this class does is enforce that a* 'required' property has actually been configured with a value. It does* <b>not</b> check anything else... In particular, it does not check that a* configured value is not {@code null}.** <p>Note: A default RequiredAnnotationBeanPostProcessor will be registered* by the "context:annotation-config" and "context:component-scan" XML tags.* Remove or turn off the default annotation configuration there if you intend* to specify a custom RequiredAnnotationBeanPostProcessor bean definition.** @author Rob Harrop* @author Juergen Hoeller* @since 2.0* @see #setRequiredAnnotationType* @see Required*/ public class RequiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapterimplements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware { }3.3.4?CommonAnnotationBeanPostProcessor
/*** {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation* that supports common Java annotations out of the box, in particular the JSR-250* annotations in the {@code javax.annotation} package. These common Java* annotations are supported in many Java EE 5 technologies (e.g. JSF 1.2),* as well as in Java 6's JAX-WS.** <p>This post-processor includes support for the {@link javax.annotation.PostConstruct}* and {@link javax.annotation.PreDestroy} annotations - as init annotation* and destroy annotation, respectively - through inheriting from* {@link InitDestroyAnnotationBeanPostProcessor} with pre-configured annotation types.** <p>The central element is the {@link javax.annotation.Resource} annotation* for annotation-driven injection of named beans, by default from the containing* Spring BeanFactory, with only {@code mappedName} references resolved in JNDI.* The {@link #setAlwaysUseJndiLookup "alwaysUseJndiLookup" flag} enforces JNDI lookups* equivalent to standard Java EE 5 resource injection for {@code name} references* and default names as well. The target beans can be simple POJOs, with no special* requirements other than the type having to match.** <p>The JAX-WS {@link javax.xml.ws.WebServiceRef} annotation is supported too,* analogous to {@link javax.annotation.Resource} but with the capability of creating* specific JAX-WS service endpoints. This may either point to an explicitly defined* resource by name or operate on a locally specified JAX-WS service class. Finally,* this post-processor also supports the EJB 3 {@link javax.ejb.EJB} annotation,* analogous to {@link javax.annotation.Resource} as well, with the capability to* specify both a local bean name and a global JNDI name for fallback retrieval.* The target beans can be plain POJOs as well as EJB 3 Session Beans in this case.** <p>The common annotations supported by this post-processor are available in* Java 6 (JDK 1.6) as well as in Java EE 5/6 (which provides a standalone jar for* its common annotations as well, allowing for use in any Java 5 based application).** <p>For default usage, resolving resource names as Spring bean names,* simply define the following in your application context:** <pre class="code">* <bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/></pre>** For direct JNDI access, resolving resource names as JNDI resource references* within the Java EE application's "java:comp/env/" namespace, use the following:** <pre class="code">* <bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor">* <property name="alwaysUseJndiLookup" value="true"/>* </bean></pre>** {@code mappedName} references will always be resolved in JNDI,* allowing for global JNDI names (including "java:" prefix) as well. The* "alwaysUseJndiLookup" flag just affects {@code name} references and* default names (inferred from the field name / property name).** <p><b>NOTE:</b> A default CommonAnnotationBeanPostProcessor will be registered* by the "context:annotation-config" and "context:component-scan" XML tags.* Remove or turn off the default annotation configuration there if you intend* to specify a custom CommonAnnotationBeanPostProcessor bean definition!* <p><b>NOTE:</b> Annotation injection will be performed <i>before</i> XML injection; thus* the latter configuration will override the former for properties wired through* both approaches.** @author Juergen Hoeller* @since 2.5* @see #setAlwaysUseJndiLookup* @see #setResourceFactory* @see org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor* @see org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor*/ @SuppressWarnings("serial") public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessorimplements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable { }3.3.5?PersistenceAnnotationBeanPostProcessor
/*** BeanPostProcessor that processes {@link javax.persistence.PersistenceUnit}* and {@link javax.persistence.PersistenceContext} annotations, for injection of* the corresponding JPA resources {@link javax.persistence.EntityManagerFactory}* and {@link javax.persistence.EntityManager}. Any such annotated fields or methods* in any Spring-managed object will automatically be injected.** <p>This post-processor will inject sub-interfaces of {@code EntityManagerFactory}* and {@code EntityManager} if the annotated fields or methods are declared as such.* The actual type will be verified early, with the exception of a shared ("transactional")* {@code EntityManager} reference, where type mismatches might be detected as late* as on the first actual invocation.** <p>Note: In the present implementation, PersistenceAnnotationBeanPostProcessor* only supports {@code @PersistenceUnit} and {@code @PersistenceContext}* with the "unitName" attribute, or no attribute at all (for the default unit).* If those annotations are present with the "name" attribute at the class level,* they will simply be ignored, since those only serve as deployment hint* (as per the Java EE specification).** <p>This post-processor can either obtain EntityManagerFactory beans defined* in the Spring application context (the default), or obtain EntityManagerFactory* references from JNDI ("persistence unit references"). In the bean case,* the persistence unit name will be matched against the actual deployed unit,* with the bean name used as fallback unit name if no deployed name found.* Typically, Spring's {@link org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean}* will be used for setting up such EntityManagerFactory beans. Alternatively,* such beans may also be obtained from JNDI, e.g. using the {@code jee:jndi-lookup}* XML configuration element (with the bean name matching the requested unit name).* In both cases, the post-processor definition will look as simple as this:** <pre class="code">* <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/></pre>** In the JNDI case, specify the corresponding JNDI names in this post-processor's* {@link #setPersistenceUnits "persistenceUnits" map}, typically with matching* {@code persistence-unit-ref} entries in the Java EE deployment descriptor.* By default, those names are considered as resource references (according to the* Java EE resource-ref convention), located underneath the "java:comp/env/" namespace.* For example:** <pre class="code">* <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor">* <property name="persistenceUnits">* <map/gt;* <entry key="unit1" value="persistence/unit1"/>* <entry key="unit2" value="persistence/unit2"/>* </map/gt;* </property>* </bean></pre>** In this case, the specified persistence units will always be resolved in JNDI* rather than as Spring-defined beans. The entire persistence unit deployment,* including the weaving of persistent classes, is then up to the Java EE server.* Persistence contexts (i.e. EntityManager references) will be built based on* those server-provided EntityManagerFactory references, using Spring's own* transaction synchronization facilities for transactional EntityManager handling* (typically with Spring's {@code @Transactional} annotation for demarcation* and {@link org.springframework.transaction.jta.JtaTransactionManager} as backend).** <p>If you prefer the Java EE server's own EntityManager handling, specify entries* in this post-processor's {@link #setPersistenceContexts "persistenceContexts" map}* (or {@link #setExtendedPersistenceContexts "extendedPersistenceContexts" map},* typically with matching {@code persistence-context-ref} entries in the* Java EE deployment descriptor. For example:** <pre class="code">* <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor">* <property name="persistenceContexts">* <map/gt;* <entry key="unit1" value="persistence/context1"/>* <entry key="unit2" value="persistence/context2"/>* </map/gt;* </property>* </bean></pre>** If the application only obtains EntityManager references in the first place,* this is all you need to specify. If you need EntityManagerFactory references* as well, specify entries for both "persistenceUnits" and "persistenceContexts",* pointing to matching JNDI locations.** <p><b>NOTE: In general, do not inject EXTENDED EntityManagers into STATELESS beans,* i.e. do not use {@code @PersistenceContext} with type {@code EXTENDED} in* Spring beans defined with scope 'singleton' (Spring's default scope).</b>* Extended EntityManagers are <i>not</i> thread-safe, hence they must not be used* in concurrently accessed beans (which Spring-managed singletons usually are).** <p>Note: A default PersistenceAnnotationBeanPostProcessor will be registered* by the "context:annotation-config" and "context:component-scan" XML tags.* Remove or turn off the default annotation configuration there if you intend* to specify a custom PersistenceAnnotationBeanPostProcessor bean definition.** @author Rod Johnson* @author Juergen Hoeller* @since 2.0* @see javax.persistence.PersistenceUnit* @see javax.persistence.PersistenceContext*/ @SuppressWarnings("serial") public class PersistenceAnnotationBeanPostProcessorimplements InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor,MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware, Serializable {3.3.6?EventListenerMethodProcessor
/*** Register {@link EventListener} annotated method as individual {@link ApplicationListener}* instances.** @author Stephane Nicoll* @author Juergen Hoeller* @since 4.2*/ public class EventListenerMethodProcessor implements SmartInitializingSingleton, ApplicationContextAware { }3.3.7?DefaultEventListenerFactory
/*** Default {@link EventListenerFactory} implementation that supports the* regular {@link EventListener} annotation.* <p>Used as "catch-all" implementation by default.** @author Stephane Nicoll* @since 4.2*/ public class DefaultEventListenerFactory implements EventListenerFactory, Ordered { }扯遠(yuǎn)了,就此打住!
?
轉(zhuǎn)載于:https://www.cnblogs.com/davidwang456/p/6274583.html
總結(jié)
以上是生活随笔為你收集整理的spring源码分析之@Conditional的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 设置tomcat远程debug
- 下一篇: tomcat指定配置文件路径方法