spring-注解驱动模式

spring web装配原理:

 /**
     * WebApplicationInitializer Spring MVC 提供接口。
     *
     * Spring中的web自动配置,也是可以,
     */

    /**
     * AbstractContextLoaderInitializer 装配原理:
     *      ContextLoaderListener是标准ServletContextListener的实现,监听ServletContext生命周期
     *      启动-Servlet调用ServletContextListener实现类的默认方法。contextInitialized
     *      关闭-contextDestroyed
     */

    /**
     * 运行到3.0中,web.xml配置文件中的ContextLoaderListener的方式可替换为AbstractContextLoaderInitializer的实现类
     *      只需要实现createRootApplicationContext()方法
     *
     * 注意:官方不推荐,使用AbstractContextLoaderInitializer进行,ContextLoaderListener允许重复注册到SevletContext。
     * 如果Web应用的ClassPath下同时存在多个AbstractContextLoaderInitializer的实现类,抛异常IllegalStateException
     */

 

public class SpringWeb2 {
    /**
     * AbstractDispatcherServletInitializer装配原理
     *
     * AbstractDispatcherServletInitializer extends AbstractContextLoaderInitializer的子类
     *      补上没有注册DispatcherServlet,且没有实现父类的createRootApplicationContext()
     *      提供注册Filter模板方法
     */
}

 

public class SpringWeb3 {
    /**
     * AbstractAnnotationConfigDispatcherServletInitializer装配原理
     *  由于其父类AbstractDispatcherServletInitializer没有实现createRootApplicationContext()
     *  且需要子类实现:protected abstract WebApplicationContext createServletApplicationContext();
     *
     * 而AbstractAnnotationConfigDispatcherServletInitializer直接实现了这两个方法
     *
     *  Root WebApplicationContext 和DispatcherServlet WebApplicationContext,都
     *  采用注解驱动Web应用上下文实现:AnnotationConfigWebApplicationContext
     *
     */

    /**
     * @Nullable:字段可以为空
     */
}

 

import原理:

/**
 * @author beter.quan
 * @date 2020/10/20 2:20 下午
 */
public class Theory {
    /**
     * 装载@Configuration Class,之前没有@ComponentScan,所以只能使用导入注解@Import
     * <context:annotation-config>对应的BeanDefinitionParser实现为:AnnotationConfigBeanDefinitionParser
     * 里面的方法:public BeanDefinition parse(Element element, ParserContext parserContext)
     *      没有直接解析BeanDefinition实例,调用了
     *      AnnotationConfigUtils.registerAnnotationConfigProcessors(parserContext.getRegistry(), source);
     *
     * @Configuration 处理类ConfigurationClassPostProcessor 被封装为BeanDefinition并注册
     *
     * ConfigurationClassPostProcessor xml配置驱动,注解驱动,都通过registerAnnotationConfigProcessors方法进行装载
     * 且为最高优先级的BeanFactoryPostProcessor实现
     * 注释解析
     * p>This post processor is priority-ordered as it is important that any
     *  * {@link Bean} methods declared in {@code @Configuration} classes have
     *  * their corresponding bean definitions registered before any other
     *  * {@link BeanFactoryPostProcessor} executes.
     *
     */

    /**
     * AbstractApplicationContext#refresh()调用时,spring容器(BeanFactory)将ConfigurationClassPostProcessor 初始化为Bean
     *  随后invokeBeanFactoryPostProcessors实际上是使用:
     *  PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors。这个方法里面;
     *  private static void invokeBeanFactoryPostProcessors(
     *             Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
     *
     *         for (BeanFactoryPostProcessor postProcessor : postProcessors) {
     *             postProcessor.postProcessBeanFactory(beanFactory);
     *                }
     *      调用接口的实现类的postProcessBeanFactory 方法
     *   例如:ConfigurationClassPostProcessor#public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
     *
     *   执行postProcessBeanFactory期间,ConfigurationClassParser是将spring BeanDefinition 进行注解原信息解析
     *   解析的时候有两个parse重载方法,
     *      @Configuration Class被ConfigurationClass 类所抽象,且处理方法为processConfigurationClass,但真正执行的是doProcessConfigurationClass
     *       在doProcessConfigurationClass方法中,@Import @ImportResource @Bean都被处理
     *
     *
     *  解析后,ConfigurationClass集合将被ConfigurationClassBeanDefinitionReader 再次注册Spring Bean
     */

