Spring的模式注解装配、@Enable模块装配、条件装配与工厂加载机制

前言:这是在慕课网上学习Spring Boot2.0深度实践之核心技术篇 时所做的笔记,主要供本人复习之用.

目录

第一章 Spirng模式注解装配

1.1 模式注解举例

1.2 装配方式:

1.3 自定义模式注解

第二章 Spring @Enable模块装配

2.1 基于注解驱动

2.2 基于接口驱动实现

第三章 Spirng条件装配

3.1 基于配置方式实现 @Profile

3.2 基于编程方式实现

3.2.1 OnSystemPropertyCondition

3.2.2 ConditioanlOnSystemProperty

3.3.3 应用

第四章 工厂加载机制

4.1 通过EnableAutoConfiguration激活自动装配

4.2 实现自动装配:

4.3 配置到自动化装配文件里:


第一章 Spirng模式注解装配

模式注解一种用于声明在应用中扮演"组件"角色的注解,即标注了这个注解,表明一个类等在应用中扮演组件.

应用指的是Spring或SpringBoot应用,

1.1 模式注解举例

@component作为一种由Spirng容器托管的通用模式组件,任何被@Component标准的组件均为组件扫描的候选对象.类似的,凡是被@Component原标注的注解,如@Service,任何组件标注它时,也将被是做组件扫描的候选对象.

1.2 装配方式:

装配方式:<context:component-scan>(Spring 2.5)或@ComponentScan(Spring 3.1)

1.3 自定义模式注解

模式注解的派生性:

@component,@Repository,@FirstLevelRepository注解,都有value签名,保留了签名的一致性,这就是注解的派生性.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {

	String value() default "";

}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Repository {
	@AliasFor(annotation = Component.class)
	String value() default "";
}

 

模式注解的层次性:

我们声明二级注解SecondLevelRepository,我们的SecondLevelRepository派生于FirstLevelRepository,这就是层次性.

@SecondLevelRepository(value = "myFirstLevelRepository") // Bean 名称
public class MyFirstLevelRepository {
}

 我们的@SpringBootAppliacation也是模式注解.

 

第二章 Spring @Enable模块装配

模块装配的举例:

2.1 基于注解驱动

Import可以导入多个类,只不过这里我们只导入了一个.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(HelloWorldConfiguration.class)
public @interface EnableHelloWorld {
}

 

public class HelloWorldConfiguration {

    @Bean
    public String helloWorld() { // 方法名即 Bean 名称
        return "Hello,World 2018";
    }

}

 完成以上两步后,意味着只要我们EnableHelloWorld的注解标注在某个类上时,我们的Bean就已经存在了.

@EnableHelloWorld
public class EnableHelloWorldBootstrap {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = new SpringApplicationBuilder(EnableHelloWorldBootstrap.class)
                .web(WebApplicationType.NONE)
                .run(args);

        // helloWorld Bean 是否存在
        String helloWorld =
                context.getBean("helloWorld", String.class);

        System.out.println("helloWorld Bean : " + helloWorld);

        // 关闭上下文
        context.close();
    }
}

 

2.2 基于接口驱动实现

加载过程:HelloWorldImportSelector->helloWorldConfiguration->HelloWorld

我们用下面的Selector进行一个导入,导入之后变成了helloword Bean.这样的好处是可以通过编程来控制哪个要变成Bean.

public class HelloWorldConfiguration {

    @Bean
    public String helloWorld() { // 方法名即 Bean 名称
        return "Hello,World 2018";
    }

}
public class HelloWorldImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{HelloWorldConfiguration.class.getName()};
    }
}

 

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(HelloWorldImportSelector.class)
public @interface EnableHelloWorld {
}

 

第三章 Spirng条件装配

版本:在Spring3.0推出了@Configuration,3.1推出了ImportSelector

定义:Bean装配的前置判断

举例:@Profile ,@Conditional

实现:注解方式,编程方式.

3.1 基于配置方式实现 @Profile

计算服务,多整数求和sum

public interface CalculateService {

    Integer sum(Integer... values);
}

@Profile("Java7")  for循环实现

@Profile("Java7")
@Service
public class Java7CalculateService implements CalculateService {

    @Override
    public Integer sum(Integer... values) {
        System.out.println("Java 7 for 循环实现 ");
        int sum = 0;
        for (int i = 0; i < values.length; i++) {
            sum += values[i];
        }
        return sum;
    }

    public static void main(String[] args) {
        CalculateService calculateService = new Java7CalculateService();
        System.out.println(calculateService.sum(1,2,3,4,5,6,7,8,9,10));
    }

}

@Profile("Java8") Lamda表达式实现

@Profile("Java8")
@Service
public class Java8CalculateService implements CalculateService {

    @Override
    public Integer sum(Integer... values) {
        System.out.println("Java 8 Lambda 实现");
        int sum = Stream.of(values).reduce(0, Integer::sum);
        return sum;
    }

