SpringBoot2.0源码二

第二章:走向自动装配

第一节:Spring Framework 手动装配

第二节:Spring Framework 手动装配自定义模式注解

spirng 模式注解装配
定义
  • 一种用于声明在应用(Spring 或Spring boot中)中扮演“组件”角色的注解
举例
  • @Component @Service @Controller @Configuration
1.@Service @Controller @Repository这三个注解从源码上看其实都是@Component 实现的,所以本质上这三个没有什么区别。

通常地,@Service @Controller @Repository是为了给不同的类打上不同的标志来区别开各个类的作用是什么,

@Service表明是一个服务

@Controller表明是一个控制器

@Repository表明是一个仓储,说明是数据库访问模型

如果该类没有明确定义是服务、控制器、仓储,可以用@Component标明
@Component 作为spring容器托管的通用模式组件,任何被它附加的组件,都会被容器作为组件扫描对象
2.@Autowired

首先spring是一个约定大于配置的框架,变量的名字对于注入的对象是有影响的 
@Autowired
private Book book;

其次需要注意的是接口不可以用@Component,也没有意义,提到的bean都是具体的class类

① @Autowired优先按bytype查找并实例化,没有找到任何一个bean,会报错
② 按bytype找到多个,会按byname找,如果仍没找到,会报错(byname查找方式可以用@Qualifier,@Qualifier声明的byname变量优先级最高)
③ 在成员变量注入和setter注入的时候必须加上@Autowired,在构造器注入的时候可以不加,直接按原来的方式写构造器把实例当参数传进去即可,spring官方推荐构造函数注入或setter注入,因为两种是对public做注入

3.@Configuration

是在spring3.0里加入的新特性,通常在写框架的时候被用到,是配置类注解,用来解决变化的问题,很重要
@Configuration主要是用来取代xml配置方式的

装配方式
  • <context:component-scan>

    <beans>
    激活注解驱动特性
    <context:annotation-config />
    寻找被@Component 或者派生注解标记的类class,将他们注册为 spring bean
    <context:component-scan base-package="com.lc.springboot" />
    </beans>
    
  • @ComponentScan

    @ComponentScan(basePackages = "com.lc.springboot")
    public class SpringConfiguration{
    	...
    }
    
    

第三节:@Enable 模块装配两种方式

定义
  • 具备相同领域的功能组件集合,组合所形成一个独立的单元
举例
  • @EnableWebMvc -web MVC模块

  • @EnableAutoConfiguration - 自动装配模块

  • @EnableEurekaServer - Eureka 服务器模块

实现
注解驱动方式
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc{   
}

@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport{
    
}
接口编程方式
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(CachingConfigurationSelector.class)
public @interface EnableCaching{   
}

public class CachingConfigurationSelector extends AdviceModeImportSelector<EnableCaching>{
    switch(adviceMode){
        case PROXY:
            return new String[]{AutoProxyRegistrar.class.getName(),ProxyCachingConfiguration.class.getName()};
        case ASPECTJ:
            return new String[]{AnnotationConfigUtils.CACHE_ASPECT_CONFIGURATION_CLASS_NAME};
        default:
            return null;    
    }
}

public class AdviceModeImportSelector implements ImportSelector{
    
}

第四节:Spring条件装配

定义
  • Bean装配的前置判断(条件装配也属于spring framework 手动装配一种)
举例
  • @Profile - 配置化条件装配
  • @Contitional - 编程条件装配

实现

  • 基于配置方式实现 - @Profile

    • 计算服务,多整数求和Sum
    • @Profile("java7") for循环
    • @Profile("java8") lambda表达式
    public interface Calculate {
        //变量参数
        Integer sum(Integer... values);
    }
    
    @Profile("java7")
    @Service
    public class Java7Calculate implements Calculate {
        public Integer sum(Integer... values) {
            System.out.println("java7");
            int sum = 0;
            for (Integer value : values) {
                sum += value;
            }
            return sum;
        }
    
        public static void main(String[] args) {
            Java7Calculate java7Calculate = new Java7Calculate();
            System.out.println(java7Calculate.sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
        }
    }
    
    @Profile("java8")
    @Service
    public class Java8Calculate implements Calculate{
        public Integer sum(Integer... values) {
            System.out.println("java8");
            int sum = Stream.of(values).reduce(0, Integer::sum);
            return sum;
        }
        public static void main(String[] args) {
            Java8Calculate java8Calculate = new Java8Calculate();
            System.out.println(java8Calculate.sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
        }
    }
    
    /*
    *  启动类
    */
    //两种包扫描方式都可以实现
    @SpringBootApplication(scanBasePackages = "com.lc.service")
    //@ComponentScan(basePackages = "com.lc.service")
    public class CalculateBootstrap {
        public static void main(String[] args) {
            ConfigurableApplicationContext context = new SpringApplicationBuilder(CalculateBootstrap.class)
                    .web(WebApplicationType.NONE)
                    .profiles("java8")//指定当前容器使用哪个profile
                    .run(args);
            //判断Bean是否存在
            Calculate calculate = context.getBean(Calculate.class);
            System.out.println(calculate.sum(1,2,3,4,5,6,7,8,9,10));
            //关闭上下文
            context.close();
        }
    }
    
  • 基于编程方式实现 - @ConditionalOnProperty

    /**
    * 自定义注解
    */
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE, ElementType.METHOD})
    @Documented
    @Conditional({OnMyPropertyCondition.class})
    public @interface MyConditionalOnProperty {
        String value();
    
        String name();
    
    }
    
    /*
    * 实现注解,同时编程进行各种判断
    */
    public class OnMyPropertyCondition implements Condition {
        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            Map<String, Object> attributes = metadata.getAnnotationAttributes(MyConditionalOnProperty.class.getName());
            String name = (String) attributes.get("name");
            String value = (String) attributes.get("value");
            String javaValue = System.getProperty(name);//获取系统用户信息,也可以从配置文件中读取
            System.out.println(javaValue);
            return value.equals(javaValue); //输入值和系统用户名相同,则返回
        }
    }
    
    /*
    * 条件装配,启动类,
    */
    public class OnMyPropertyConditionBootstrap {
        //创建个Bean,使用条件装配,如果value相同,才会注入IOC容器
        @Bean
        @MyConditionalOnProperty(name = "user.name",value = "2466")
        public String helloWorld(){
            return "hello,world";
        }
        
        public static void main(String[] args) {
            ConfigurableApplicationContext context = new SpringApplicationBuilder(OnMyPropertyConditionBootstrap.class)
                    .web(WebApplicationType.NONE)//web应用类型,Servlet、Reactive、None,第三章推断web类型详解源码
                    .run(args);
    
            String bean = context.getBean("helloWorld",String.class);//使用context上下文,获取配置对应的Bean,在value相同时,可以获取,在value不同时,则会报错,容器中没有该Bean
            System.out.println(bean);
            //关闭上下文
            context.close();
        }
    }
    

第五节:Spring Boot 自动装配

定义
  • 基于规约大于配置,实现spirng组件自动装配的目的
底层装配方式
  • Spirng模式注解
  • Spirng @Enable模块
  • Spirng条件装配
  • Spirng工厂加载机制
    • 实现类 SpringFactoriesLoader
    • 配置资源 META-INF/spring.factories
实现步骤
  1. 激活自动装配 - @EnableAutoConfiguration

  2. 实现自动装配 - XXXAutoConfiguration

  3. 配置自动装配实现 - META/INFO/spring.factories

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值