    /**
     * ConfigurationClassBeanDefinitionReader 将@Import @ImportResource @Bean 一并注册
     */
}

 

@Conditional

public class OwnerTest {
    /**
     * @Profile 配置条件装配---静态激活和配置
     */

    /**
     * @Conditional 指定多个或一个Condiction,所有condiction匹配----》条件成立
     *
     * 这里的匹配只的是执行condiction返回true
     * boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
     * ConditionContext这个参数包含Spring应用上下文相关的:BeanDefinitionRegistry,ConfigurableBeanFactory
     */
    /**
     * 还有包括:
     * @ConditionalOnClass
     * @ConditionalOnBean
     * @ConditionalOnProperty
     *
     */
}

 

@conditional原理:

/**
 * @author beter.quan
 * @date 2020/10/20 8:34 下午
 * @Conditional条件装配原理
 */
public class TheoryConditional {
    /**
     * @Conditional(ProfileCondition.class)
     * public @interface Profile
     */
    // ProfileCondition 代码内容一下
    class ProfileCondition implements Condition {
        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
            if (attrs != null) {
                for (Object value : attrs.get("value")) {//
                    if (context.getEnvironment().acceptsProfiles(Profiles.of((String[]) value))) {
                        return true;
                    }
                }
                return false;
            }
            return true;
        }
        /**
         * @Conditional的统一处理实现ConditionEvaluator
         *ConditionEvaluator里面的方法
         * public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase)
         * 将AnnotatedTypeMetadata标注的所有COndition实例一一匹配,不匹配放回true 跳过。
         */
    }
}

 

 

 

 

自定义conditional注解

先定义Condition,实现该接口

/**
 * @author beter.quan
 * @date 2020/10/20 8:10 下午
 */
public class OnSystemPropertyCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // 获取ConditionalOnSystemProperty所有属性方法的值,这里就是属性名name对应的值
        MultiValueMap<String, Object> attibutes = metadata.getAllAnnotationAttributes(ConditionalOnSystemProperty.class.getName());
        String propertyName = (String) attibutes.getFirst("name");
        String propertyValue = (String) attibutes.getFirst("value");
        String systemPropertyValue = System.getProperty(propertyName);
        if (Objects.equals(systemPropertyValue, propertyValue)) {
            System.out.printf("属性名称 %s 找到匹配 %s", propertyName, propertyValue);
            return true;
        }
        return false;
    }
}

 

编写自定义条件注解

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnSystemPropertyCondition.class)
public @interface ConditionalOnSystemProperty {
    String name();

    String value();
}

 

编写配置类

@Configuration
public class CondictionalMessageConfiguration {
    @ConditionalOnSystemProperty(name = "language", value = "Chinese")
    @Bean("message")
    public String cMessage() {
        return "中文";
    }

    @ConditionalOnSystemProperty(name = "language", value = "English")
    @Bean("message")
    public String eMessage() {
        return "English";
    }

}

测试

/**
 * @author beter.quan
 * @date 2020/10/20 8:22 下午
 */
public class ConditionalTest {
    public static void main(String[] args) {
        System.setProperty("language", "English");
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(CondictionalMessageConfiguration.class);
        context.refresh();
        String message = context.getBean("message", String.class);
        System.out.println(message);
    }
}

 

posted @ 2020-10-21 08:59  小丑quan  阅读(375)  评论(0)    收藏  举报