    public static void main(String[] args) {
        CalculateService calculateService = new Java8CalculateService();
        System.out.println(calculateService.sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
    }

}

Java8使用:

@SpringBootApplication(scanBasePackages = "com.imooc.diveinspringboot.service")
public class CalculateServiceBootstrap {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = new SpringApplicationBuilder(CalculateServiceBootstrap.class)
                .web(WebApplicationType.NONE)
                .profiles("Java8")
                .run(args);

        // CalculateService Bean 是否存在
        CalculateService calculateService = context.getBean(CalculateService.class);

        System.out.println("calculateService.sum(1...10) : " +
                calculateService.sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));

        // 关闭上下文
        context.close();
    }
}

 

3.2 基于编程方式实现

Spring4之后Profile的实现是通过@Contional(ProfileCondition.class)来实现的.

AnnotatedTypeMetadata保存的是一些元信息.用来获得注解的一些信息.

实现(模仿的是ConditionalOnProperty):

3.2.1 OnSystemPropertyCondition

如果返回true表示参数正确,建立对应的Bean.

public class OnSystemPropertyCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {

        Map<String, Object> attributes = metadata.getAnnotationAttributes(ConditionalOnSystemProperty.class.getName());

        String propertyName = String.valueOf(attributes.get("name"));

        String propertyValue = String.valueOf(attributes.get("value"));

        String javaPropertyValue = System.getProperty(propertyName);

        return propertyValue.equals(javaPropertyValue);
    }
}

3.2.2 ConditioanlOnSystemProperty

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
@Conditional(OnSystemPropertyCondition.class)
public @interface ConditionalOnSystemProperty {

    /**
     * Java 系统属性名称
     * @return
     */
    String name();

    /**
     * Java 系统属性值
     * @return
     */
    String value();
}

3.3.3 应用

在matches函数中,取出来的name是user.name,value是Mercy.就是注解在上面的值.

public class ConditionalOnSystemPropertyBootstrap {

    @Bean
    @ConditionalOnSystemProperty(name = "user.name", value = "Mercy")
    public String helloWorld() {
        return "Hello,World 小马哥";
    }

    public static void main(String[] args) {
        ConfigurableApplicationContext context = new SpringApplicationBuilder(ConditionalOnSystemPropertyBootstrap.class)
                .web(WebApplicationType.NONE)
                .run(args);
        // 通过名称和类型获取 helloWorld Bean
        String helloWorld = context.getBean("helloWorld", String.class);

        System.out.println("helloWorld Bean : " + helloWorld);

        // 关闭上下文
        context.close();
    }
}

第四章 工厂加载机制

更详细的可以看:https://blog.csdn.net/q610376681/article/details/88578155

定义:基于约定大于配置的原则,实现Spring组件自动装配的目的.

装配:模式注解,@Enable模块,条件装配,工厂加载机制

实现:激活自动装配,实现自动装配,配置自动装配实现.

是SpringBoot主要使用的自动装配机制

原理:由SpringFactoriesLoader的loadFactories进行加载,通过for循环进行迭代装配所有依赖中META-INF/Spring.facorties里的值.

public static <T> List<T> loadFactories(Class<T> factoryClass, @Nullable ClassLoader classLoader) {
		Assert.notNull(factoryClass, "'factoryClass' must not be null");
		ClassLoader classLoaderToUse = classLoader;
		if (classLoaderToUse == null) {
			classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
		}
		List<String> factoryNames = loadFactoryNames(factoryClass, classLoaderToUse);
		if (logger.isTraceEnabled()) {
			logger.trace("Loaded [" + factoryClass.getName() + "] names: " + factoryNames);
		}
		List<T> result = new ArrayList<>(factoryNames.size());
		for (String factoryName : factoryNames) {
			result.add(instantiateFactory(factoryName, factoryClass, classLoaderToUse));
		}
		AnnotationAwareOrderComparator.sort(result);
		return result;
	}

实现:

4.1 通过EnableAutoConfiguration激活自动装配

@EnableAutoConfiguration
public class EnableAutoConfigurationBootstrap {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = new SpringApplicationBuilder(EnableAutoConfigurationBootstrap.class)
                .web(WebApplicationType.NONE)
                .run(args);

        // helloWorld Bean 是否存在
        String helloWorld =
                context.getBean("helloWorld", String.class);

        System.out.println("helloWorld Bean : " + helloWorld);

        // 关闭上下文
        context.close();

    }
}

4.2 实现自动装配:

@EnableHelloWorld的定义可以参考1.2.2节,@ConditionalOnSystemProperty可以参考1.3.1节.

@Configuration // Spring 模式注解装配
@EnableHelloWorld // Spring @Enable 模块装配
@ConditionalOnSystemProperty(name = "user.name", value = "Mercy") // 条件装配
public class HelloWorldAutoConfiguration {
}

4.3 配置到自动化装配文件里:

在resource中新建META-INF,在META-INF中新建Spring.factories,写入以下内容,\用于换行.

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.imooc.diveinspringboot.configuration.HelloWorldAutoConfiguration

流程:

首先进行ConditionalOnSystemProperty的判断,如果满足条件就进行下一步.

然后使用模式注解配置为Bean.

@Enable模块:@EnableHelloword->HelloWorldImportSelector->HelloWorldConfiguration->最终生成HelloWordBean.

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值