01 SpringBoot自动装配入门核心原理

文章目录

    • 自动装配
      • SpringFrame手动装配
        • Spring模式注解:
          • 注解的层次性和派生性
      • @Enable模块装配
      • Spring条件装配
        • 基于profile配置化装配方式
        • 基于conditional编程化方式条件装配
      • SpringBoot自动配置
      • 总结

自动装配

SpringFrame手动装配

Spring模式注解:

生命在应用中扮演组件角色的注解

@Component @Service @Configuration

不同注解代表了组件在springApplication中的角色。

注解的层次性和派生性
  • @Component
    • @Repository
      • FirstLevelRepository
        • SecondLevelRepository

SecondLevelRepository继承自元注解@Component,他也具备其特性。被@SecondLevelRepository标注的注解,也是ComponentScan的扫描和加载的对象。


@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repository
public @interface FirstLevelRepository {
    String value() default "";
}


/**
 * 层次性:一级的注解可以用来标注二级注解
 * 派生性: 每层注解集成上级注解的特性
 */


@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@FirstLevelRepository
public @interface SecondLevelRepository {
    String value() default "";
}

@Enable模块装配

Spring Framework 3.1 开始支持”@Enable 模块驱动“。所谓“模块”是指具备相同领域的功能组件集合, 组合所形成一个独立的单元。比如 Web MVC 模块、AspectJ代理模块、Caching(缓存)模块、JMX(Java 管 理扩展)模块、Async(异步处理)模块等。

@EnableWebMvc、@EnableAutoConfigruation

自定义enable模块

配置类用来生成HelloWoldBean

@Configuration
public class HelloWorldConfiguration {

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

启动类用来获取容器中的bean这里使用了@EnableHelloWorld注解来自定义容器中的bean

@EnableHelloWorld
public class EnableHelloWorldBootstrap {
    public static void main(String[] args) {

        ConfigurableApplicationContext context = new SpringApplicationBuilder(EnableHelloWorldBootstrap.class)
                .web(WebApplicationType.NONE)
                .run(args);


        String helloWorld = context.getBean("helloWorld", String.class);

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

        //close context
        context.close();

    }

}

自定义EnableHelloWorld注解

import java.lang.annotation.*;

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

注意:这里有两种方式@Import,第一种直接引入HelloWorldConfiguration类,这样只能创建该配置生成的bean

第二种方式,通过ImportSelector的方法,动态选择注入的bean对象,更加的灵活

@Configuration
public class HelloWorldImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {

        //在选择其中可以选择不同的Helloworld实现方式
        return  new String[]{HelloWorldConfiguration.class.getName()};
    }
}

Spring条件装配

在装配Bean前做判断是否加载bean

  • @Profile 配置化条件装配
  • @Contitional 编程化条件装配

基于profile配置化装配方式

profile用法有一定局限性,Contitional是更普遍的用法

@Service
@Profile("java7")
public class Java7CalculateServiceImpl implements CalculateService {
    @Override
    public Integer sum(Integer... values) {
        System.out.println("java7 implement");
        return Stream.of(values).reduce(0,Integer::sum);
    }
}

@Service
@Profile("java8")
public class Java8CalculateServiceImpl implements CalculateService {
    @Override
    public Integer sum(Integer... values) {
        System.out.println("java8 implement");
        return Stream.of(values).reduce(0,Integer::sum);
    }
}
@ComponentScan(basePackages = "com.kouryoushine.springbootlearingexample.service")
public class CalculateServiceBootStrap {

    public static void main(String[] args) {

        ConfigurableApplicationContext context = new SpringApplicationBuilder(CalculateServiceBootStrap.class)
                .web(WebApplicationType.NONE)
                .profiles("java7")
                .run(args);


        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));

        //close context
        context.close();

    }
}

基于conditional编程化方式条件装配

自定义一个拥有条件装配的注解ConditionalOnSystemProperty,包含了2个属性

/**
 * java系统属性判断
 */

import org.springframework.context.annotation.Conditional;

import java.lang.annotation.*;

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

    String name();  //系统参数名
    String value(); //参数值
}

定义条件判断的class,OnSystemPropertyCondition

  • 获取注解的属性并和系统属性判断,如果相等则返回ture,否则返回false
/**
 * 系统属性条件判断
 */
public class OnSystemPropertyCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        
        //获取注解ConditionalOnSystemProperty的属性和值
        Map annotationAttributes = annotatedTypeMetadata.getAnnotationAttributes(ConditionalOnSystemProperty.class.getName());
        String name = String.valueOf( annotationAttributes.get("name"));
        String value = String.valueOf( annotationAttributes.get("value"));
        String javaPropertyValue = System.getProperty(name);

        //判断注解传入的value值是否等于系统参数

        return value.equals(javaPropertyValue);
    }
}

测试

判断系统用户名是否是Administrator,如果是则注入helloworldBean,否则不注入

/**
 * 系统属性判断
 */

public class SystemPropertyConditionBootstrap {

    //条件满足是才会装载helloWorldbean
    @Bean
    @ConditionalOnSystemProperty(name = "user.name",value = "Administrator")
    public String helloWorld(){
        return "Hello WOrld Admin";
    }

    public static void main(String[] args) {

        ConfigurableApplicationContext context = new SpringApplicationBuilder(SystemPropertyConditionBootstrap.class)
                .web(WebApplicationType.NONE)
                .run(args);

        String  helloworld = context.getBean("helloWorld",String.class);
        System.out.println(helloworld);
        //close context
        context.close();

    }
}

SpringBoot自动配置

SpringBoot准守约定大于配置原则,使用了下面几种底层装配技术

  • Spring 模式注解装配
  • SPring @Enable模块装配
  • Spring 条件装配
  • Spring 工厂加载机制

在启动类里加入@EnableAutoConfiguration注解,就会通过Meta-INF的spring.factories的文件扫描对应的类

@EnableAutoConfiguration
public class EnableAutoConfigurationBootStrap {
    public static void main(String[] args) {

        ConfigurableApplicationContext context = new SpringApplicationBuilder(EnableAutoConfigurationBootStrap.class)
                .web(WebApplicationType.NONE)
                .run(args);

        String helloWorld = context.getBean("helloWorld", String.class);
        System.out.println("helloworld Bean:"+helloWorld);
        //close context
        context.close();

    }
}

META-INF/spring.factories文件内容,指定自动装配对象

# 将HelloWorldAutoConfiguration类指定为自动装配的对象
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.kouryoushine.springbootlearingexample.configuration.HelloWorldAutoConfiguration

这里三个注解融合了本文的全部内容

  1. 添加到容器
  2. 添加的模块,包含了selector功能
  3. 添加的条件
/**
 * HelloWorld自动装配
 */
@Configuration  //注解模式装配
@EnableHelloWorld  //enable模块装配
@ConditionalOnSystemProperty(name = "user.name",value = "Administrator") //条件装配
public class HelloWorldAutoConfiguration {

    //@EnableHelloWorld 避免了模块化的开发

}

总结

springboot的自动装配是通过springframework 的手动装配模式一步一步构建的。

你可能感兴趣的:(springboot)