springboot-自动装配

Spring 模式注解

模式注解是一种用于声明在应用中扮演“组件”角色的注解。如 Spring Framework 中的 @Repository 标注在任何类上 ,用于扮演仓储角色的模式注解。
@Component 作为一种由 Spring 容器托管的通用模式组件,任何被 @Component 标注的组件均为组件扫描的候选对象。凡是被 @Component 元标注的注解标注时,如 @Service ,也被视作组件扫描的候选对象。

装配方式

@ComponentScan 方式

@ComponentScan(basePackages = "com.dive.in.spring.boot")
public class SpringConfiguration {
...
}
Spring @Enable 模块装配

Spring Framework 3.1 开始支持”@Enable 模块驱动“。所谓“模块”是指具备相同领域的功能组件集合, 组合所形成一个独立的单元。比如 Web MVC 模块(@EnableWebMvc)、AspectJ代理模块(@EnableAspectJAutoProxy) 等。

自定义 @Enable 模块

HelloWorldConfiguration:

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

}

HelloWorldImportSelector:

import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
import com.example.demo.configuration.HelloWorldConfiguration;
public class HelloWorldImportSelector implements ImportSelector{

	@Override
	public String[] selectImports(AnnotationMetadata arg0) {
		// TODO Auto-generated method stub
		return new String[]{HelloWorldConfiguration.class.getName()};
	}

}

EnableHelloWorld:

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

}

EnableHelloWorldBootstrap:

@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();
    }

}

运行结果:
helloWorld Bean : Hello,World 2020

Spring 条件装配

1、基于配置方式实现 - @Profile

定义一个服务接口CalculateService :

package com.example.demo.service;

public interface CalculateService {
	/**
     * 从多个整数 sum 求和
     * @param values 多个整数
     * @return sum 累加值
     */
    Integer sum(Integer... values);
}

Java7CalculateService:

package com.example.demo.service;

import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
@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;
    }

}

Java8CalculateService:

package com.example.demo.service;

import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
import java.util.stream.Stream;
@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;
    }
}

启动类

@SpringBootApplication(scanBasePackages = "com.example.demo.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();
    }
}

可以根据在context中设置不同的profile装配不同的Bean。

2、基于接口编程方式实现 - @Conditional

系统属性条件判断OnSystemPropertyCondition:

/**
 * 系统属性条件判断
 */
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);
    }
}

条件注解ConditionalOnSystemProperty:

/**
 * Java 系统属性 条件判断
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
@Conditional(OnSystemPropertyCondition.class)
public @interface ConditionalOnSystemProperty {

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

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

系统属性条件引导类ConditionalOnSystemPropertyBootstrap:

/**
 * 系统属性条件引导类
 */
public class ConditionalOnSystemPropertyBootstrap {

    @Bean
    @ConditionalOnSystemProperty(name = "user.name", value = "rose")
    public String helloWorld() {
        return "Hello,World 2020";
    }

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

运行之后propertyValue不等于javaPropertyValue,所以会拿不到helloWorld这个Bean.
在这里插入图片描述
在这里插入图片描述

Spring Boot 自动装配

springboot的自动装配基于约定大于配置的原则,其中使用了底层装配技术:
1、Spring 模式注解装配
2、Spring @Enable 模块装配
3、Spring 条件装配装配
4、Spring 工厂加载机制

  • 实现类: SpringFactoriesLoader
  • 配置资源: META-INF/spring.factories

实现方法:

  1. 激活自动装配 - @EnableAutoConfiguration
  2. 实现自动装配 - XXXAutoConfiguration
  3. 配置自动装配实现 - META-INF/spring.factories

自定义自动装配:
在resources目录下新建 META-INF/spring.factories,并指定spring工厂机制要自动装配的类:
在这里插入图片描述
HelloWorldAutoConfiguration:

import com.example.demo.annotation.EnableHelloWorld;
import com.imooc.diveinspringboot.condition.ConditionalOnSystemProperty;
import org.springframework.context.annotation.Configuration;

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

EnableAutoConfigurationBootstrap启动类:

/**
 * {@link 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();

    }
}

整体流程:
1、HelloWorldAutoConfiguration
2、条件判断: user.name == “Administrator”
3、模式注解: @Configuration
4、@Enable 模块: @EnableHelloWorld -> HelloWorldImportSelector -> HelloWorldConfiguration - > helloWorld
最后通过了@Enable 模块装配了helloWorld这个Bean。

关于spring工厂机制参见SpringApplication初始化源码分析

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值