`
yyddbull
  • 浏览: 1014 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

spring boot学习二:Spring Boot自动装配分析与实战

 
阅读更多

上文中简单介绍了intellij环境下Spring Boot的入门示例,从而见识到了Spring Boot的强大,几乎不用做什么配置,就能运行一个Spring mvc的示例,要知道,Spring之前都是以繁琐的配置而为人诟病,Spring Boot的自动装配,可以根据pom的依赖配置,自动生成相应的bean,并加载到Spring Context中,简化了Spring项目搭建的复杂度,本节主要介绍Spring Boot自动装配的流程,并最终提供了自定义自动装配的示例代码。

一、在这之前,首先要介绍一下Spring4中的条件注解:@Conditional,Spring会根据独立的注解条件来创建类,Spring条件注解示例如下:

1、首先创建ch2_1工程和condmodule模块,项目结构如下所示:

 

 

2、创建对应的条件类,其中,MatchCondition表示匹配的条件类,NotMatchCondition表示不匹配的条件类,MatchCondition代码如下:

 

package com.flagship.condition;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class MatchCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, 
                    AnnotatedTypeMetadata annotatedTypeMetadata) {
        return true;
    }
}

 NotMatchCondition代码如下:

package com.flagship.condition;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class NotMatchCondition implements Condition {

    @Override
    public boolean matches(ConditionContext conditionContext,AnnotatedTypeMetadata annotatedTypeMetadata) {
        return false;
    }
}

 3、创建2个类,MatchBean和NotMatchBean,实现同一接口BeanInterface,后续Java配置类中,会根据不同的注解条件,生成相应的类对象,我们用类中的description()来打印信息,以此识别不同的对象信息,BeanInterface代码如下:

package com.flagship.bean;

public interface BeanInterface {
    public void description();
}

 MatchBean代码如下:

package com.flagship.bean;

public class MatchBean implements BeanInterface {
    @Override
    public void description() {
        System.out.println("this is MatchBean's method!");
    }
}

 NotMatchBean代码如下:

package com.flagship.bean;

public class NotMatchBean implements BeanInterface {
    @Override
    public void description() {
        System.out.println("this is NotMatchBean's method!");
    }
}

 4、Java配置类代码如下,此处采用@Configuration注解声明配置类,类似以前的xml配置文件,@Bean注解声明当前方法的返回值是一个Bean对象:

package com.flagship.config;

import com.flagship.bean.BeanInterface;
import com.flagship.bean.MatchBean;
import com.flagship.bean.NotMatchBean;
import com.flagship.condition.MatchCondition;
import com.flagship.condition.NotMatchCondition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ConditionalCfg {
    @Bean
    @Conditional(MatchCondition.class)
    public BeanInterface getMatchBeanObject(){
        return new MatchBean();
    }

    @Bean
    @Conditional(NotMatchCondition.class)
    public BeanInterface getNotMatchBeanObject(){
        return new NotMatchBean();
    }
}

 5、运行类代码如下,根据条件类的matches方法的返回值,最终会调用MatchBean类的description方法:

package com.flagship.condmodule;

import com.flagship.bean.BeanInterface;
import com.flagship.config.ConditionalCfg;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Application {
     public static void main(String[] args) {
         AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ConditionalCfg.class);
	 BeanInterface bean = ctx.getBean(BeanInterface.class);
	 bean.description();
     }
}

 最终控制台打印信息为:this is MatchBean's method!

 二、跟踪官网文档说明,Spring Boot条件注解大致分了如下几类如下:

Class conditions:@ConditionalOnClass和@ConditionalOnMissingClass,表示类是否在类路径下的条件注解

Bean conditions:@ConditionalOnBean和@ConditionalOnMissingBean,表示Bean是否被定义的条件注解

Property conditions:@ConditionalOnProperty,使用prefix和name属性用来表示是否有值,默认的话,只要该属性存在值,且不为false,即可匹配

Resource conditions:@ConditionalOnResource表示是否存在指定的resouce的条件注解

Web application conditions:@ConditionalOnWebApplication和@ConditionalOnNotWebApplication,当项目是web项目,或者不是web项目的条件注解

SpEL expression conditions:@ConditionalOnExpression,根据SPEL表达式执行结果作为条件

 

自动装配代码跟踪:

我们从上一章节的@SpringBootApplication开始,由于@SpringBootApplication是由@EnableAutoConfiguration组成的,我们观察@EnableAutoConfiguration注解的源码如下:

 

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.boot.autoconfigure;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({EnableAutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

 EnableAutoConfiguration使用@Import注解将EnableAutoConfigurationImportSelector导入并声明为一个Bean,跟踪EnableAutoConfigurationImportSelector的源码,发现其继承AutoConfigurationImportSelector类,而其中有这么一个方法getCandidateConfigurations

 

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,AnnotationAttributes attributes) {
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
       //...省略其余代码
    }
继续跟踪SpringFactoriesLoader.loadFactoryNames方法,其代码如下:

 

 

public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
     String factoryClassName = factoryClass.getName();
     try {
        Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") :ClassLoader.getSystemResources("META-INF/spring.factories");
        ArrayList result = new ArrayList();
        while(urls.hasMoreElements()) {
            URL url = (URL)urls.nextElement();
            Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
            String factoryClassNames = properties.getProperty(factoryClassName);
            result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
         }

 发现最终读取的就是META-INF/spring.factories文件,点击intellij中【External Libraries】中spring-boot-autoconfigure-1.5.7.RELEASE.jar,打开META-INF/spring.factories文件,查看里面内容

 

 此文件中提供了Spring Boot的默认自动配置,随便点开启动一个配置类:org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration,代码如下:

@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurerAdapter.class})
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
@AutoConfigureOrder(-2147483638)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, 
                                             ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration {
    public static final String DEFAULT_PREFIX = "";
    public static final String DEFAULT_SUFFIX = "";

    public WebMvcAutoConfiguration() {
    }

 可以看到,这里使用了上述介绍的条件注解来实现自动装配功能

 三、本节我们根据上面介绍的原理,开始自定义实现一个自动装配,实现根据项目properties文件的配置打印当前环境信息日志的功能

1、首先,新建一个maven-archetype-quickstart模版的maven模块,并在src\main目录下建好resources\META-INF\spring.factories文件,架构如下图所示:



 

2、pom文件中加入autofigure的依赖,代码如下:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>ch2_1</artifactId>
        <groupId>com.flagship</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>autocfg</artifactId>
    <packaging>jar</packaging>

    <name>envLog</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
            <version>1.5.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

 3、新建Java配置类:LogServiceProp,会读取项目配置文件中"env.log"开头的属性值

package com.flagship.autocfg;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
 * Java配置类
 */
@ConfigurationProperties(prefix="env.log")
public class LogServiceProp {

    private String runPattern = "run";
    
    public String getRunPattern() {
        return runPattern;
    }
    public void setRunPattern(String runPattern) {
        this.runPattern = runPattern;
    }
}

 4、新建业务实体类,用于打印日志,其中,printEnv方法用来在控制台打印当前的运行模式日志,代码如下:

package com.flagship.autocfg;

public class LogService {

    private String runPatternLog;

    public String printEnv(){
        return "current env is in:" + runPatternLog + " pattern!";
    }

    public String getRunPatternLog() {
        return runPatternLog;
    }
    public void setRunPatternLog(String runPatternLog) {
        this.runPatternLog = runPatternLog;
    }
}

 5、建立自动配置类:LogConfiguration,其中@Configuration注解标识的类,表明作为一个配置类,类似于之前的xml配置文件,@EnableConfigurationProperties告诉Spring Boot 任何被@ConfigurationProperties注解的beans将自动被属性配置,@ConditionalOnClass用来条件注解,当LogService.class存在类路径的时候起效,@ConditionalOnMissingBean当容器中没有这个Bean对象的时候,自动配置这个Bean对象,代码如下:

package com.flagship.autocfg;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableConfigurationProperties(LogServiceProp.class)
@ConditionalOnClass(LogService.class)
public class LogConfiguration {
    @Autowired
    private LogServiceProp logServiceProp;

    @Bean
    @ConditionalOnMissingBean(LogService.class)
    public LogService getLogService(){
        LogService service = new LogService();
        service.setRunPatternLog(logServiceProp.getRunPattern());
        return service;
    }
}

 6、spring.factories文件中加入自动配置类,代码如下:

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.flagship.autocfg.LogConfiguration

 7、回到第一节的condmodule模块,pom加入对envLog模块的依赖,代码如下:

<dependency>
	<groupId>com.flagship</groupId>
	<artifactId>autocfg</artifactId>
	<version>0.0.1-SNAPSHOT</version>
</dependency>

 8、src\main\resources\application.properties中加入如下配置:

      env.log.runPattern=debug

9、新建mvc入口测试类,代码如下:

package com.flagship.condmodule;

import com.flagship.autocfg.LogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@SpringBootApplication
public class AutoCfgApplication {

	@Autowired
	LogService service;

	@RequestMapping("/")
	public String getEnvLog(){
		return service.printEnv();
	}

	public static void main(String[] args) {
		SpringApplication.run(AutoCfgApplication.class,args);
	}
}

 10、运行后结果如下,此时神奇的效果出现了,工程中并没有配置LogService这个对象,但是却可以通过@Autowired注解进行注入,这就是Spring Boot自动配置的威力:

current env is in:debug pattern!
  • 大小: 15.6 KB
  • 大小: 157.2 KB
  • 大小: 8.3 KB
分享到:
评论

相关推荐

    Spring Boot技术知识点:Bean装配1

    6. **配置类与属性源**:Spring Boot允许从application.properties或application.yml文件中读取配置属性,并通过@ConfigurationProperties注解将这些属性映射到Java对象上,方便在Bean装配时使用。 7. **条件注解...

    Spring Boot 面试必备手册

    Spring Boot 的自动配置原理是通过 `@EnableAutoConfiguration` 注解启动,然后从 `META-INF/spring.factories` 文件中导入自动配置类。这些配置类会根据类路径中是否存在某些类、环境变量、命令行参数等条件,来...

    spring boot

    ### Spring Boot核心知识点详解 #### 一、Spring Boot简介 Spring Boot是由Pivotal团队提供的全新框架,其设计...希望通过对Spring Boot的学习,大家能够掌握其核心概念与技术要点,从而在实际工作中更好地应用它。

    Spring Boot 系列实战合集.zip

    在"Spring Boot 系列实战合集.zip"这个压缩包中,可能包含了多个关于 Spring Boot 实战的项目或者教程。"新建文件夹"可能是一个包含不同主题或阶段学习资料的组织结构,而"Spring-Boot-In-Action-master"则很可能是...

    第三节-springboot源码解析-王炸篇.pdf

    通过源码分析,开发者可以更好地理解Spring Boot的自动装配、启动流程以及如何自定义启动器。Spring Boot的自动装配原理涉及到Spring Boot的核心特性,它简化了基于Spring的应用开发,通过自动配置减少了大量的配置...

    spring boot基础笔记

    4. Spring Boot自动装配原理:Spring Boot自动装配是指Spring Boot通过EnableAutoConfiguration注解自动配置Spring应用中各个组件。它依据项目中添加的jar依赖来猜测需要配置的内容,并通过spring.factories文件中...

    spring-boot

    Spring Boot是一个开源的Java基础框架,它是为了解决使用Spring框架时配置过多、装配复杂的问题而设计的。Spring Boot致力于简化Spring应用的初始搭建以及开发过程,它为Java开发者提供了一种快速、简便的方式来创建...

    Spring 实战 (中文第4版) PDF + source code

    《Spring 实战 (中文第4版)》是深入学习Spring框架和相关技术的权威指南,由Manning出版社出版。本书全面覆盖了Spring框架的核心概念、关键特性以及在实际开发中的应用,适合Java开发者和对Spring感兴趣的人员阅读。...

    深度剖析Spring Boot自动装配机制实现原理(csdn)————程序.pdf

    总的来说,Spring Boot的自动装配机制基于一系列注解和接口,如`@EnableAutoConfiguration`、`AutoConfigurationImportSelector`、`@Conditional`等,实现了根据项目依赖和配置动态地加载和配置bean,极大地提升了...

    spring-boot自动装配原理.md

    spring-boot自动装配原理.md

    spring Boot 2 精髓

    本书系统介绍了Spring Boot 2的主要技术,侧重于两个方面,一方面是极速开发一个Web应用系统,详细介绍Spring Boot框架、Spring MVC、视图技术、数据库访问技术,并且介绍多环境部署、自动装配、单元测试等高级特性...

    spring实战全部源代码.zip

    《Spring实战》第五版的源代码压缩包"spring实战全部源代码.zip"包含了全面的示例项目,旨在帮助读者深入理解和应用Spring框架。这个压缩包中的"spring-in-action-5-samples-master"目录揭示了书中的各个实战案例,...

    关于spring boot中几种注入方法的一些个人看法

    下面我们将对 Spring Boot 中的几种注入方法进行详细的介绍和分析。 1. @Autowired @Autowired 是 Spring 中最常用的注入方法之一,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。@Autowired ...

    Spring boot +jdbctemplate

    综上所述,Spring Boot与JdbcTemplate的结合,为开发高效、简洁的Java Web应用提供了强大支持。通过自动配置、内嵌Web服务器、JdbcTemplate的简单操作、声明式事务管理、拦截器以及数据源的配置,开发者可以更专注于...

    [课堂课件讲解]Java微服务实践-Spring Boot 自定义启动器.pptx

    其中,Spring Boot自定义启动器是Spring Boot框架中最核心的组件,能够自动装配模块、启动器模块等多种组件。 Spring Boot Starter又称作为Spring Boot启动器,是Spring Boot框架中最核心的组件。其中可能包含自动...

    Spring学习笔记&源码

    7. **Spring Boot**:简述Spring Boot的自动化配置和起步依赖,以及如何快速构建微服务应用。 8. **Spring Cloud**:如果包含高级内容,可能还会涉及到Spring Cloud的相关组件,如Eureka服务注册与发现、Ribbon...

    mybatis学习总结:mybatis和spring, spring boot的集成

    这篇“mybatis学习总结”着重探讨了MyBatis如何与Spring和Spring Boot进行集成,这对于构建高效、可维护的企业级应用至关重要。 首先,MyBatis与Spring的集成主要通过Spring的IoC(Inversion of Control)容器来...

    Spring Boot中的@ComponentScan注解:深入理解组件扫描机制

    @ComponentScan注解是Spring Boot中实现组件自动装配的核心机制。通过合理配置组件扫描,可以提高应用程序的模块化程度、可维护性和启动性能。 本文通过深入分析@ComponentScan注解的工作原理和使用场景,为读者...

    SPRING技术内幕:深入解析SPRING架构与设计原理_spring_

    《SPRING技术内幕:深入解析SPRING架构与设计原理》这本书深入探讨了Spring框架的核心机制、设计理念以及在实际开发中的应用。Spring作为Java领域最流行的轻量级框架,它的广泛应用和强大功能使得深入理解其工作原理...

    Spring Boot浅谈(是什么/能干什么/优点和不足).docx

    - **编码变简单**:Spring Boot通过提供默认配置和自动装配,让开发者更专注于业务逻辑而不是基础设施的配置。 - **配置变简单**:通过使用`@ConfigurationProperties`和YAML/properties文件,Spring Boot允许将...

Global site tag (gtag.js) - Google Analytics