根源在AnnotationConfigApplicationContext和AnnotationConfigWebApplicationContext,以AnnotationConfigApplicationContext为例:
1.构造方法
/** * 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(); }
一种是注解类方式,一种是扫描方式,殊途同归。以注解类来分析:
/** * 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. 实现方法AnnotatedBeanDefinitionReader
public void register(Class<?>... annotatedClasses) { for (Class<?> annotatedClass : annotatedClasses) { registerBean(annotatedClass); } }
具体逻辑还是在该类内部:
@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来了
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)实现:
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 钓上大鱼,处理注解的相关processor在这里注册:
/** * 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 InstantiationAwareBeanPostProcessorAdapter implements 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 InstantiationAwareBeanPostProcessorAdapter implements 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 InitDestroyAnnotationBeanPostProcessor implements 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 PersistenceAnnotationBeanPostProcessor implements 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 { }
扯远了,就此打住!
微信公众号: 架构师日常笔记 欢迎关注!